更改PySide6中QAbstractTableModel的模型索引背景



我想改变我的表中特定索引的背景颜色,但只能在特定任务完成后。

我知道我可以使用Background角色来更改Table模型中的颜色,但是我希望根据外部因素而不是基于表本身的更改来更改背景颜色。例如,下面的代码显示了一个基本的QTableView示例,在QWidget中显示了6行。在主应用程序中,我可以使用setData更改特定索引的文本,如下所示。

model.setData(model.index(2, 0), "Task Complete")

下面是完整的代码:

import sys
from PySide6.QtWidgets import (
QApplication, QWidget, QTableView, QVBoxLayout
)
from PySide6.QtCore import Qt, QAbstractTableModel
from PySide6.QtGui import QBrush

class TableModel(QAbstractTableModel):
def __init__(self, data):
super().__init__()
self._data = data
def data(self, index, role=Qt.DisplayRole):
# display data
if role == Qt.DisplayRole:
try:
return self._data[index.row()][index.column()]
except IndexError:
return ''
def setData(self, index, value, role=Qt.EditRole):
if role in (Qt.DisplayRole, Qt.EditRole):
# if value is blank
if not value:
return False
self._data[index.row()][index.column()] = value
self.dataChanged.emit(index, index)
return True
def rowCount(self, index):
return len(self._data)
def columnCount(self, index):
return len(self._data[0])

def flags(self, index):
return super().flags(index) | Qt.ItemIsEditable

class MainApp(QWidget):
def __init__(self):
super().__init__()
self.window_width, self.window_height = 200, 250
self.setMinimumSize(self.window_width, self.window_height)
self.layout = {}
self.layout['main'] = QVBoxLayout()
self.setLayout(self.layout['main'])
self.table = QTableView()
self.layout['main'].addWidget(self.table)
model = TableModel(data)
self.table.setModel(model)
# THIS IS WHERE THE QUESTION IS
model.setData(model.index(2, 0), "Task Complete") # Change background color instead of text
model.setData(model.index(5, 0), "Task Complete") # Change background color instead of text
if __name__ == '__main__':
data = [
["Task 1"],
["Task 2"],
["Task 3"],
["Task 4"],
["Task 5"],
["Task 6"],
]
app = QApplication(sys.argv)
myApp = MainApp()
myApp.show()
try:
sys.exit(app.exec())
except SystemExit:
print('Closing Window...')

我试图改变setData函数使用Qt.BackgroundRole而不是Qt.EditRole,但这并不适用于改变颜色。结果是代码运行了,但是什么也没发生。

我希望能够根据我选择的特定索引用任何颜色填充背景。但是,我希望这些代码驻留在MainApp类中,而不是在TableModel类中。

建议尝试

为data()添加代码

if role == Qt.BackgroundRole:
return QBrush(Qt.green)

改变setData ()

def setData(self, index, value, role=Qt.BackgroundRole):
if role in (Qt.DisplayRole, Qt.BackgroundRole):
# if value is blank
if not value:
return False
self._data[index.row()][index.column()] = value
self.dataChanged.emit(index, index)
return True

在MainApp中也更改了setData

model.setData(model.index(5, 0), QBrush(Qt.green))

这导致以绿色突出显示整个表,而不是特定索引。

如果要为每个索引设置不同的颜色,则必须将颜色信息存储在另一个数据结构中,并返回相应的索引值。

data()setData()必须根据角色访问不同的值(参见关于项目角色的文档),这意味着您必须而不是使用self._data不分青红皂白的任何角色。如果在与文本相同的数据结构中为行/列设置颜色,则文本将丢失。

一个简单的解决方案是创建一个列表的列表,这些列表具有与源数据相同的大小,使用None作为默认值。

class TableModel(QAbstractTableModel):
def __init__(self, data):
super().__init__()
self._data = data
rows = len(data)
cols = len(data[0])
self._backgrounds = [[None] * cols for _ in range(rows)]
def data(self, index, role=Qt.DisplayRole):
if not index.isValid():
return
elif role in (Qt.DisplayRole, Qt.EditRole):
return self._data[index.row()][index.column()]
elif role == Qt.BackgroundRole:
return self._backgrounds[index.row()][index.column()]
def setData(self, index, value, role=Qt.EditRole):
if (
not index.isValid() 
or index.row() >= len(self._data)
or index.column() >= len(self._data[0])
):
return False
if role == Qt.EditRole:
self._data[index.row()][index.column()] = value
elif role == Qt.BackgroundRole:
self._backgrounds[index.row()][index.column()] = value
else:
return False
self.dataChanged.emit(index, index, [role])
return True

注意:您应该始终确保data至少有一行,否则columnCount()将引发异常

然后,要更新颜色,还必须使用适当的角色:

model.setData(model.index(5, 0), QBrush(Qt.green), Qt.BackgroundRole)

注意,如果您不需要保持数据结构的完整性(只包含显示的值),一个常见的解决方案是使用字典。

您可以使用以角色为键,数据结构为值的普通字典:

class TableModel(QAbstractTableModel):
def __init__(self, data):
super().__init__()
rows = len(data)
cols = len(data[0])
self._data = {
Qt.DisplayRole: data,
Qt.BackgroundRole: [[None] * cols for _ in range(rows)]
}
# implement the other functions accordingly

否则,使用单个结构,为每个项使用唯一的字典:

class TableModel(QAbstractTableModel):
def __init__(self, data):
super().__init__()
self._data = []
for rowData in data:
self._data.append([
{Qt.DisplayRole: item} for item in rowData
])
def data(self, index, role=Qt.DisplayRole):
if not index.isValid():
return
data = self._data[index.row()][index.column()]
if role == Qt.EditRole:
role = Qt.DisplayRole
return data.get(role)
def setData(self, index, value, role=Qt.EditRole):
if (
not index.isValid() 
or role not in (Qt.EditRole, Qt.BackgroundRole)
):
return False
self._data[index.row()][index.column()][role] = value
self.dataChanged.emit(index, index, [role])
return True

最新更新