使用PySide覆盖QPushButton类事件方法

时间:2018-06-19 14:32:26

标签: python python-2.7 pyside

我想创建一个自定义按钮类,以允许单击拖放。我还希望能够控制它的美观性(按钮颜色,鼠标悬停在颜色上,单击的颜色,拖曳在颜色上等等)。

注意:这些示例是我需要做的简短的通用版本。我知道它并不包含所有必要的工作,某些变量和函数的名称仅是示例。我的实际示例将需要多达15个此类的实例,而不是所示的4个实例。

点击的示例中,只要我覆盖 mousePressEvent mouseReleaseEvent my_button.clicked.connect(my_func)语句就不会更长的作品。而且我想将此自定义类用于所有类型的按钮功能,所以我不能只是将按钮功能放在重写的方法中,这是我当前的解决方案,并且我讨厌它(见下文)。我在样式表更改后尝试使用super(DropZone_Category, self)mouseReleaseEvent(event)语句(如其他问题所建议),但这对我没有任何帮助。我真正想要做的就是控制样式表,因此,如果有更好的方法,请告知。

from PySide import QtGui, QtCore


class DropZone_Category(QtGui.QPushButton):
    def __init__(self, parent=None, *args, **kwargs):
        super(DropZone_Category, self).__init__(parent, *args, **kwargs)

        # Instance Attrs
        self.parent = parent

        # Style Variables
        self.dropZone_font = QtGui.QFont()
        self.dropZone_font.setPointSize(16)
        self.dropZone_font.setFamily("Calibri")
        self.default_button_stylesheet = "background-color: rgb(100,100,100);" \
                                         "color: lightgrey;" \
                                         "border-radius: 3px;"

        self.drag_button_stylesheet = "background-color: rgb(166,215,176);" \
                                          "color: rgb(0,97,19);" \
                                          "border-radius: 3px;"

        self.hover_button_stylesheet =  "background-color: rgb(150,150,150);" \
                                         "color: lightgrey;" \
                                         "border-radius: 3px;"

        self.clicked_button_stylesheet = "background-color: rgb(80,80,80);" \
                                         "color: lightgrey;" \
                                         "border-radius: 3px;"

        # Overrides
        self.resize(QtCore.QSize(120, 120))
        self.setFont(self.dropZone_font)
        self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
        self.setMinimumSize(90, 90)
        self.setAcceptDrops(True)
        self.setStyleSheet(self.default_button_stylesheet)

    def enterEvent(self, *args, **kwargs):
        self.setStyleSheet(self.hover_button_stylesheet)

    def leaveEvent(self, *args, **kwargs):
        self.setStyleSheet(self.default_button_stylesheet)

    def mousePressEvent(self, *args, **kwargs):
        self.setStyleSheet(self.clicked_button_stylesheet)
        # super(DropZone_Category, self).mousePressEvent(event)

    def mouseReleaseEvent(self, event,*args, **kwargs):
        button_used = self.text()
        self.setStyleSheet(self.default_button_stylesheet)
        # super(DropZone_Category, self).mouseReleaseEvent(event)

        if button_used == "btn1":
            btn1_clicked_func()
        elif button_used == "btn2":
            btn2_clicked_func()
        elif button_used == "btn3":
            btn3_clicked_func()
        elif button_used == "btn4":
            btn4_clicked_func()

拖放功能的示例中,我需要一种更简单,更干净的方法来设置每个按钮的放置功能,因为每个所需的实例都不同。如果可能,类似于my_button.clicked.connect(my_func)的内容。如果不可能的话,我欢迎其他建议。我目前正在像上面的mouseReleaseEvent方法一样处理它,但是在 dropEvent 方法中,我再次...讨厌。

def dragEnterEvent(self, event):
        if event.mimeData().hasUrls():
            self.setStyleSheet(self.drag_button_stylesheet)

            event.acceptProposedAction()
        else:
            super(DropZone_Category, self).dragEnterEvent(event)

def dragLeaveEvent(self, event):
    self.setStyleSheet(self.default_button_stylesheet)

def dragMoveEvent(self, event):
    super(DropZone_Category, self).dragMoveEvent(event)

