如何在多个项目小部件之间共享单个样式表?
下面的代码创建了一个 QTreeWidget
,里面有两个 QComboBoxes
,它们被设置为这个树形控件的项目小部件。第一个下拉框(ComboBox)有一个 QSS 样式表。
问题:因为 QTreeWidgetItem
这个父级控件没有 .setStyleSheet()
这个方法,所以我必须一个一个地遍历每个项目的小部件来设置或修改它们的样式表。显然,这样额外的计算会让图形界面的响应变慢。如果所有项目的下拉框都能共享同一个样式表,那就太好了。这样只要改变一个下拉框的样式表,就能同时改变所有项目下拉框的外观。怎么才能做到这一点呢?
from PyQt4 import QtCore, QtGui
app = QtGui.QApplication([])
class Tree(QtGui.QTreeWidget):
def __init__(self, *args, **kwargs):
super(Tree, self).__init__()
for each in ['Item_1','Item_2','Item_3','Item_4','Item_5']:
item=QtGui.QTreeWidgetItem([each])
self.addTopLevelItem(item)
combo1=QtGui.QComboBox()
combo2=QtGui.QComboBox()
self.setItemWidget(item, 1, combo1)
self.setItemWidget(item, 2, combo2)
comboStyle="QComboBox {background-color: #7A7A7A; border: 1px solid black;}"
combo1.setStyleSheet(comboStyle)
self.setColumnCount(5)
self.resize(360,240)
self.show()
tree=Tree()
sys.exit(app.exec_())
2 个回答
0
这是我如何使用信号和槽来改变并重新应用样式表到子类小部件的方法。我喜欢这种方法,因为这样就不需要逐个遍历所有的 QListWidgetsItems
和它的 ItemWidgets
。这些 ItemWidgets
会监听信号,并自己更新样式。我还在这里实现了一个机制,当点击其中一个 Item-Widgets
时,可以选择对应的 QTreeWidgetItem
。
from PyQt4 import QtCore, QtGui
app = QtGui.QApplication([])
class LineEdit(QtGui.QLineEdit):
def __init__(self, tree, item):
QtGui.QLineEdit.__init__(self)
self.tree=tree
self.item=item
self.restyle()
def mousePressEvent(self, event):
self.emit(QtCore.SIGNAL('click!'),self)
def restyle(self):
if self.item.isSelected(): bgColor='#7A7A7A'
elif self.tree.indexFromItem(self.item).row()%2: bgColor='#1F1F1F'
else: bgColor='#262626'
stylesheet="QLineEdit {{background-color: {0}; border: 1px solid black;}}".format(bgColor)
self.setStyleSheet(stylesheet)
for i in range(5): self.item.setBackgroundColor(i, QtGui.QColor(bgColor))
class ComboBox(QtGui.QComboBox):
def __init__(self, tree, item):
QtGui.QComboBox.__init__(self)
self.tree=tree
self.item=item
self.restyle()
def mousePressEvent(self, event):
self.emit(QtCore.SIGNAL('click!'),self)
def restyle(self):
if self.item.isSelected(): bgColor='#7A7A7A'
elif self.tree.indexFromItem(self.item).row()%2: bgColor='#1F1F1F'
else: bgColor='#262626'
stylesheet="QComboBox {{background-color: {0}; border: 1px solid black;}}".format(bgColor)
self.setStyleSheet(stylesheet)
for i in range(5): self.item.setBackgroundColor(i, QtGui.QColor(bgColor))
class Tree(QtGui.QTreeWidget):
def __init__(self, *args, **kwargs):
super(Tree, self).__init__()
self.setAutoFillBackground(True)
self.setBackgroundRole(QtGui.QPalette.Base)
p = self.palette()
p.setColor(self.backgroundRole(), QtGui.QColor("#0F0F0F"))
self.setPalette(p)
self.setColumnCount(5)
for each in ['Item_1','Item_2','Item_3','Item_4','Item_5']:
item=QtGui.QTreeWidgetItem([each])
self.addTopLevelItem(item)
combo=ComboBox(self, item)
lineEdit=LineEdit(self, item)
combo.connect(self, QtCore.SIGNAL('selectionChanged!'), combo.restyle)
lineEdit.connect(self, QtCore.SIGNAL('selectionChanged!'), lineEdit.restyle)
self.setItemWidget(item, 1, combo)
self.setItemWidget(item, 2, lineEdit)
self.connect(combo, QtCore.SIGNAL('click!'), self.select)
self.connect(lineEdit, QtCore.SIGNAL('click!'), self.select)
self.itemSelectionChanged.connect(self.emitOnChange)
self.resize(480,120)
self.show()
def select(self, itemWidget):
for i in range(self.topLevelItemCount()):
self.topLevelItem(i).setSelected(False)
itemWidget.item.setSelected(True)
def emitOnChange(self, arg=None):
self.emit(QtCore.SIGNAL('selectionChanged!'),self)
tree=Tree()
sys.exit(app.exec_())
1
我个人觉得单独设置样式并没有什么问题,反而可能更清晰。不过,下面这种方法也可以:你可以为父级控件设置样式,子控件会自动继承这些样式,除非你另有指定。
class Tree(QtGui.QTreeWidget):
def __init__(self, *args, **kwargs):
super(Tree, self).__init__()
comboStyle="QComboBox {background-color: #7A7A7A; border: 1px solid black;}"
self.setStyleSheet(comboStyle)
for each in ['Item_1','Item_2','Item_3','Item_4','Item_5']:
item=QtGui.QTreeWidgetItem([each])
self.addTopLevelItem(item)
combo1=QtGui.QComboBox()
combo2=QtGui.QComboBox()
self.setItemWidget(item, 1, combo1)
self.setItemWidget(item, 2, combo2)
self.setColumnCount(5)
self.resize(360,240)
self.show()
需要注意的是,这样做可能会导致列宽发生变化,所以你可能需要使用一个叫 resizeColumnToContents()
的方法来调整列宽。