用 PySide 覆盖 QPushButton Class 事件方法
Overriding QPushButton Class Event Method with PySide
我想制作一个允许点击和拖放的自定义按钮class。我还希望能够控制它的美观(按钮颜色、鼠标悬停颜色、点击颜色、拖动颜色等)。
注意:这些示例是我需要做的较短的通用版本。我知道它不包含工作所需的所有内容,一些变量和函数的名称只是示例。我的真实示例将需要多达 15 个此 class 的实例,而不是显示的 4 个。
在 clicking 按钮的示例中,一旦我覆盖 mousePressEvent 和 mouseReleaseEvent my_button.clicked.connect(my_func)
语句不再有效。因为我想将此自定义 class 用于所有类型的按钮功能,所以我不能只将按钮功能放在覆盖的方法中,这是我当前的解决方案,我讨厌它(见下文)。我尝试在我的样式 sheet 更改后使用 super(DropZone_Category, self)mouseReleaseEvent(event)
语句(如其他问题中所建议的那样),但这对我来说绝对没有任何作用。我真正想用这些覆盖来做的就是控制样式 sheet 所以如果有更好的方法来做到这一点,请指教。
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的审美。再加上将从这些 classes 中使用的大量非常具体的实例,以及添加的拖放功能,这让我很头疼。我目前的结论(与其他人的建议)是为我需要的每个特殊实例(即 DropZone_Categories 的 15 个子class )创建一个此基础 class 的子 class。我真的很讨厌这样做,因为感觉它违反了制作 classes 的全部原因。如果这是唯一的解决方案,我会很乐意这样做,但我只是想在弄得一团糟之前先看看。感谢和抱歉 post。
首先我看到你错误地使用了 Qt StyleSheet,QSS 处理像 hover
和 pressed
这样的伪状态,所以没有必要每时每刻都改变 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
}
根据您提到的内容,这是与您的 post 最相关的信息,您希望每个按钮以不同方式处理文件,因此最好的选择是创建一个信号,将文件发送到将负责处理它的插槽。在下面的示例中,创建了 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_())
我想制作一个允许点击和拖放的自定义按钮class。我还希望能够控制它的美观(按钮颜色、鼠标悬停颜色、点击颜色、拖动颜色等)。
注意:这些示例是我需要做的较短的通用版本。我知道它不包含工作所需的所有内容,一些变量和函数的名称只是示例。我的真实示例将需要多达 15 个此 class 的实例,而不是显示的 4 个。
在 clicking 按钮的示例中,一旦我覆盖 mousePressEvent 和 mouseReleaseEvent my_button.clicked.connect(my_func)
语句不再有效。因为我想将此自定义 class 用于所有类型的按钮功能,所以我不能只将按钮功能放在覆盖的方法中,这是我当前的解决方案,我讨厌它(见下文)。我尝试在我的样式 sheet 更改后使用 super(DropZone_Category, self)mouseReleaseEvent(event)
语句(如其他问题中所建议的那样),但这对我来说绝对没有任何作用。我真正想用这些覆盖来做的就是控制样式 sheet 所以如果有更好的方法来做到这一点,请指教。
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的审美。再加上将从这些 classes 中使用的大量非常具体的实例,以及添加的拖放功能,这让我很头疼。我目前的结论(与其他人的建议)是为我需要的每个特殊实例(即 DropZone_Categories 的 15 个子class )创建一个此基础 class 的子 class。我真的很讨厌这样做,因为感觉它违反了制作 classes 的全部原因。如果这是唯一的解决方案,我会很乐意这样做,但我只是想在弄得一团糟之前先看看。感谢和抱歉 post。
首先我看到你错误地使用了 Qt StyleSheet,QSS 处理像 hover
和 pressed
这样的伪状态,所以没有必要每时每刻都改变 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
}
根据您提到的内容,这是与您的 post 最相关的信息,您希望每个按钮以不同方式处理文件,因此最好的选择是创建一个信号,将文件发送到将负责处理它的插槽。在下面的示例中,创建了 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_())