提交 cdd03cea 编写于 作者: 之一Yo's avatar 之一Yo

添加工具提示位置枚举 `ToolTipPosition` 和导航菜单项工具提示功能,#159

上级 710e27a1
...@@ -66,7 +66,7 @@ class Window(FramelessWindow): ...@@ -66,7 +66,7 @@ class Window(FramelessWindow):
self.setTitleBar(StandardTitleBar(self)) self.setTitleBar(StandardTitleBar(self))
# use dark theme mode # use dark theme mode
setTheme(Theme.DARK) # setTheme(Theme.DARK)
# change the theme color # change the theme color
# setThemeColor('#0078d4') # setThemeColor('#0078d4')
...@@ -82,12 +82,6 @@ class Window(FramelessWindow): ...@@ -82,12 +82,6 @@ class Window(FramelessWindow):
self.folderInterface = Widget('Folder Interface', self) self.folderInterface = Widget('Folder Interface', self)
self.settingInterface = Widget('Setting Interface', self) self.settingInterface = Widget('Setting Interface', self)
self.stackWidget.addWidget(self.searchInterface)
self.stackWidget.addWidget(self.musicInterface)
self.stackWidget.addWidget(self.videoInterface)
self.stackWidget.addWidget(self.folderInterface)
self.stackWidget.addWidget(self.settingInterface)
# initialize layout # initialize layout
self.initLayout() self.initLayout()
...@@ -104,35 +98,14 @@ class Window(FramelessWindow): ...@@ -104,35 +98,14 @@ class Window(FramelessWindow):
self.hBoxLayout.setStretchFactor(self.stackWidget, 1) self.hBoxLayout.setStretchFactor(self.stackWidget, 1)
def initNavigation(self): def initNavigation(self):
self.navigationInterface.addItem( self.addSubInterface(self.searchInterface, FIF.SEARCH, 'Search')
routeKey=self.searchInterface.objectName(), self.addSubInterface(self.musicInterface, FIF.MUSIC, 'Music library')
icon=FIF.SEARCH, self.addSubInterface(self.videoInterface, FIF.VIDEO, 'Video library')
text='Search',
onClick=lambda: self.switchTo(self.searchInterface)
)
self.navigationInterface.addItem(
routeKey=self.musicInterface.objectName(),
icon=FIF.MUSIC,
text='Music library',
onClick=lambda: self.switchTo(self.musicInterface)
)
self.navigationInterface.addItem(
routeKey=self.videoInterface.objectName(),
icon=FIF.VIDEO,
text='Video library',
onClick=lambda: self.switchTo(self.videoInterface)
)
self.navigationInterface.addSeparator() self.navigationInterface.addSeparator()
# add navigation items to scroll area # add navigation items to scroll area
self.navigationInterface.addItem( self.addSubInterface(self.folderInterface, FIF.FOLDER, 'Folder library', NavigationItemPosition.SCROLL)
routeKey=self.folderInterface.objectName(),
icon=FIF.FOLDER,
text='Folder library',
onClick=lambda: self.switchTo(self.folderInterface),
position=NavigationItemPosition.SCROLL
)
# for i in range(1, 21): # for i in range(1, 21):
# self.navigationInterface.addItem( # self.navigationInterface.addItem(
# f'folder{i}', # f'folder{i}',
...@@ -150,13 +123,7 @@ class Window(FramelessWindow): ...@@ -150,13 +123,7 @@ class Window(FramelessWindow):
position=NavigationItemPosition.BOTTOM position=NavigationItemPosition.BOTTOM
) )
self.navigationInterface.addItem( self.addSubInterface(self.settingInterface, FIF.SETTING, 'Settings', NavigationItemPosition.BOTTOM)
routeKey=self.settingInterface.objectName(),
icon=FIF.SETTING,
text='Settings',
onClick=lambda: self.switchTo(self.settingInterface),
position=NavigationItemPosition.BOTTOM
)
#!IMPORTANT: don't forget to set the default route key if you enable the return button #!IMPORTANT: don't forget to set the default route key if you enable the return button
# self.navigationInterface.setDefaultRouteKey(self.musicInterface.objectName()) # self.navigationInterface.setDefaultRouteKey(self.musicInterface.objectName())
...@@ -179,6 +146,18 @@ class Window(FramelessWindow): ...@@ -179,6 +146,18 @@ class Window(FramelessWindow):
self.setQss() self.setQss()
def addSubInterface(self, interface, icon, text: str, position=NavigationItemPosition.TOP):
""" add sub interface """
self.stackWidget.addWidget(interface)
self.navigationInterface.addItem(
routeKey=interface.objectName(),
icon=icon,
text=text,
onClick=lambda: self.switchTo(interface),
position=position,
tooltip=text
)
def setQss(self): def setQss(self):
color = 'dark' if isDarkTheme() else 'light' color = 'dark' if isDarkTheme() else 'light'
with open(f'resource/{color}/demo.qss', encoding='utf-8') as f: with open(f'resource/{color}/demo.qss', encoding='utf-8') as f:
......
...@@ -109,12 +109,6 @@ class Window(FramelessWindow): ...@@ -109,12 +109,6 @@ class Window(FramelessWindow):
self.folderInterface = Widget('Folder Interface', self) self.folderInterface = Widget('Folder Interface', self)
self.settingInterface = Widget('Setting Interface', self) self.settingInterface = Widget('Setting Interface', self)
self.stackWidget.addWidget(self.searchInterface)
self.stackWidget.addWidget(self.musicInterface)
self.stackWidget.addWidget(self.videoInterface)
self.stackWidget.addWidget(self.folderInterface)
self.stackWidget.addWidget(self.settingInterface)
# initialize layout # initialize layout
self.initLayout() self.initLayout()
...@@ -134,35 +128,14 @@ class Window(FramelessWindow): ...@@ -134,35 +128,14 @@ class Window(FramelessWindow):
self.navigationInterface.displayModeChanged.connect(self.titleBar.raise_) self.navigationInterface.displayModeChanged.connect(self.titleBar.raise_)
def initNavigation(self): def initNavigation(self):
self.navigationInterface.addItem( self.addSubInterface(self.searchInterface, FIF.SEARCH, 'Search')
routeKey=self.searchInterface.objectName(), self.addSubInterface(self.musicInterface, FIF.MUSIC, 'Music library')
icon=FIF.SEARCH, self.addSubInterface(self.videoInterface, FIF.VIDEO, 'Video library')
text='Search',
onClick=lambda: self.switchTo(self.searchInterface)
)
self.navigationInterface.addItem(
routeKey=self.musicInterface.objectName(),
icon=FIF.MUSIC,
text='Music library',
onClick=lambda: self.switchTo(self.musicInterface)
)
self.navigationInterface.addItem(
routeKey=self.videoInterface.objectName(),
icon=FIF.VIDEO,
text='Video library',
onClick=lambda: self.switchTo(self.videoInterface)
)
self.navigationInterface.addSeparator() self.navigationInterface.addSeparator()
# add navigation items to scroll area # add navigation items to scroll area
self.navigationInterface.addItem( self.addSubInterface(self.folderInterface, FIF.FOLDER, 'Folder library', NavigationItemPosition.SCROLL)
routeKey=self.folderInterface.objectName(),
icon=FIF.FOLDER,
text='Folder library',
onClick=lambda: self.switchTo(self.folderInterface),
position=NavigationItemPosition.SCROLL
)
# for i in range(1, 21): # for i in range(1, 21):
# self.navigationInterface.addItem( # self.navigationInterface.addItem(
# f'folder{i}', # f'folder{i}',
...@@ -180,13 +153,7 @@ class Window(FramelessWindow): ...@@ -180,13 +153,7 @@ class Window(FramelessWindow):
position=NavigationItemPosition.BOTTOM position=NavigationItemPosition.BOTTOM
) )
self.navigationInterface.addItem( self.addSubInterface(self.settingInterface, FIF.SETTING, 'Settings', NavigationItemPosition.BOTTOM)
routeKey=self.settingInterface.objectName(),
icon=FIF.SETTING,
text='Settings',
onClick=lambda: self.switchTo(self.settingInterface),
position=NavigationItemPosition.BOTTOM
)
#!IMPORTANT: don't forget to set the default route key #!IMPORTANT: don't forget to set the default route key
self.navigationInterface.setDefaultRouteKey(self.musicInterface.objectName()) self.navigationInterface.setDefaultRouteKey(self.musicInterface.objectName())
...@@ -209,6 +176,18 @@ class Window(FramelessWindow): ...@@ -209,6 +176,18 @@ class Window(FramelessWindow):
self.setQss() self.setQss()
def addSubInterface(self, interface, icon, text: str, position=NavigationItemPosition.TOP):
""" add sub interface """
self.stackWidget.addWidget(interface)
self.navigationInterface.addItem(
routeKey=interface.objectName(),
icon=icon,
text=text,
onClick=lambda: self.switchTo(interface),
position=position,
tooltip=text
)
def setQss(self): def setQss(self):
color = 'dark' if isDarkTheme() else 'light' color = 'dark' if isDarkTheme() else 'light'
with open(f'resource/{color}/demo.qss', encoding='utf-8') as f: with open(f'resource/{color}/demo.qss', encoding='utf-8') as f:
......
...@@ -4,7 +4,7 @@ from PyQt5.QtCore import QEvent, QPoint, Qt, QUrl ...@@ -4,7 +4,7 @@ from PyQt5.QtCore import QEvent, QPoint, Qt, QUrl
from PyQt5.QtGui import QDesktopServices from PyQt5.QtGui import QDesktopServices
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout
from qfluentwidgets import ToolTip, ToolTipFilter, setTheme, Theme, PushButton from qfluentwidgets import ToolTip, ToolTipFilter, setTheme, Theme, PushButton, ToolTipPosition
class Demo(QWidget): class Demo(QWidget):
...@@ -15,7 +15,6 @@ class Demo(QWidget): ...@@ -15,7 +15,6 @@ class Demo(QWidget):
self.button1 = PushButton('キラキラ', self) self.button1 = PushButton('キラキラ', self)
self.button2 = PushButton('食べた愛', self) self.button2 = PushButton('食べた愛', self)
self.button3 = PushButton('シアワセ', self) self.button3 = PushButton('シアワセ', self)
self._toolTip = ToolTip(parent=self)
# use dark theme # use dark theme
# setTheme(Theme.DARK) # setTheme(Theme.DARK)
...@@ -24,11 +23,11 @@ class Demo(QWidget): ...@@ -24,11 +23,11 @@ class Demo(QWidget):
self.button2.setToolTip('aiko - 食べた愛 🥰') self.button2.setToolTip('aiko - 食べた愛 🥰')
self.button3.setToolTip('aiko - シアワセ 😊') self.button3.setToolTip('aiko - シアワセ 😊')
self.button1.setToolTipDuration(1000) self.button1.setToolTipDuration(1000)
self.button2.setToolTipDuration(5000) # self.button2.setToolTipDuration(-1) # won't disappear
self.button1.installEventFilter(self) self.button1.installEventFilter(ToolTipFilter(self.button1, 0, ToolTipPosition.TOP))
self.button2.installEventFilter(self) self.button2.installEventFilter(ToolTipFilter(self.button2, 0, ToolTipPosition.BOTTOM))
self.button3.installEventFilter(ToolTipFilter(self.button3)) self.button3.installEventFilter(ToolTipFilter(self.button3, 300, ToolTipPosition.RIGHT))
self.button1.clicked.connect(lambda: QDesktopServices.openUrl(QUrl( self.button1.clicked.connect(lambda: QDesktopServices.openUrl(QUrl(
'https://www.youtube.com/watch?v=S0bXDRY1DGM&list=RDMM&index=1'))) 'https://www.youtube.com/watch?v=S0bXDRY1DGM&list=RDMM&index=1')))
...@@ -44,26 +43,9 @@ class Demo(QWidget): ...@@ -44,26 +43,9 @@ class Demo(QWidget):
self.hBox.addWidget(self.button3) self.hBox.addWidget(self.button3)
self.resize(480, 240) self.resize(480, 240)
self._toolTip.hide()
self.setStyleSheet('Demo{background:white}') self.setStyleSheet('Demo{background:white}')
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())
tip.adjustPos(obj.mapToGlobal(QPoint()), obj.size())
tip.show()
elif e.type() == QEvent.Leave:
tip.hide()
elif e.type() == QEvent.ToolTip:
return True
return super().eventFilter(obj, e)
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -6,6 +6,7 @@ from PyQt5.QtGui import QResizeEvent, QIcon ...@@ -6,6 +6,7 @@ from PyQt5.QtGui import QResizeEvent, QIcon
from PyQt5.QtWidgets import QWidget from PyQt5.QtWidgets import QWidget
from .navigation_panel import NavigationPanel, NavigationItemPosition, NavigationWidget, NavigationDisplayMode from .navigation_panel import NavigationPanel, NavigationItemPosition, NavigationWidget, NavigationDisplayMode
from .navigation_widget import NavigationPushButton
from ...common.style_sheet import FluentStyleSheet from ...common.style_sheet import FluentStyleSheet
from ...common.icon import FluentIconBase from ...common.icon import FluentIconBase
...@@ -41,7 +42,7 @@ class NavigationInterface(QWidget): ...@@ -41,7 +42,7 @@ class NavigationInterface(QWidget):
FluentStyleSheet.NAVIGATION_INTERFACE.apply(self) FluentStyleSheet.NAVIGATION_INTERFACE.apply(self)
def addItem(self, routeKey: str, icon: Union[str, QIcon, FluentIconBase], text: str, onClick, selectable=True, def addItem(self, routeKey: str, icon: Union[str, QIcon, FluentIconBase], text: str, onClick, selectable=True,
position=NavigationItemPosition.TOP): position=NavigationItemPosition.TOP, tooltip: str = None) -> NavigationPushButton:
""" add navigation item """ add navigation item
Parameters Parameters
...@@ -58,16 +59,21 @@ class NavigationInterface(QWidget): ...@@ -58,16 +59,21 @@ class NavigationInterface(QWidget):
onClick: callable onClick: callable
the slot connected to item clicked signal the slot connected to item clicked signal
selectable: bool
whether the item is selectable
position: NavigationItemPosition position: NavigationItemPosition
where the button is added where the button is added
selectable: bool tooltip: str
whether the item is selectable the tooltip of item
""" """
self.panel.addItem(routeKey, icon, text, onClick, selectable, position) button = self.panel.addItem(routeKey, icon, text, onClick, selectable, position, tooltip)
self.setMinimumHeight(self.panel.layoutMinHeight()) self.setMinimumHeight(self.panel.layoutMinHeight())
return button
def addWidget(self, routeKey: str, widget: NavigationWidget, onClick, position=NavigationItemPosition.TOP): def addWidget(self, routeKey: str, widget: NavigationWidget, onClick, position=NavigationItemPosition.TOP,
tooltip: str = None):
""" add custom widget """ add custom widget
Parameters Parameters
...@@ -83,8 +89,11 @@ class NavigationInterface(QWidget): ...@@ -83,8 +89,11 @@ class NavigationInterface(QWidget):
position: NavigationItemPosition position: NavigationItemPosition
where the button is added where the button is added
tooltip: str
the tooltip of widget
""" """
self.panel.addWidget(routeKey, widget, onClick, position) self.panel.addWidget(routeKey, widget, onClick, position, tooltip)
self.setMinimumHeight(self.panel.layoutMinHeight()) self.setMinimumHeight(self.panel.layoutMinHeight())
def addSeparator(self, position=NavigationItemPosition.TOP): def addSeparator(self, position=NavigationItemPosition.TOP):
......
...@@ -8,6 +8,7 @@ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QFrame, QApplication ...@@ -8,6 +8,7 @@ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QFrame, QApplication
from .navigation_widget import NavigationPushButton, NavigationToolButton, NavigationWidget, NavigationSeparator from .navigation_widget import NavigationPushButton, NavigationToolButton, NavigationWidget, NavigationSeparator
from ..widgets.scroll_area import SingleDirectionScrollArea from ..widgets.scroll_area import SingleDirectionScrollArea
from ..widgets.tool_tip import ToolTipFilter
from ...common.style_sheet import FluentStyleSheet from ...common.style_sheet import FluentStyleSheet
from ...common.icon import FluentIconBase from ...common.icon import FluentIconBase
from ...common.icon import FluentIcon as FIF from ...common.icon import FluentIcon as FIF
...@@ -85,6 +86,13 @@ class NavigationPanel(QFrame): ...@@ -85,6 +86,13 @@ class NavigationPanel(QFrame):
self.history.emptyChanged.connect(self.returnButton.setDisabled) self.history.emptyChanged.connect(self.returnButton.setDisabled)
self.returnButton.clicked.connect(self.history.pop) self.returnButton.clicked.connect(self.history.pop)
# add tool tip
self.returnButton.installEventFilter(ToolTipFilter(self.returnButton, 1000))
self.returnButton.setToolTip(self.tr('Back'))
self.menuButton.installEventFilter(ToolTipFilter(self.menuButton, 1000))
self.menuButton.setToolTip(self.tr('Open Navigation'))
self.setProperty('menu', False) self.setProperty('menu', False)
self.scrollWidget.setObjectName('scrollWidget') self.scrollWidget.setObjectName('scrollWidget')
FluentStyleSheet.NAVIGATION_INTERFACE.apply(self) FluentStyleSheet.NAVIGATION_INTERFACE.apply(self)
...@@ -112,7 +120,8 @@ class NavigationPanel(QFrame): ...@@ -112,7 +120,8 @@ class NavigationPanel(QFrame):
self.topLayout.addWidget(self.returnButton, 0, Qt.AlignTop) self.topLayout.addWidget(self.returnButton, 0, Qt.AlignTop)
self.topLayout.addWidget(self.menuButton, 0, Qt.AlignTop) self.topLayout.addWidget(self.menuButton, 0, Qt.AlignTop)
def addItem(self, routeKey: str, icon: Union[str, QIcon, FluentIconBase], text: str, onClick, selectable=True, position=NavigationItemPosition.TOP): def addItem(self, routeKey: str, icon: Union[str, QIcon, FluentIconBase], text: str, onClick, selectable=True,
position=NavigationItemPosition.TOP, tooltip: str = None):
""" add navigation item """ add navigation item
Parameters Parameters
...@@ -134,14 +143,20 @@ class NavigationPanel(QFrame): ...@@ -134,14 +143,20 @@ class NavigationPanel(QFrame):
selectable: bool selectable: bool
whether the item is selectable whether the item is selectable
tooltip: str
the tooltip of item
""" """
if routeKey in self.items: if routeKey in self.items:
return return
button = NavigationPushButton(icon, text, selectable, self) button = NavigationPushButton(icon, text, selectable, self)
self.addWidget(routeKey, button, onClick, position) self.addWidget(routeKey, button, onClick, position, tooltip)
return button
def addWidget(self, routeKey: str, widget: NavigationWidget, onClick, position=NavigationItemPosition.TOP): def addWidget(self, routeKey: str, widget: NavigationWidget, onClick, position=NavigationItemPosition.TOP,
tooltip: str = None):
""" add custom widget """ add custom widget
Parameters Parameters
...@@ -157,6 +172,9 @@ class NavigationPanel(QFrame): ...@@ -157,6 +172,9 @@ class NavigationPanel(QFrame):
position: NavigationItemPosition position: NavigationItemPosition
where the button is added where the button is added
tooltip: str
the tooltip of widget
""" """
if routeKey in self.items: if routeKey in self.items:
return return
...@@ -169,6 +187,10 @@ class NavigationPanel(QFrame): ...@@ -169,6 +187,10 @@ class NavigationPanel(QFrame):
if self.displayMode in [NavigationDisplayMode.EXPAND, NavigationDisplayMode.MENU]: if self.displayMode in [NavigationDisplayMode.EXPAND, NavigationDisplayMode.MENU]:
widget.setCompacted(False) widget.setCompacted(False)
if tooltip:
widget.setToolTip(tooltip)
widget.installEventFilter(ToolTipFilter(widget, 1000))
self._addWidgetToLayout(widget, position) self._addWidgetToLayout(widget, position)
def addSeparator(self, position=NavigationItemPosition.TOP): def addSeparator(self, position=NavigationItemPosition.TOP):
...@@ -233,6 +255,7 @@ class NavigationPanel(QFrame): ...@@ -233,6 +255,7 @@ class NavigationPanel(QFrame):
""" expand navigation panel """ """ expand navigation panel """
self._setWidgetCompacted(False) self._setWidgetCompacted(False)
self.expandAni.setProperty('expand', True) self.expandAni.setProperty('expand', True)
self.menuButton.setToolTip(self.tr('Close Navigation'))
# determine the display mode according to the width of window # determine the display mode according to the width of window
# https://learn.microsoft.com/en-us/windows/apps/design/controls/navigationview#default # https://learn.microsoft.com/en-us/windows/apps/design/controls/navigationview#default
...@@ -269,6 +292,8 @@ class NavigationPanel(QFrame): ...@@ -269,6 +292,8 @@ class NavigationPanel(QFrame):
self.expandAni.setProperty('expand', False) self.expandAni.setProperty('expand', False)
self.expandAni.start() self.expandAni.start()
self.menuButton.setToolTip(self.tr('Open Navigation'))
def toggle(self): def toggle(self):
""" toggle navigation panel """ """ toggle navigation panel """
if self.displayMode in [NavigationDisplayMode.COMPACT, NavigationDisplayMode.MINIMAL]: if self.displayMode in [NavigationDisplayMode.COMPACT, NavigationDisplayMode.MINIMAL]:
......
...@@ -15,7 +15,7 @@ from .stacked_widget import PopUpAniStackedWidget, OpacityAniStackedWidget ...@@ -15,7 +15,7 @@ from .stacked_widget import PopUpAniStackedWidget, OpacityAniStackedWidget
from .state_tool_tip import StateToolTip from .state_tool_tip import StateToolTip
from .switch_button import SwitchButton, IndicatorPosition from .switch_button import SwitchButton, IndicatorPosition
from .table_view import TableView, TableWidget, TableItemDelegate from .table_view import TableView, TableWidget, TableItemDelegate
from .tool_tip import ToolTip, ToolTipFilter from .tool_tip import ToolTip, ToolTipFilter, ToolTipPosition
from .tree_view import TreeWidget, TreeView from .tree_view import TreeWidget, TreeView
from .cycle_list_widget import CycleListWidget from .cycle_list_widget import CycleListWidget
from .scroll_bar import ScrollBar, SmoothScrollBar, SmoothScrollDelegate from .scroll_bar import ScrollBar, SmoothScrollBar, SmoothScrollDelegate
\ No newline at end of file
# coding:utf-8 # coding:utf-8
from PyQt5.QtCore import QEvent, QObject, QPoint, QTimer, Qt from enum import Enum
from PyQt5.QtCore import QEvent, QObject, QPoint, QTimer, Qt, QPropertyAnimation, QSize
from PyQt5.QtGui import QColor, QCursor from PyQt5.QtGui import QColor, QCursor
from PyQt5.QtWidgets import (QApplication, QFrame, QGraphicsDropShadowEffect, from PyQt5.QtWidgets import (QApplication, QFrame, QGraphicsDropShadowEffect,
QHBoxLayout, QLabel, QWidget) QHBoxLayout, QLabel, QWidget)
...@@ -7,13 +9,36 @@ from PyQt5.QtWidgets import (QApplication, QFrame, QGraphicsDropShadowEffect, ...@@ -7,13 +9,36 @@ from PyQt5.QtWidgets import (QApplication, QFrame, QGraphicsDropShadowEffect,
from ...common import FluentStyleSheet from ...common import FluentStyleSheet
class ToolTipPosition(Enum):
""" Info bar position """
TOP = 0
BOTTOM = 1
LEFT = 2
RIGHT = 3
TOP_LEFT = 4
TOP_RIGHT = 5
BOTTOM_LEFT = 6
BOTTOM_RIGHT = 7
class ToolTip(QFrame): class ToolTip(QFrame):
""" Tool tip """ """ Tool tip """
def __init__(self, text='', parent=None): def __init__(self, text='', parent=None):
"""
Parameters
----------
text: str
the text of tool tip
parent: QWidget
parent widget
"""
super().__init__(parent=parent) super().__init__(parent=parent)
self.__text = text self.__text = text
self.__duration = 1000 self.__duration = 1000
self.container = QFrame(self) self.container = QFrame(self)
self.timer = QTimer(self) self.timer = QTimer(self)
...@@ -27,6 +52,10 @@ class ToolTip(QFrame): ...@@ -27,6 +52,10 @@ class ToolTip(QFrame):
self.containerLayout.addWidget(self.label) self.containerLayout.addWidget(self.label)
self.containerLayout.setContentsMargins(8, 6, 8, 6) self.containerLayout.setContentsMargins(8, 6, 8, 6)
# add opacity effect
self.opacityAni = QPropertyAnimation(self, b'windowOpacity', self)
self.opacityAni.setDuration(150)
# add shadow # add shadow
self.shadowEffect = QGraphicsDropShadowEffect(self) self.shadowEffect = QGraphicsDropShadowEffect(self)
self.shadowEffect.setBlurRadius(25) self.shadowEffect.setBlurRadius(25)
...@@ -56,9 +85,15 @@ class ToolTip(QFrame): ...@@ -56,9 +85,15 @@ class ToolTip(QFrame):
def duration(self): def duration(self):
return self.__duration return self.__duration
def setDuration(self, duration): def setDuration(self, duration: int):
""" set tooltip duration in milliseconds """ """ set tooltip duration in milliseconds
self.__duration = abs(duration)
Parameters
----------
duration: int
display duration in milliseconds, if `duration <= 0`, tooltip won't disappear automatically
"""
self.__duration = duration
def __setQss(self): def __setQss(self):
""" set style sheet """ """ set style sheet """
...@@ -69,40 +104,148 @@ class ToolTip(QFrame): ...@@ -69,40 +104,148 @@ class ToolTip(QFrame):
self.adjustSize() self.adjustSize()
def showEvent(self, e): def showEvent(self, e):
self.opacityAni.setStartValue(0)
self.opacityAni.setEndValue(1)
self.opacityAni.start()
self.timer.stop() self.timer.stop()
self.timer.start(self.__duration) if self.duration() > 0:
self.timer.start(self.__duration + self.opacityAni.duration())
super().showEvent(e) super().showEvent(e)
def hideEvent(self, e): def hideEvent(self, e):
self.timer.stop() self.timer.stop()
super().hideEvent(e) super().hideEvent(e)
def adjustPos(self, pos, size): def adjustPos(self, widget, position: ToolTipPosition):
""" adjust the position of tooltip relative to widget """ adjust the position of tooltip relative to widget """
manager = ToolTipPositionManager.make(position)
self.move(manager.position(self, widget))
Parameters
----------
pos: QPoint
global position of widget
size: QSize class ToolTipPositionManager:
size of widget """ Tooltip position manager """
"""
x = pos.x() + size.width()//2 - self.width()//2 def position(self, tooltip: ToolTip, parent: QWidget) -> QPoint:
y = pos.y() - self.height() pos = self._pos(tooltip, parent)
x, y = pos.x(), pos.y()
# adjust postion to prevent tooltips from appearing outside the screen
rect = QApplication.screenAt(QCursor.pos()).availableGeometry() rect = QApplication.screenAt(QCursor.pos()).availableGeometry()
x = min(max(0, x) if QCursor().pos().x() >= 0 else x, rect.width() - self.width() - 4) x = min(max(-2, x) if QCursor().pos().x() >= 0 else x, rect.width() - tooltip.width() - 4)
y = min(max(0, y), rect.height() - self.height() - 4) y = min(max(-2, y), rect.height() - tooltip.height() - 4)
return QPoint(x, y)
def _pos(self, tooltip: ToolTip, parent: QWidget) -> QPoint:
raise NotImplementedError
@staticmethod
def make(position: ToolTipPosition):
""" mask info bar manager according to the display position """
managers = {
ToolTipPosition.TOP: TopToolTipManager,
ToolTipPosition.BOTTOM: BottomToolTipManager,
ToolTipPosition.LEFT: LeftToolTipManager,
ToolTipPosition.RIGHT: RightToolTipManager,
ToolTipPosition.TOP_RIGHT: TopRightToolTipManager,
ToolTipPosition.BOTTOM_RIGHT: BottomRightToolTipManager,
ToolTipPosition.TOP_LEFT: TopLeftToolTipManager,
ToolTipPosition.BOTTOM_LEFT: BottomLeftToolTipManager,
}
if position not in managers:
raise ValueError(f'`{position}` is an invalid info bar position.')
self.move(x, y) return managers[position]()
class TopToolTipManager(ToolTipPositionManager):
""" Top tooltip position manager """
def _pos(self, tooltip: ToolTip, parent: QWidget):
pos = parent.mapToGlobal(QPoint())
x = pos.x() + parent.width()//2 - tooltip.width()//2
y = pos.y() - tooltip.height()
return QPoint(x, y)
class BottomToolTipManager(ToolTipPositionManager):
""" Bottom tooltip position manager """
def _pos(self, tooltip: ToolTip, parent: QWidget) -> QPoint:
pos = parent.mapToGlobal(QPoint())
x = pos.x() + parent.width()//2 - tooltip.width()//2
y = pos.y() + parent.height()
return QPoint(x, y)
class LeftToolTipManager(ToolTipPositionManager):
""" Left tooltip position manager """
def _pos(self, tooltip: ToolTip, parent: QWidget) -> QPoint:
pos = parent.mapToGlobal(QPoint())
x = pos.x() - tooltip.width()
y = pos.y() + (parent.height() - tooltip.height()) // 2
return QPoint(x, y)
class RightToolTipManager(ToolTipPositionManager):
""" Right tooltip position manager """
def _pos(self, tooltip: ToolTip, parent: QWidget) -> QPoint:
pos = parent.mapToGlobal(QPoint())
x = pos.x() + parent.width()
y = pos.y() + (parent.height() - tooltip.height()) // 2
return QPoint(x, y)
class TopRightToolTipManager(ToolTipPositionManager):
""" Top right tooltip position manager """
def _pos(self, tooltip: ToolTip, parent: QWidget) -> QPoint:
pos = parent.mapToGlobal(QPoint())
x = pos.x() + parent.width() - tooltip.width() + \
tooltip.layout().contentsMargins().right()
y = pos.y() - tooltip.height()
return QPoint(x, y)
class TopLeftToolTipManager(ToolTipPositionManager):
""" Top left tooltip position manager """
def _pos(self, tooltip: ToolTip, parent: QWidget) -> QPoint:
pos = parent.mapToGlobal(QPoint())
x = pos.x() - tooltip.layout().contentsMargins().left()
y = pos.y() - tooltip.height()
return QPoint(x, y)
class BottomRightToolTipManager(ToolTipPositionManager):
""" Bottom right tooltip position manager """
def _pos(self, tooltip: ToolTip, parent: QWidget) -> QPoint:
pos = parent.mapToGlobal(QPoint())
x = pos.x() + parent.width() - tooltip.width() + \
tooltip.layout().contentsMargins().right()
y = pos.y() + parent.height()
return QPoint(x, y)
class BottomLeftToolTipManager(ToolTipPositionManager):
""" Bottom left tooltip position manager """
def _pos(self, tooltip: ToolTip, parent: QWidget) -> QPoint:
pos = parent.mapToGlobal(QPoint())
x = pos.x() - tooltip.layout().contentsMargins().left()
y = pos.y() + parent.height()
return QPoint(x, y)
class ToolTipFilter(QObject): class ToolTipFilter(QObject):
""" Tool tip filter """ """ Tool tip filter """
def __init__(self, parent: QWidget, showDelay=300): def __init__(self, parent: QWidget, showDelay=300, position=ToolTipPosition.TOP):
""" """
Parameters Parameters
---------- ----------
...@@ -111,11 +254,15 @@ class ToolTipFilter(QObject): ...@@ -111,11 +254,15 @@ class ToolTipFilter(QObject):
showDelay: int showDelay: int
show tool tip after how long the mouse hovers in milliseconds show tool tip after how long the mouse hovers in milliseconds
position: TooltipPosition
where to show the tooltip
""" """
super().__init__(parent=parent) super().__init__(parent=parent)
self.isEnter = False self.isEnter = False
self._tooltip = None self._tooltip = None
self._tooltipDelay = showDelay self._tooltipDelay = showDelay
self.position = position
self.timer = QTimer(self) self.timer = QTimer(self)
def eventFilter(self, obj: QObject, e: QEvent) -> bool: def eventFilter(self, obj: QObject, e: QEvent) -> bool:
...@@ -126,11 +273,11 @@ class ToolTipFilter(QObject): ...@@ -126,11 +273,11 @@ class ToolTipFilter(QObject):
elif e.type() == QEvent.Enter: elif e.type() == QEvent.Enter:
self.isEnter = True self.isEnter = True
parent = self.parent() # type: QWidget parent = self.parent() # type: QWidget
if parent.isWidgetType() and parent.toolTip(): if parent.isWidgetType() and parent.toolTip() and parent.isEnabled():
if self._tooltip is None: if self._tooltip is None:
self._tooltip = ToolTip(parent.toolTip(), parent.window()) self._tooltip = ToolTip(parent.toolTip(), parent.window())
t = parent.toolTipDuration() if parent.toolTipDuration() > 0 else 1000 t = parent.toolTipDuration() if parent.toolTipDuration() > 0 else -1
self._tooltip.setDuration(t) self._tooltip.setDuration(t)
# show the tool tip after delay # show the tool tip after delay
...@@ -151,7 +298,7 @@ class ToolTipFilter(QObject): ...@@ -151,7 +298,7 @@ class ToolTipFilter(QObject):
parent = self.parent() # type: QWidget parent = self.parent() # type: QWidget
self._tooltip.setText(parent.toolTip()) self._tooltip.setText(parent.toolTip())
self._tooltip.adjustPos(parent.mapToGlobal(QPoint()), parent.size()) self._tooltip.adjustPos(parent, self.position)
self._tooltip.show() self._tooltip.show()
def setToolTipDelay(self, delay: int): def setToolTipDelay(self, delay: int):
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册