QColorDialog 和 QItemDelegate

QColorDialog and QItemDelegate

我有一个 QTableView,我在其中使用 QItemDelegate 作为按钮。 我正在尝试更改按钮的颜色,所以当我单击它时,我调用了 QColorDialog。但是后来我无法将颜色发送回按钮。

目前进展情况如下:

按钮和 QColorDialog:

class ButtonDelegate(QItemDelegate):
    def __init__(self, parent):
        QItemDelegate.__init__(self, parent)

    def paint(self, painter, option, index):
        widget = QWidget()
        layout = QHBoxLayout()
        widget.setLayout(layout)
        btn = QPushButton('')
        btn.setStyleSheet("background-color:rgb(86,12,65)")
        ix = QPersistentModelIndex(index)
        btn.clicked.connect(lambda ix = ix : self.onClicked(ix))
        layout.addWidget(btn)
        layout.setContentsMargins(2,2,2,2)
        if not self.parent().indexWidget(index):
            self.parent().setIndexWidget(index, widget)

    def onClicked(self, ix):

        colorPicker = QColorDialog.getColor()
        #colorPicker.show()
        r = str(colorPicker.red())
        g = str(colorPicker.red())
        b = str(colorPicker.red())
        bgcolor = 'background-color:rgb(' + r + ',' + g + ',' + b +')'

下一步是什么?我尝试在委托 init 中将按钮声明为 self.btn = QPushButton(),然后在 onCLick 方法中重用它,但按钮甚至没有那样绘制。

有所启示?

谢谢!

编辑 1

型号:

class Model(QAbstractTableModel):

    def __init__(self, vtxTable, parent = None):
        QAbstractTableModel.__init__(self, parent)
        #data
        self.groups = []
        #header
        self.header_labels = ['Color', 'Group', 'Done']
        self.vtxTable = vtxTable


    def rowCount(self, parent):
        return len(self.groups)

    def columnCount(self, parent):
        return 3

    def flags(self, index):

        if index.column() == 2: 
            fl = fl = Qt.ItemIsEnabled | Qt.ItemIsSelectable
        else:
            fl = Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable
        return fl


    def headerData(self, section, orientation, role):
        if role == Qt.DisplayRole and orientation == Qt.Horizontal:
            return self.header_labels[section]

    def removeRow(self, row, parent = QModelIndex()):
        self.beginRemoveRows(parent, row, row)
        self.groups.remove(self.groups[row])
        self.endRemoveRows()
        self.vtxTable.setModel(QStringListModel())


    def insertRows(self, position, row, values = [] , parent = QModelIndex()):

        lastposition = self.rowCount(0)
        self.beginInsertRows(parent, lastposition, lastposition)
        self.groups.insert(lastposition, values)
        self.endInsertRows()

    def setData(self, index, value, role = Qt.EditRole):

        setIt = False
        value = value
        row = index.row()
        column = index.column()

        if role == Qt.EditRole:
            setIt = True

            if not len(value) == 0: 
                if value in self.getGrpNames():
                    warning("Group must have a unique name.")
                    setIt = False
                else:
                    setIt = True
            else:
                warning("New group must have a name.")
                setIt = False

        if role == Qt.BackgroundRole:
            setIt = True

        if setIt:
            self.groups[row][column] = value
            self.dataChanged.emit(row, column)

        return False

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

        row = index.row()
        column = index.column()

        if role == Qt.DisplayRole:
            if column == 0: 
                #value = [self.groups[row][column].redF(), self.groups[row][column].greenF(), self.groups[row][column].blueF()]
                value = self.groups[row][column]
            else:
                value = self.groups[row][column]
            return value

        elif role == Qt.TextAlignmentRole:
            return Qt.AlignCenter;

        elif role == Qt.EditRole: 
            index = index 
            return index.data()   

        elif role == Qt.BackgroundRole and column == 0:
            value = self.groups[row][column]


    def getGrpNames(self):
        rows = self.rowCount(1)
        grps = []
        for row in range(rows):
            grp = self.index(row, 1).data()
            grps.append(grp)

        return grps

    def getAllVtx(self):

        rows = self.rowCount(1)
        allVtxs = []
        for row in range(rows):
            index =  self.createIndex(row, 3)
            vtxs = index.data()
            for vtx in vtxs:
                allVtxs.append(vtx)
        return allVtxs

    def getData(self):
        rows = self.rowCount(1)
        data = {}
        for row in range(rows):
            color = self.index(row, 0).data()
            grp = self.index(row, 1).data()
            done = self.index(row, 2).data()
            vtxs = self.groups[row][3]
            #index = self.createIndex(row,0)
            data[grp] = [grp, color, done, vtxs]

        return data

    def queryVtx(self, vtx):

        data = self.getData()

        for key in data:
            vtxs = data[key][3]
            if vtx in vtxs:
                return data[key][0]

        else:
            return False

Table 查看:

class Table(QTableView):

    def __init__(self,  *args, **kwargs):
        QTableView.__init__(self, *args, **kwargs)

        self.setItemDelegateForColumn(0, colorDelegate(self))
        hHeader = self.horizontalHeader()
        #hHeader.setSectionResizeMode(QHeaderView.Fixed);
        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.setSelectionMode(QAbstractItemView.SingleSelection)
        vHeader = self.verticalHeader()
        vHeader.hide()

单击行的第一个单元格时,我希望能够为其选择一种颜色,并将其保存在模型中。

谢谢。

委托的目标是自定义显示在 QAbstractItemView 中的每个项目,另一种方法是使用 indexWidget 方法插入一个小部件。委托的优点是内存消耗最小。建议不要同时使用。

