在PySide QTreeWidget中设置行的背景

时间:2014-06-18 15:49:38

标签: python qt pyside qstyleditemdelegate

我从previous post的答案开始,但它似乎没有起作用。所有行都呈现相同的颜色。

我创建了一个主窗口类

import sys

from PySide import QtCore, QtGui

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        self.settingsTree = SettingsTree()
        self.setCentralWidget(self.settingsTree)

        self.locationDialog = None

        # self.autoRefreshAct.setChecked(True)
        # self.fallbacksAct.setChecked(True)

        self.setWindowTitle("Test")
        self.resize(500, 600)
        self.setTreeDataObject(ItemManifest())
        self.settingsTree.setItemDelegate(SelectionColorDelegate(self.settingsTree))

    def setTreeDataObject(self, treeData):
        self.settingsTree.setTreeDataObject(treeData)

        # self.refreshAct.setEnabled(True)
        # self.autoRefreshAct.setEnabled(True)

ItemManifest用于保存特定于列表项的数据(不确定这是Qt的做事方式)

class ItemManifest(QtCore.QObject):
    def __init__(self, parent=None):
        super(ItemManifest, self).__init__(parent)
        self.myList = [{'name': 'a', 'vid':'1', 'pid': '1'},
                       {'name': 'b', 'vid':'2', 'pid': '1'},
                       {'name': 'c', 'vid':'3', 'pid': '1'}]

这是我的实际树小部件,有三列:

class SettingsTree(QtGui.QTreeWidget):
    def __init__(self, parent=None):
        super(SettingsTree, self).__init__(parent)

        self.setHeaderLabels(("Name", "vid", "pid"))
        self.header().setResizeMode(0, QtGui.QHeaderView.Stretch)
        self.header().setResizeMode(2, QtGui.QHeaderView.Stretch)

        self.refreshTimer = QtCore.QTimer()
        self.refreshTimer.setInterval(2000)
        self.autoRefresh = False

        self.groupIcon = QtGui.QIcon()
        self.groupIcon.addPixmap(self.style().standardPixmap(QtGui.QStyle.SP_DirClosedIcon),
                QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.groupIcon.addPixmap(self.style().standardPixmap(QtGui.QStyle.SP_DirOpenIcon),
                QtGui.QIcon.Normal, QtGui.QIcon.On)
        self.keyIcon = QtGui.QIcon()
        self.keyIcon.addPixmap(self.style().standardPixmap(QtGui.QStyle.SP_FileIcon))

        self.refreshTimer.timeout.connect(self.refresh)

    def setTreeDataObject(self, treeData):
        self.treeData = treeData
        self.clear()

        if self.treeData is not None:
            self.treeData.setParent(self)
            self.refresh()
            if self.autoRefresh:
                self.refreshTimer.start()
        else:
            self.refreshTimer.stop()

    def sizeHint(self):
        return QtCore.QSize(800, 600)

    def setAutoRefresh(self, autoRefresh):
        self.autoRefresh = autoRefresh

        if self.treeData is not None:
            if self.autoRefresh:
                self.refresh()
                self.refreshTimer.start()
            else:
                self.refreshTimer.stop()

    def refresh(self):
        if self.treeData is None:
            return

        # The signal might not be connected.
        # try:
        #     self.itemChanged.disconnect(self.updateSetting)
        # except:
        #     pass

        self.updateChildItems(None)

        # self.itemChanged.connect(self.updateSetting)

    def event(self, event):
        if event.type() == QtCore.QEvent.WindowActivate:
            if self.isActiveWindow() and self.autoRefresh:
                self.refresh()

        return super(SettingsTree, self).event(event)

    '''on change to settings update tree'''
    def updateChildItems(self, parent):
        dividerIndex = 0

        for printer in self.treeData.myList:
            childIndex = self.findChild(parent, printer['name'], 0)
            if childIndex == -1 or childIndex >= dividerIndex:
                if childIndex != -1:
                    child = self.childAt(parent, childIndex)
                    for i in range(child.childCount()):
                        self.deleteItem(child, i)
                    self.moveItemForward(parent, childIndex, dividerIndex)
                else:
                    child = self.createItem(printer['name'], parent, dividerIndex)
                child.setIcon(0, self.keyIcon)
                dividerIndex += 1
            else:
                child = self.childAt(parent, childIndex)

            child.setText(1, printer['vid'])
            child.setText(2, printer['pid'])

    def createItem(self, text, parent, index):
        after = None

        if index != 0:
            after = self.childAt(parent, index - 1)

        if parent is not None:
            item = QtGui.QTreeWidgetItem(parent, after)
        else:
            item = QtGui.QTreeWidgetItem(self, after)

        item.setText(0, text)
        item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
        return item

    def deleteItem(self, parent, index):
        if parent is not None:
            item = parent.takeChild(index)
        else:
            item = self.takeTopLevelItem(index)
        del item

    def childAt(self, parent, index):
        if parent is not None:
            return parent.child(index)
        else:
            return self.topLevelItem(index)

    def childCount(self, parent):
        if parent is not None:
            return parent.childCount()
        else:
            return self.topLevelItemCount()

    def findChild(self, parent, text, startIndex):
        for i in range(self.childCount(parent)):
            if self.childAt(parent, i).text(0) == text:
                return i
        return -1

    def moveItemForward(self, parent, oldIndex, newIndex):
        for int in range(oldIndex - newIndex):
            self.deleteItem(parent, newIndex)

创建一个颜色委托,用于设置文本“a”为绿色

的行的背景颜色
class SelectionColorDelegate(QtGui.QStyledItemDelegate):
    def __init__(self, parent):
        super(SelectionColorDelegate, self).__init__(parent)

    def initStyleOption(self, option, index):
        # let the base class initStyleOption fill option with the default values
        super(SelectionColorDelegate,self).initStyleOption(option, index)
        # override what you need to change in option
        if index.data() == 'a':
            backColor = QtGui.QColor("green")
            option.palette.setColor(QtGui.QPalette.Base, backColor)
            option.backgroundBrush = backColor

让它发挥作用:

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

我设置背景颜色的尝试似乎都没有效果。

1 个答案:

答案 0 :(得分:4)

在进一步学习Qt之后,我重构了代码以使用模型/视图关系。该模型继承自QtCore.QAbstractItemModel,并按如下方式实现数据方法:

class MyTreeModel(QtCore.QAbstractItemModel):

    def data(self, index, role):
        if not index.isValid():
            return None

        item = index.internalPointer()

        if role == QtCore.Qt.BackgroundRole:
            if item.status.status == 'Not installed':
                return QtGui.QBrush(QtCore.Qt.lightGray)
            if item.status.head_test_failed:
                return QtGui.QBrush(QtCore.Qt.red)
            if item.status.status == 'failure':
                return QtGui.QBrush(QtCore.Qt.red)
            if item.status.status == 'running':
                return QtGui.QBrush(QtCore.Qt.green)
            return QtGui.QBrush(QtCore.Qt.transparent)

        if role != QtCore.Qt.DisplayRole:
            return None

        return item.data(index.column())

这样我就可以使用标准的TreeView(或任何其他视图)。 role == QtCore.Qt.BackgroundRole告诉模型这是格式化请求。