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

菜单添加弹出动画

上级 024d5ecc
...@@ -18,6 +18,9 @@ ...@@ -18,6 +18,9 @@
### Hollow Handle Slider ### Hollow Handle Slider
![](./_static/gallery/hollow_handle_slider.gif) ![](./_static/gallery/hollow_handle_slider.gif)
### Round Corners Menu
![](./_static/gallery/round_menu.gif)
### Message Dialog ### Message Dialog
![](./_static/gallery/dialog_with_mask.gif) ![](./_static/gallery/dialog_with_mask.gif)
......
...@@ -29,8 +29,8 @@ class Demo(QWidget): ...@@ -29,8 +29,8 @@ class Demo(QWidget):
submenu = RoundMenu(self, "Add to") submenu = RoundMenu(self, "Add to")
submenu.setIcon(FIF.icon(FIF.ADD)) submenu.setIcon(FIF.icon(FIF.ADD))
submenu.addActions([ submenu.addActions([
QAction(FIF.icon(FIF.FOLDER), 'Folder'), QAction(FIF.icon(FIF.VIDEO), 'Video'),
QAction(FIF.icon(FIF.MUSIC_FOLDER), 'Music folder'), QAction(FIF.icon(FIF.MUSIC), 'Music'),
]) ])
menu.addMenu(submenu) menu.addMenu(submenu)
...@@ -53,7 +53,7 @@ class Demo(QWidget): ...@@ -53,7 +53,7 @@ class Demo(QWidget):
) )
# show menu # show menu
menu.exec(e.globalPos()) menu.exec(e.globalPos(), ani=True)
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
from qframelesswindow import WindowEffect from qframelesswindow import WindowEffect
from PyQt5.QtCore import (QEasingCurve, QEvent, QPropertyAnimation, QRect, from PyQt5.QtCore import (QEasingCurve, QEvent, QPropertyAnimation, QRect,
Qt, QSize, QRectF, pyqtSignal, QPoint) Qt, QSize, QRectF, pyqtSignal, QPoint)
from PyQt5.QtGui import QIcon, QColor, QPainter, QPen, QPixmap from PyQt5.QtGui import QIcon, QColor, QPainter, QPen, QPixmap, QRegion
from PyQt5.QtWidgets import (QAction, QApplication, QMenu, QProxyStyle, QStyle, from PyQt5.QtWidgets import (QAction, QApplication, QMenu, QProxyStyle, QStyle,
QGraphicsDropShadowEffect, QListWidget, QWidget, QHBoxLayout, QGraphicsDropShadowEffect, QListWidget, QWidget, QHBoxLayout,
QListWidgetItem, QStyleOptionViewItem) QListWidgetItem, QStyleOptionViewItem)
...@@ -144,7 +144,7 @@ class MenuSeparator(QWidget): ...@@ -144,7 +144,7 @@ class MenuSeparator(QWidget):
def paintEvent(self, e): def paintEvent(self, e):
painter = QPainter(self) painter = QPainter(self)
c = 0 if qconfig.theme == 'light' else 255 c = 0 if qconfig.theme == 'light' else 255
pen = QPen(QColor(c, c, c, 104), 1) pen = QPen(QColor(c, c, c, 25), 1)
pen.setCosmetic(True) pen.setCosmetic(True)
painter.setPen(pen) painter.setPen(pen)
painter.drawLine(0, 4, self.width(), 4) painter.drawLine(0, 4, self.width(), 4)
...@@ -243,6 +243,14 @@ class MenuActionListWidget(QListWidget): ...@@ -243,6 +243,14 @@ class MenuActionListWidget(QListWidget):
size += QSize(m.left()+m.right()+2, m.top()+m.bottom()) size += QSize(m.left()+m.right()+2, m.top()+m.bottom())
self.setFixedSize(size) self.setFixedSize(size)
def setItemHeight(self, height):
""" set the height of item """
for i in range(self.count()):
item = self.item(i)
item.setSizeHint(item.sizeHint().width(), i)
self.adjustSize()
class RoundMenu(QWidget): class RoundMenu(QWidget):
""" Round corner menu """ """ Round corner menu """
...@@ -255,8 +263,10 @@ class RoundMenu(QWidget): ...@@ -255,8 +263,10 @@ class RoundMenu(QWidget):
self.isSubMenu = False self.isSubMenu = False
self.parentMenu = None self.parentMenu = None
self.menuItem = None self.menuItem = None
self.itemHeight = 28
self.hBoxLayout = QHBoxLayout(self) self.hBoxLayout = QHBoxLayout(self)
self.view = MenuActionListWidget(self) self.view = MenuActionListWidget(self)
self.ani = QPropertyAnimation(self, b'pos', self)
self.__initWidgets() self.__initWidgets()
def __initWidgets(self): def __initWidgets(self):
...@@ -268,9 +278,19 @@ class RoundMenu(QWidget): ...@@ -268,9 +278,19 @@ class RoundMenu(QWidget):
self.setShadowEffect() self.setShadowEffect()
self.hBoxLayout.addWidget(self.view) self.hBoxLayout.addWidget(self.view)
self.hBoxLayout.setContentsMargins(12, 8, 12, 20) self.hBoxLayout.setContentsMargins(12, 8, 12, 20)
self.view.itemClicked.connect(self.__onItemClicked)
setStyleSheet(self, 'menu') setStyleSheet(self, 'menu')
self.view.itemClicked.connect(self._onItemClicked)
self.ani.valueChanged.connect(self._onSlideValueChanged)
def setItemHeight(self, height):
""" set the height of menu item """
if height == self.itemHeight:
return
self.itemHeight = height
self.view.setItemHeight(height)
def setShadowEffect(self, blurRadius=30, offset=(0, 8), color=QColor(0, 0, 0, 30)): def setShadowEffect(self, blurRadius=30, offset=(0, 8), color=QColor(0, 0, 0, 30)):
""" add shadow to dialog """ """ add shadow to dialog """
self.shadowEffect = QGraphicsDropShadowEffect(self.view) self.shadowEffect = QGraphicsDropShadowEffect(self.view)
...@@ -324,10 +344,12 @@ class RoundMenu(QWidget): ...@@ -324,10 +344,12 @@ class RoundMenu(QWidget):
# icon empty icon # icon empty icon
icon = QIcon(MenuIconEngine(action.icon())) icon = QIcon(MenuIconEngine(action.icon()))
if hasIcon and icon.isNull(): if hasIcon and action.icon().isNull():
pixmap = QPixmap(self.view.iconSize()) pixmap = QPixmap(self.view.iconSize())
pixmap.fill(Qt.transparent) pixmap.fill(Qt.transparent)
icon = QIcon(pixmap) icon = QIcon(pixmap)
elif not hasIcon:
icon = QIcon()
item = QListWidgetItem(icon, action.text()) item = QListWidgetItem(icon, action.text())
if not hasIcon: if not hasIcon:
...@@ -337,7 +359,7 @@ class RoundMenu(QWidget): ...@@ -337,7 +359,7 @@ class RoundMenu(QWidget):
item.setText(" " + item.text()) item.setText(" " + item.text())
w = 60 + self.view.fontMetrics().width(item.text()) w = 60 + self.view.fontMetrics().width(item.text())
item.setSizeHint(QSize(w, 33)) item.setSizeHint(QSize(w, self.itemHeight))
action.setProperty('item', item) action.setProperty('item', item)
item.setData(Qt.UserRole, action) item.setData(Qt.UserRole, action)
return item return item
...@@ -426,7 +448,7 @@ class RoundMenu(QWidget): ...@@ -426,7 +448,7 @@ class RoundMenu(QWidget):
# add submenu item # add submenu item
menu._setParentMenu(self, item) menu._setParentMenu(self, item)
item.setSizeHint(QSize(w, 33)) item.setSizeHint(QSize(w, self.itemHeight))
item.setData(Qt.UserRole, menu) item.setData(Qt.UserRole, menu)
w = SubMenuItemWidget(menu, item, self) w = SubMenuItemWidget(menu, item, self)
w.showMenuSig.connect(self._showSubMenu) w.showMenuSig.connect(self._showSubMenu)
...@@ -437,13 +459,6 @@ class RoundMenu(QWidget): ...@@ -437,13 +459,6 @@ class RoundMenu(QWidget):
def _showSubMenu(self): def _showSubMenu(self):
""" show sub menu """ """ show sub menu """
w = self.sender() w = self.sender()
# update selected row
self.view.clearSelection()
QApplication.processEvents()
self.view.setCurrentItem(w.item)
# show sub menu
pos = w.mapToGlobal(QPoint()) pos = w.mapToGlobal(QPoint())
pos += QPoint(w.width()-6, 0) pos += QPoint(w.width()-6, 0)
w.menu.exec(pos) w.menu.exec(pos)
...@@ -470,7 +485,7 @@ class RoundMenu(QWidget): ...@@ -470,7 +485,7 @@ class RoundMenu(QWidget):
self.view.addItem(item) self.view.addItem(item)
self.view.setItemWidget(item, separator) self.view.setItemWidget(item, separator)
def __onItemClicked(self, item): def _onItemClicked(self, item):
action = item.data(Qt.UserRole) action = item.data(Qt.UserRole)
if action not in self._actions: if action not in self._actions:
return return
...@@ -511,7 +526,10 @@ class RoundMenu(QWidget): ...@@ -511,7 +526,10 @@ class RoundMenu(QWidget):
view = self.parentMenu.view view = self.parentMenu.view
w = view.itemWidget(self.menuItem) w = view.itemWidget(self.menuItem)
rect = w.geometry().translated(w.mapToGlobal(QPoint())-w.pos()) rect = w.geometry().translated(w.mapToGlobal(QPoint())-w.pos())
if self.parentMenu.geometry().contains(pos) and not rect.contains(pos): mr = self.geometry()
mr.setHeight(self.itemHeight + 10)
if self.parentMenu.geometry().contains(pos) and not rect.contains(pos) and \
not mr.contains(pos):
view.clearSelection() view.clearSelection()
self._hideMenu() self._hideMenu()
...@@ -522,14 +540,40 @@ class RoundMenu(QWidget): ...@@ -522,14 +540,40 @@ class RoundMenu(QWidget):
if index < view.count()-1: if index < view.count()-1:
view.item(index+1).setFlags(Qt.ItemIsEnabled) view.item(index+1).setFlags(Qt.ItemIsEnabled)
def exec(self, pos): def _onSlideValueChanged(self, pos):
m = self.layout().contentsMargins()
w = self.view.width() + m.left() + m.right() + 120
h = self.view.height() + m.top() + m.bottom() + 20
y = self.ani.endValue().y() - pos.y()
self.setMask(QRegion(0, y, w, h))
def exec(self, pos, ani=True):
""" show menu
Parameters
----------
pos: QPoint
pop-up position
ani: bool
Whether to show pop-up animation
"""
desktop = QApplication.desktop().availableGeometry() desktop = QApplication.desktop().availableGeometry()
m = self.layout().contentsMargins() m = self.layout().contentsMargins()
w = self.view.width() + m.left() + m.right() + 20 w = self.view.width() + m.left() + m.right() + 20
h = self.view.height() + m.top() + m.bottom() + 20 h = self.view.height() + m.top() + m.bottom() + 20
pos.setX(min(pos.x() - 30, desktop.width() - w)) pos.setX(min(pos.x() - 30, desktop.width() - w))
pos.setY(min(pos.y() - 12, desktop.height() - h)) pos.setY(min(pos.y() - 10, desktop.height() - h))
self.move(pos)
if ani:
self.ani.setStartValue(pos-QPoint(0, h/2))
self.ani.setEndValue(pos)
self.ani.setDuration(250)
self.ani.setEasingCurve(QEasingCurve.OutQuad)
self.ani.start()
else:
self.move(pos)
self.show() self.show()
if not self.isSubMenu: if not self.isSubMenu:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册