代表有以下方法:

  • paint():是负责绘制正常显示的item的方法
  • createEditor(): 是负责创建编辑器的方法。
  • setEditorData():获取模型的值并在编辑器中建立。
  • setModelData(): 将编辑器获取的数据保存到模型中

此类委托的示例如下:

from PySide2.QtWidgets import *
from PySide2.QtGui import *
from PySide2.QtCore import *


class Delegate(QStyledItemDelegate):
    def createEditor(self, parent, option, index):
        dialog = QColorDialog(parent)
        return dialog

    def setEditorData(self, editor, index):
        color = index.data(Qt.BackgroundRole)
        editor.setCurrentColor(color)

    def setModelData(self, editor, model, index):
        color = editor.currentColor()
        model.setData(index, color, Qt.BackgroundRole)


if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)

    model = QStandardItemModel(4, 4)
    for i in range(model.rowCount()):
        for j in range(model.columnCount()):
            color = QColor(qrand() % 256, qrand() % 256, qrand() % 256)
            it = QStandardItem("{}{}".format(i, j))
            it.setData(color, Qt.BackgroundRole)
            model.setItem(i, j, it)
    w = QTableView()
    w.setModel(model)
    w.setItemDelegate(Delegate())
    w.show()
    sys.exit(app.exec_())

更新:

我改进了你的代码,因为它有不必要的元素,主要错误是这些 Qt::BackgroundRole 必须 return 一个 QColor

from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *

import warnings

class Model(QAbstractTableModel):
    def __init__(self, parent = None):
        QAbstractTableModel.__init__(self, parent)
        #data
        self.groups = []
        #header
        self.header_labels = ['Color', 'Group', 'Done']


    def rowCount(self, parent=QModelIndex()):
        return len(self.groups)

    def columnCount(self, parent=QModelIndex()):
        return 3

    def flags(self, index):
        fl = Qt.ItemIsEnabled | Qt.ItemIsSelectable
        if not index.column() in (2, ):
            fl |= Qt.ItemIsEditable
        return fl


    def headerData(self, section, orientation, role):
        if role == Qt.DisplayRole and orientation == Qt.Horizontal:
            return self.header_labels[section]

    def removeRow(self, row, parent = QModelIndex()):
        self.beginRemoveRows(parent, row, row)
        self.groups.remove(self.groups[row])
        self.endRemoveRows()

    def insertRows(self, values = [], position=-1):
        if position == -1:
            position = self.rowCount()
        self.beginInsertRows(QModelIndex(), position, position)
        self.groups.insert(position, values)
        self.endInsertRows()

    def setData(self, index, value, role = Qt.EditRole):
        setIt = False
        row = index.row()
        column = index.column()
        if role == Qt.EditRole:
            setIt = True
            if len(value) != 0: 
                if value in self.getGrpNames():
                    warning("Group must have a unique name.")
                    setIt = False
                else:
                    setIt = True
            else:
                warning("New group must have a name.")
                setIt = False
        if role == Qt.BackgroundRole:
            setIt = True
        if setIt:
            self.groups[row][column] = value
            self.dataChanged.emit(index, index)

        return False

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

        row = index.row()
        column = index.column()

        value = None

        if role == Qt.DisplayRole:
            if column == 0:
                value = self.groups[row][column]
            else:
                value = self.groups[row][column]
        elif role == Qt.TextAlignmentRole:
            value = Qt.AlignCenter;  
        elif role == Qt.BackgroundRole and column == 0:
            value = QColor(self.groups[row][column])
        return value

    def getGrpNames(self):
        rows = self.rowCount(1)
        grps = []
        for row in range(rows):
            grp = self.index(row, 1).data()
            grps.append(grp)
        return grps

    def getAllVtx(self):
        rows = self.rowCount(1)
        allVtxs = []
        for row in range(rows):
            index =  self.createIndex(row, 3)
            vtxs = index.data()
            for vtx in vtxs:
                allVtxs.append(vtx)
        return allVtxs

    def getData(self):
        rows = self.rowCount(1)
        data = {}
        for row in range(rows):
            color = self.index(row, 0).data()
            grp = self.index(row, 1).data()
            done = self.index(row, 2).data()
            vtxs = self.groups[row][3]
            #index = self.createIndex(row,0)
            data[grp] = [grp, color, done, vtxs]
        return data

    def queryVtx(self, vtx):
        data = self.getData()
        for key in data:
            vtxs = data[key][3]
            if vtx in vtxs:
                return data[key][0]
        else:
            return False

class ColorDelegate(QStyledItemDelegate):
    def createEditor(self, parent, option, index):
        dialog = QColorDialog(parent)
        return dialog

    def setEditorData(self, editor, index):
        color = index.data(Qt.BackgroundRole)
        editor.setCurrentColor(color)

    def setModelData(self, editor, model, index):
        color = editor.currentColor()
        model.setData(index, color, Qt.BackgroundRole)

class Table(QTableView):
    def __init__(self,  *args, **kwargs):
        QTableView.__init__(self, *args, **kwargs)
        self.setItemDelegateForColumn(0, ColorDelegate(self))
        hHeader = self.horizontalHeader()
        #hHeader.setSectionResizeMode(QHeaderView.Fixed);
        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.setSelectionMode(QAbstractItemView.SingleSelection)
        vHeader = self.verticalHeader()
        vHeader.hide()


if __name__ == "__main__":
    import sys

    app = QApplication(sys.argv)
    w = Table()
    model = Model()
    w.setModel(model)
    model.insertRows(["red", "group1", "no"])
    model.insertRows(["blue", "group1", "no"], 0)
    w.show()
    sys.exit(app.exec_())