diff --git a/README.md b/README.md index 946fff171e1c8e9be3937091d855c809b0c029cb..54e5b9ef2b66021b2e3194b96dbfd8f066a2c639 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,19 @@ A collection of commonly used widgets. + + + Tooltip + + + Tooltip + + + + + + + Flow Layout @@ -147,7 +160,7 @@ A collection of commonly used widgets. - + diff --git a/screenshot/ToolTip.gif b/screenshot/ToolTip.gif new file mode 100644 index 0000000000000000000000000000000000000000..c35fb0b5d2502b768ecbb4073670ba34ae352255 Binary files /dev/null and b/screenshot/ToolTip.gif differ diff --git a/widgets/tool_tip/demo.py b/widgets/tool_tip/demo.py new file mode 100644 index 0000000000000000000000000000000000000000..7f80825f42bf5c16295f3072cf71bfd1ed343dad --- /dev/null +++ b/widgets/tool_tip/demo.py @@ -0,0 +1,69 @@ +# coding:utf-8 +import sys +from PyQt5.QtCore import QEvent, QPoint +from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout + +from tool_tip import ToolTip + + +class Demo(QWidget): + + def __init__(self): + super().__init__() + self.hBox = QHBoxLayout(self) + self.button1 = QPushButton('キラキラ', self) + self.button2 = QPushButton('食べた愛', self) + self._toolTip = ToolTip(parent=self) + # self._tooltip.setDarkTheme(True) + + self.button1.setToolTip('aiko - キラキラ ✨') + self.button2.setToolTip('aiko - 食べた愛 🥰') + self.button1.setToolTipDuration(1000) + self.button2.setToolTipDuration(5000) + + self.button1.installEventFilter(self) + self.button2.installEventFilter(self) + + self.hBox.setContentsMargins(30, 30, 30, 30) + self.hBox.setSpacing(20) + self.hBox.addWidget(self.button1) + self.hBox.addWidget(self.button2) + + self.resize(600, 300) + self._toolTip.hide() + + with open('resource/demo.qss', encoding='utf-8') as f: + self.setStyleSheet(f.read()) + + def eventFilter(self, obj, e: QEvent): + if obj is self: + return super().eventFilter(obj, e) + + tip = self._toolTip + if e.type() == QEvent.Enter: + tip.setText(obj.toolTip()) + tip.setDuration(obj.toolTipDuration()) + + pos = obj.mapTo(self, QPoint(0, 0)) + x = pos.x() + obj.width()//2 - tip.width()//2 + y = pos.y() - 5 - tip.height() + + # adjust postion to prevent tooltips from appearing outside the window + x = min(max(5, x), self.width() - tip.width() - 5) + y = min(max(5, y), self.height() - tip.height() - 5) + + tip.move(x, y) + tip.show() + elif e.type() == QEvent.Leave: + tip.hide() + elif e.type() == QEvent.ToolTip: + return True + + return super().eventFilter(obj, e) + + +if __name__ == '__main__': + app = QApplication(sys.argv) + w = Demo() + w.show() + app.exec_() diff --git a/widgets/tool_tip/resource/demo.qss b/widgets/tool_tip/resource/demo.qss new file mode 100644 index 0000000000000000000000000000000000000000..b21a8959254bac942d1ff652f55e05eca91cc3e9 --- /dev/null +++ b/widgets/tool_tip/resource/demo.qss @@ -0,0 +1,25 @@ +QWidget{ + background-color: white; +} + +QPushButton { + background-color: rgb(204, 204, 204); + padding: 10px 64px 10px 64px; + font: 19px 'Microsoft YaHei'; + border: transparent; + border-radius: 4px; + /* height: 40px; */ +} + +QPushButton:pressed:hover { + background-color: rgb(153, 153, 153); +} + +QPushButton:hover { + background-color: rgb(230, 230, 230); +} + +QPushButton:disabled { + background-color: rgb(204, 204, 204); + color: rgb(122, 122, 122); +} \ No newline at end of file diff --git a/widgets/tool_tip/resource/tooltip.qss b/widgets/tool_tip/resource/tooltip.qss new file mode 100644 index 0000000000000000000000000000000000000000..c86567b90f47b8bfe9ec0584d6e8649c68eb135f --- /dev/null +++ b/widgets/tool_tip/resource/tooltip.qss @@ -0,0 +1,24 @@ +ToolTip[dark="false"] { + border: 1px solid rgba(0, 0, 0, 0.06); + border-radius: 5px; + background-color: rgb(243, 243, 243); +} + +ToolTip[dark="true"] { + border: 1px solid rgb(28, 28, 28); + border-radius: 5px; + background-color: rgb(43, 43, 43); +} + +QLabel { + background-color: transparent; + font: 15px 'Segoe UI', 'Microsoft YaHei'; +} + +QLabel[dark="false"] { + color: black; +} + +QLabel[dark="true"] { + color: white; +} \ No newline at end of file diff --git a/widgets/tool_tip/tool_tip.py b/widgets/tool_tip/tool_tip.py new file mode 100644 index 0000000000000000000000000000000000000000..20aa539c30ffa4d38a6503ec4d53056a866d8536 --- /dev/null +++ b/widgets/tool_tip/tool_tip.py @@ -0,0 +1,79 @@ +# coding:utf-8 +from PyQt5.QtCore import QFile, QPropertyAnimation, QTimer, Qt +from PyQt5.QtGui import QColor +from PyQt5.QtWidgets import (QApplication, QFrame, QGraphicsDropShadowEffect, + QHBoxLayout, QLabel) + + +class ToolTip(QFrame): + + def __init__(self, text='', parent=None): + super().__init__(parent=parent) + self.__text = text + self.__duration = 1000 + self.timer = QTimer(self) + self.hBox = QHBoxLayout(self) + self.label = QLabel(text, self) + self.ani = QPropertyAnimation(self, b'windowOpacity', self) + + # set layout + self.hBox.addWidget(self.label) + self.hBox.setContentsMargins(10, 7, 10, 7) + + # add shadow + self.shadowEffect = QGraphicsDropShadowEffect(self) + self.shadowEffect.setBlurRadius(32) + self.shadowEffect.setColor(QColor(0, 0, 0, 60)) + self.shadowEffect.setOffset(0, 5) + self.setGraphicsEffect(self.shadowEffect) + + self.timer.setSingleShot(True) + self.timer.timeout.connect(self.hide) + + # set style + self.setAttribute(Qt.WA_StyledBackground) + self.setDarkTheme(False) + self.__setQss() + + def text(self): + return self.__text + + def setText(self, text: str): + """ set text on tooltip """ + self.__text = text + self.label.setText(text) + self.label.adjustSize() + self.adjustSize() + + def duration(self): + return self.__duration + + def setDuration(self, duration: int): + """ set tooltip duration in milliseconds """ + self.__duration = abs(duration) + + def __setQss(self): + """ set style sheet """ + f = QFile("resource/tooltip.qss") + f.open(QFile.ReadOnly) + self.setStyleSheet(str(f.readAll(), encoding='utf-8')) + f.close() + + self.label.adjustSize() + self.adjustSize() + + def setDarkTheme(self, dark=False): + """ set dark theme """ + dark = 'true' if dark else 'false' + self.setProperty('dark', dark) + self.label.setProperty('dark', dark) + self.setStyle(QApplication.style()) + + def showEvent(self, e): + self.timer.stop() + self.timer.start(self.__duration) + super().showEvent(e) + + def hideEvent(self, e): + self.timer.stop() + super().hideEvent(e) \ No newline at end of file