python - QStyledItemDelegate 内的自定义 QPushButton
问题描述
问题:
我可以将 QPushButton 添加到 QStyledItemDelegate 就好了。我在委托的 editorEvent 方法中伪造按钮按下,所以当你按下它时,就会发生动作。我无法让我的 QPushButton 的样式表正常工作 - 它只读取第一个背景参数,即“红色”并且在鼠标悬停或按下时不会改变。
目前尚不清楚我应该如何设置按钮单击和悬停检测以使按钮像代理上的真实按钮一样。我需要设置一个事件过滤器吗?我应该在视图级别执行此操作吗?我是否在委托的绘制方法中执行此操作?一切的结合?
目标:
- 将鼠标悬停在列表时间上将显示按钮按钮的图标。
- 将鼠标悬停在按钮上将更改其背景颜色。
- 鼠标点击按钮会使背景颜色变暗以显示发生了点击。
- 如果可能的话,我想在样式表中设置这些参数,但我也不介意在绘制函数中完成所有这些。什么都行!
当前实施
按钮小部件是红色的,带有文件夹图标。这些项目在选择和悬停时正确改变颜色(我想保留它),但项目的按钮根本没有改变。
谢谢!
到目前为止,这是我汇总的内容:
import sys
from PySide2 import QtCore
from PySide2 import QtGui
from PySide2 import QtWidgets
class DelegateButton(QtWidgets.QPushButton):
def __init__(self, parent=None):
super(DelegateButton, self).__init__(parent)
# self.setLayout(QHBoxLayout())
size = 50
self.setFixedSize(size, size)
self.setIcon(self.style().standardIcon(QtWidgets.QStyle.SP_DialogOpenButton))
self.setStyleSheet("""
QPushButton{
background:red;
height: 30px;
font: 12px "Roboto Thin";
border-radius: 25
}
QPushButton:hover{
background: green;
}
QPushButton:hover:pressed{
background: blue;
}
QPushButton:pressed{
background: yellow;
}
""")
class MainWindow(QtWidgets.QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.resize(300, 300)
# Model/View
entries = ['one', 'two', 'three']
model = QtGui.QStandardItemModel()
delegate = ListItemDelegate()
self.listView = QtWidgets.QListView(self)
self.listView.setModel(model)
self.listView.setItemDelegate(delegate)
for i in entries:
item = QtGui.QStandardItem(i)
model.appendRow(item)
# Layout
main_layout = QtWidgets.QVBoxLayout()
main_layout.addWidget(self.listView)
self.setLayout(main_layout)
# Connections
delegate.delegateButtonPressed.connect(self.on_delegate_button_pressed)
def on_delegate_button_pressed(self, index):
print('"{}" delegate button pressed'.format(index.data(QtCore.Qt.DisplayRole)))
class ListItemDelegate(QtWidgets.QStyledItemDelegate):
delegateButtonPressed = QtCore.Signal(QtCore.QModelIndex)
def __init__(self):
super(ListItemDelegate, self).__init__()
self.button = DelegateButton()
def sizeHint(self, option, index):
size = super(ListItemDelegate, self).sizeHint(option, index)
size.setHeight(50)
return size
def editorEvent(self, event, model, option, index):
# Launch app when launch button clicked
if event.type() == QtCore.QEvent.MouseButtonRelease:
click_pos = event.pos()
rect_button = self.rect_button
if rect_button.contains(click_pos):
self.delegateButtonPressed.emit(index)
return True
else:
return False
else:
return False
def paint(self, painter, option, index):
spacing = 10
icon_size = 40
# Item BG #########################################
painter.save()
if option.state & QtWidgets.QStyle.State_Selected:
painter.setBrush(QtGui.QColor('orange'))
elif option.state & QtWidgets.QStyle.State_MouseOver:
painter.setBrush(QtGui.QColor('black'))
else:
painter.setBrush(QtGui.QColor('purple'))
painter.drawRect(option.rect)
painter.restore()
# Item Text ########################################
rect_text = option.rect
QtWidgets.QApplication.style().drawItemText(painter, rect_text, QtCore.Qt.AlignVCenter | QtCore.Qt.AlignLeft, QtWidgets.QApplication.palette(), True, index.data(QtCore.Qt.DisplayRole))
# Custom Button ######################################
self.rect_button = QtCore.QRect(
option.rect.right() - icon_size - spacing,
option.rect.bottom() - int(option.rect.height() / 2) - int(icon_size / 2),
icon_size,
icon_size
)
option = QtWidgets.QStyleOptionButton()
option.initFrom(self.button)
option.rect = self.rect_button
# Button interactive logic
if self.button.isDown():
option.state = QtWidgets.QStyle.State_Sunken
else:
pass
if self.button.isDefault():
option.features = option.features or QtWidgets.QStyleOptionButton.DefaultButton
option.icon = self.button.icon()
option.iconSize = QtCore.QSize(30, 30)
painter.save()
self.button.style().drawControl(QtWidgets.QStyle.CE_PushButton, option, painter, self.button)
painter.restore()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
解决方案
试试: https ://doc.qt.io/qt-4.8/qstyle.html#StateFlag-enum
import sys
import PySide.QtCore as core
import PySide.QtGui as gui
QPushButton#pushButton {
background-color: yellow;
}
QPushButton#pushButton:hover {
background-color: rgb(224, 255, 0);
}
QPushButton#pushButton:pressed {
background-color: rgb(224, 0, 0);
}
您的自定义 QStyledItemDelegate 捕获鼠标事件,因此它不会传递给 QListView。所以在 QStyledItemDelegate.editor(Event) 中只需要添加一个。
if event.type() == core.QEvent.MouseButtonPress:
return False
现在可以使用 option.state 和 gui.QStyle.State_Selected 在paint() 方法中识别选择。
if __name__ == '__main__':
app = gui.QApplication(sys.argv)
app.setStyleSheet('QListView::item:hover {background: none;}')
mw = gui.QMainWindow()
model = MyListModel()
view = gui.QListView()
view.setItemDelegate(MyListDelegate(parent=view))
view.setSpacing(5)
view.setModel(model)
mw.setCentralWidget(view)
mw.show()
sys.exit(app.exec_())
class MyListDelegate(gui.QStyledItemDelegate):
w = 300
imSize = 90
pad = 5
h = imSize + 2*pad
sepX = 10
def __init__(self, parent=None):
super(MyListDelegate, self).__init__(parent)
def paint(self, painter, option, index):
mouseOver = option.state in [73985, 73729]
if option.state & QStyle.State_MouseOver::
painter.fillRect(option.rect, painter.brush())
pen = painter.pen()
painter.save()
x,y = (option.rect.x(), option.rect.y())
dataRef = index.data()
pixmap = dataRef.pixmap()
upperLabel = dataRef.upperLabel()
lowerLabel = dataRef.lowerLabel()
if mouseOver:
newPen = gui.QPen(core.Qt.green, 1, core.Qt.SolidLine)
painter.setPen(newPen)
else:
painter.setPen(pen)
painter.drawRect(x, y, self.w, self.h)
painter.setPen(pen)
x += self.pad
y += self.pad
painter.drawPixmap(x, y, pixmap)
font = painter.font()
textHeight = gui.QFontMetrics(font).height()
sX = self.imSize + self.sepX
sY = textHeight/2
font.setBold(True)
painter.setFont(font)
painter.drawText(x+sX, y-sY,
self.w-self.imSize-self.sepX, self.imSize,
core.Qt.AlignVCenter,
upperLabel)
font.setBold(False)
font.setItalic(True)
painter.setFont(font)
painter.drawText(x+sX, y+sY,
self.w-self.imSize-self.sepX, self.imSize,
core.Qt.AlignVCenter,
lowerLabel)
painter.restore()
def sizeHint(self, option, index):
return core.QSize(self.w, self.imSize+2*self.pad)
def editorEvent(self, event, model, option, index):
if event.type() == core.QEvent.MouseButtonRelease:
print 'Clicked on Item', index.row()
if event.type() == core.QEvent.MouseButtonDblClick:
print 'Double-Clicked on Item', index.row()
return True
window.button->setAutoFillBackground(false);
window.button->setAutoFillBackground(true);
window.button->setPalette(*palette_red);
设置 CSS 的另一种解决方案:
import sys
from PyQt5 import Qt as qt
class TopLabelNewProject(qt.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
layout = qt.QHBoxLayout(self)
layout.setContentsMargins(40, 0, 32, 0)
self.setLayout(layout)
self.setFixedHeight(80)
self.label = qt.QLabel("Dashboard")
layout.addWidget(self.label, alignment=qt.Qt.AlignLeft)
# self.newProjectButton = Buttons.DefaultButton("New project", self)
self.newProjectButton = qt.QPushButton("New project", self)
layout.addWidget(self.newProjectButton, alignment=qt.Qt.AlignRight)
style = '''
QWidget {
background-color: white;
}
QLabel {
font: medium Ubuntu;
font-size: 20px;
color: #006325;
}
QPushButton {
background-color: #006325;
color: white;
min-width: 70px;
max-width: 70px;
min-height: 70px;
max-height: 70px;
border-radius: 35px;
border-width: 1px;
border-color: #ae32a0;
border-style: solid;
}
QPushButton:hover {
background-color: #328930;
}
QPushButton:pressed {
background-color: #80c342;
}
'''
if __name__ == '__main__':
app = qt.QApplication(sys.argv)
app.setStyleSheet(style)
ex = TopLabelNewProject()
ex.show()
sys.exit(app.exec_())
推荐阅读
- c# - 在 confluent-dotnet-kafka 中,如何在 .Net 中的 Message Producer 中传递对象
- rubygems - 在本地服务站点时无法理解多个捆绑程序/宝石错误
- asp.net - 无法自动进入服务器。带有 ASMX 服务的 ASP.NET 网络表单应用程序
- javascript - Vue需要计算属性和方法中的function关键字吗?
- reactjs - 是否可以在固定域内容纳烧瓶和反应?
- php - 如何在 Flutter 中设置 S2S 回传调用?
- javascript - 引导模式每次都显示相同
- sql - 仅在前面行中的一个值小于另一个值时聚合前面的行
- python - 一个不和谐的机器人命令使其他命令不起作用
- python - 如何将类的其他对象的引用存储在同一个类中?