【问题标题】:PySide2 composite widget Hover EffectPySide2 复合小部件悬停效果
【发布时间】:2019-09-21 15:07:42
【问题描述】:

如何在鼠标指针进入或离开 QListWidgetItem 时为自定义小部件内的组合元素的位置、比例或任何其他属性设置动画? (见下图)

还有没有更好的方法来管理 ListWidgetItem 周围的空间? item_widget.sizeHint() 提供了不需要的额外空间,这就是我向 setSizeHint 添加硬编码值的原因。

ProductMainWindow.py

from PySide2 import QtCore, QtGui, QtWidgets
import productThumbnailWidget
import sys
sys.path.append('E:/code')

class prodMainWindowUI(QtWidgets.QMainWindow):
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        self.setupUi(self)    
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName("verticalLayout")
        self.productListWidget = QtWidgets.QListWidget(self.centralwidget)
        self.productListWidget.setObjectName("productListWidget")
        self.productListWidget.setViewMode(QtWidgets.QListWidget.IconMode)
        self.productListWidget.setIconSize(QtCore.QSize(256,256))
        self.productListWidget.setResizeMode(QtWidgets.QListWidget.Adjust)
        self.productListWidget.setMovement(QtWidgets.QListWidget.Static) # disable drag and drop
        self.productListWidget.setGridSize(QtCore.QSize(256 + 5, 256 + 5))

        self.verticalLayout.addWidget(self.productListWidget)
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        for i in range(6):
            item = QtWidgets.QListWidgetItem(self.productListWidget)
            item_widget = productThumbnailWidget.productThumbWidget()
            #item.setSizeHint(item_widget.sizeHint())
            item.setSizeHint(QtCore.QSize(256,256))
            self.productListWidget.addItem(item)
            self.productListWidget.setItemWidget(item, item_widget)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QtWidgets.QApplication.translate("MainWindow", "MainWindow", None, -1))


app = QtWidgets.QApplication(sys.argv)
prodUI = prodMainWindowUI()
prodUI.show()
sys.exit(app.exec_())

productThumbnailWidget

from PySide2 import QtCore, QtGui, QtWidgets

class productThumbWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(productThumbWidget, self).__init__(parent)
        self.setObjectName("Form")
        self.resize(256, 256)
        self.setMinimumSize(QtCore.QSize(256, 256))
        self.setMaximumSize(QtCore.QSize(256, 256))

        self.verticalLayout = QtWidgets.QVBoxLayout()
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setSpacing(0)
        self.verticalLayout.setObjectName("verticalLayout")

        self.frame = QtWidgets.QFrame()
        self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame.setObjectName("frame")

        self.thumbnailLabel = QtWidgets.QLabel("", self.frame)
        self.thumbnailLabel.setObjectName("thumbnailLabel")
        self.thumbnailLabel.setScaledContents(False)
        self.thumbnailLabel.setGeometry(QtCore.QRect(0, 0, 256, 256))
        self.thumbnailLabel.setMinimumSize(QtCore.QSize(256, 256))
        self.thumbnailLabel.setMaximumSize(QtCore.QSize(256, 256))
        self.thumbnailLabel.setPixmap(QtGui.QPixmap("E:/code/android.png"))    

        self.backgroundLabel = QtWidgets.QLabel("", self.frame)
        self.backgroundLabel.setObjectName("backgroundLabel")
        self.backgroundLabel.setGeometry(QtCore.QRect(0, 206, 256, 50))
        self.backgroundLabel.setMinimumSize(QtCore.QSize(256, 50))
        self.backgroundLabel.setMaximumSize(QtCore.QSize(256, 50))        
        self.backgroundLabel.setStyleSheet("QLabel#backgroundLabel{\n"
"    background: #32353B;\n"
"}")        

        self.titleLabel = QtWidgets.QLabel("Title", self.frame)
        self.titleLabel.setObjectName("titleLabel")
        self.titleLabel.setGeometry(QtCore.QRect(10, 218, 246, 25))
        self.titleLabel.setMinimumSize(QtCore.QSize(246, 25))
        self.titleLabel.setMaximumSize(QtCore.QSize(246, 25))
        font = QtGui.QFont()
        font.setFamily("SF Pro Display")
        font.setPointSize(16)
        font.setWeight(75)
        font.setBold(True)
        self.titleLabel.setFont(font)
        self.titleLabel.setStyleSheet("QLabel#titleLabel {\n"
"    color: #FFFFFF;\n"
"}")
        self.verticalLayout.addWidget(self.frame)
        self.setLayout(self.verticalLayout)

输出