def dropEvent(self, event):
    zone_used = self.text()
    paths_list = [url.toLocalFile() for url in event.mimeData().urls()]
    num_files = len(paths_list)

    if not utils.isImages(paths_list): # check if drop objects are images
        print "Drop Rejected: Not all files dropped were images"
    elif not event.mimeData().hasUrls(): # check if drop objects are files
        print "Drop Rejected: Not all items dropped were files"
    else:
        if button_used == "btn1":
            btn1_dropped_func(paths_list )
        elif button_used == "btn2":
            btn2_dropped_func(paths_list )
        elif button_used == "btn3":
            btn3_dropped_func(paths_list )
        elif button_used == "btn4":
            btn4_dropped_func(paths_list )


        sleep(.5)
        self.setStyleSheet(self.default_button_stylesheet)

如上所述,造成混乱的主要原因是我真的很想学习如何控制UI的美观性。再加上将在这些类中使用的大量非常具体的实例以及新增的拖放功能,这使我感到头疼。我当前的结论(有其他建议)是为我需要的每个特殊实例创建此基类的子类(即DropZone_Categories的15个子类)。我真的很讨厌这样做,因为这似乎违反了上课的全部理由。如果这是唯一的解决方案,我会很乐意这样做,但我只是想在弄得一团糟之前先看看。感谢您,并表示抱歉。

1 个答案:

答案 0 :(得分:0)

我首先看到您使用的Qt StyleSheet不正确,QSS处理伪hoverpressed之类的伪状态,因此没有必要每次都更改QSS任务很昂贵。

那种情况下的解决方案是使用伪状态:

DropZone_Category{
    background-color: rgb(100,100,100);
    color: lightgrey;
    border-radius: 3px;
}

DropZone_Category:hover{
    background-color: rgb(150,150,150);
    color: lightgrey;
    border-radius: 3px;
}

DropZone_Category:pressed{
    background-color: rgb(80,80,80);
    color: lightgrey;
    border-radius: 3px
}

根据您所说的,这是与您的帖子最相关的信息,您希望每个按钮以不同的方式处理文件,因此最好的选择是创建一个信号,将文件发送到负责处理它。在下面的示例中,创建了4个按钮,每个按钮都可以连接到文件获取的插槽,那么处理这些文件的逻辑部分就是您的责任。

import sys

from PySide import QtGui, QtCore


class DropZone_Category(QtGui.QPushButton):
    pathsChanged = QtCore.Signal(list)

    def __init__(self, *args, **kwargs):
        super(DropZone_Category, self).__init__(*args, **kwargs)
        font = self.font()
        font.setPointSize(16)
        font.setFamily("Calibri")
        self.setFont(font)
        self.resize(QtCore.QSize(120, 120))
        self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
        self.setMinimumSize(90, 90)
        self.setAcceptDrops(True)

        QSS = """
            DropZone_Category{
                background-color: rgb(100,100,100);
                color: lightgrey;
                border-radius: 3px;
            }

            DropZone_Category:hover{
                background-color: rgb(150,150,150);
                color: lightgrey;
                border-radius: 3px;
            }

            DropZone_Category:pressed{
                background-color: rgb(80,80,80);
                color: lightgrey;
                border-radius: 3px
            }
        """
        self.setStyleSheet(QSS)

    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls():
            event.acceptProposedAction()

    def dropEvent(self, event):
        paths_list = [url.toLocalFile() for url in event.mimeData().urls()]
        if paths_list:
            self.pathsChanged.emit(paths_list)

class Widget(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        lay = QtGui.QVBoxLayout(self)

        info = [("category 1", self.fun1), ("category 2", self.fun2), ("category 3", self.fun3), ("category 4", self.fun4)]

        for text, fun in info:
            button = DropZone_Category(text)
            button.pathsChanged.connect(fun)
            lay.addWidget(button)

    def fun1(self, files):
        print("fun1", files)

    def fun2(self, files):
        print("fun2", files)

    def fun3(self, files):
        print("fun3", files)

    def fun4(self, files):
        print("fun4", files)

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())