【问题讨论】:

    标签: python pyside2


    【解决方案1】:

    解决方案是使用 QPropertyAnimation 为矩形的位置设置动画,并使用事件 QEvent::Enter 和 QEvent::Leave: 来激活动画

    import shiboken2
    from PySide2 import QtCore, QtGui, QtWidgets
    
    
    class RectangleHoverEffect(QtCore.QObject):
        def __init__(self, rectangle, parent):
            super().__init__(parent)
            if not isinstance(rectangle, QtWidgets.QWidget):
                raise TypeError(f"{rectangle} must be a QWidget")
            if rectangle.parent() is None:
                raise ValueError(f"{rectangle} must have a parent")
            self.m_rectangle = rectangle
            self.m_rectangle.parent().installEventFilter(self)
            self.m_animation = QtCore.QPropertyAnimation(
                self,
                targetObject=self.m_rectangle,
                propertyName=b"pos",
                duration=300,
                easingCurve=QtCore.QEasingCurve.OutQuad,
            )
    
        def eventFilter(self, obj, event):
            if shiboken2.isValid(self.m_rectangle):
                if self.m_rectangle.parent() is obj:
                    y0 = self.m_rectangle.parent().height()
                    y1 = self.m_rectangle.parent().height() - self.m_rectangle.height()
    
                    if event.type() == QtCore.QEvent.Enter:
                        self._start_animation(y0, y1)
                    elif event.type() == QtCore.QEvent.Leave:
                        self._start_animation(y1, y0)
            return super().eventFilter(obj, event)
    
        def _start_animation(self, y0, y1):
            self.m_animation.setStartValue(QtCore.QPoint(0, y0))
            self.m_animation.setEndValue(QtCore.QPoint(0, y1))
            self.m_animation.start()
    
    
    class ThumbWidget(QtWidgets.QFrame):
        def __init__(self, title, pixmap, parent=None):
            super().__init__(parent)
            self.setFrameShape(QtWidgets.QFrame.StyledPanel)
            self.setFrameShadow(QtWidgets.QFrame.Raised)
    
            pixmap_label = QtWidgets.QLabel(pixmap=pixmap, scaledContents=True)
            title_label = QtWidgets.QLabel(title)
            title_label.setStyleSheet("""color: #FFFFFF""")
            font = QtGui.QFont()
            font.setFamily("SF Pro Display")
            font.setPointSize(16)
            font.setWeight(75)
            font.setBold(True)
            title_label.setFont(font)
    
            background_label = QtWidgets.QLabel(pixmap_label)
            background_label.setStyleSheet("background: #32353B;")
            background_label.setFixedSize(self.width(), 50)
            background_label.move(0, self.height())
    
            background_lay = QtWidgets.QVBoxLayout(background_label)
            background_lay.addWidget(title_label)
    
            self.setFixedSize(256, 256)
            lay = QtWidgets.QVBoxLayout(self)
            lay.setContentsMargins(0, 0, 0, 0)
            lay.setSpacing(0)
            lay.addWidget(pixmap_label)
    
            effect = RectangleHoverEffect(background_label, self)
    
    
    class ProductMainWindow(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super().__init__(parent)
    
            self.product_listwidget = QtWidgets.QListWidget(
                viewMode=QtWidgets.QListWidget.IconMode,
                iconSize=QtCore.QSize(256, 256),
                resizeMode=QtWidgets.QListWidget.Adjust,
                movement=QtWidgets.QListWidget.Static,
            )
            self.product_listwidget.setGridSize(QtCore.QSize(256 + 5, 256 + 5))
    
            for i in range(6):
                item = QtWidgets.QListWidgetItem()
                item_widget = ThumbWidget(f"Title {i}", QtGui.QPixmap("E:/code/android.png"))
                item.setSizeHint(QtCore.QSize(256, 256))
                self.product_listwidget.addItem(item)
                self.product_listwidget.setItemWidget(item, item_widget)
    
            central_widget = QtWidgets.QWidget()
            self.setCentralWidget(central_widget)
            lay = QtWidgets.QVBoxLayout(central_widget)
            lay.addWidget(self.product_listwidget)
    
            self.resize(960, 480)
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        w = ProductMainWindow()
        w.show()
        sys.exit(app.exec_())
    

    【讨论】:

    • 在向 QListWidget 填充 2000-3000 个项目时,RAM 使用率变高(直到我关闭应用程序才下降)。如何解决这个问题?
    猜你喜欢
    • 1970-01-01
    • 2018-03-26
    • 2021-11-12
    • 2016-09-21
    • 2011-06-20
    • 2015-01-21
    • 2011-06-02
    • 1970-01-01
    相关资源
    最近更新 更多