QTableview,PySide2中单元格的背景颜色
Posted
技术标签:
【中文标题】QTableview,PySide2中单元格的背景颜色【英文标题】:background color of cells in QTableview, PySide2 【发布时间】:2019-02-25 15:41:40 【问题描述】:是否可以使用 PySide2 有条件地更改 QTableView 中项目的背景颜色?
我在model view framework 上阅读了很多内容。我不知道是否有必要使用委托。最近,我能够在没有代表的情况下获得一列复选框。我相信虚拟方法setItemData(index, roles)
和itemData(index)
可能是我需要的。但是,PySide2 中没有QMap
。我的模型必须需要某个地方来存储QtCore.Qt.BackgroundRole
使用的额外信息(那个枚举,顺便说一句,说“用于使用默认委托渲染的项目的背景画笔”)如果我没有指定委托,是“默认委托”使用?我应该改用QStandardItemModel
吗?
在下面的示例代码中,如何根据某些阈值(最小和最大列是阈值?
from PySide2.QtWidgets import (QWidget, QApplication, QTableView,QVBoxLayout)
import sys
from PandasModel2 import PandasModel2
import numpy as np
import pandas as pd
class Example(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(300, 300, 700, 300)
self.setWindowTitle("QTableView")
self.initData()
self.initUI()
def initData(self):
data = pd.DataFrame(np.random.randint(1,10,size=(6,4)), columns=['Test#','MIN', 'MAX','MEASURED'])
data['Test#'] = [1,2,3,4,5,6]
#add the checkable column to the DataFrame
data['Check'] = True
self.model = PandasModel2(data)
def initUI(self):
self.tv = QTableView(self)
self.tv.setModel(self.model)
vbox = QVBoxLayout()
vbox.addWidget(self.tv)
self.setLayout(vbox)
app = QApplication([])
ex = Example()
ex.show()
sys.exit(app.exec_())
我有一个使用 pandas dataFrame 的自定义模型:
import PySide2.QtCore as QtCore
class PandasModel2(QtCore.QAbstractTableModel):
"""
Class to populate a table view with a pandas dataframe.
This model is non-hierachical.
"""
def __init__(self, data, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent)
self._data = data
def rowCount(self, parent=None):
return self._data.shape[0]
def columnCount(self, parent=None):
return self._data.shape[1]
def data(self, index, role=QtCore.Qt.DisplayRole):
if role==QtCore.Qt.DisplayRole:
if index.column() != 4:
#don't want what determines check state to be shown as a string
if index.isValid():
if index.column() in [1,2,3]:
return ':.3f'.format(self._data.iloc[index.row(), index.column()])
if index.column() == 0:
return ':.2f'.format(self._data.iloc[index.row(), index.column()])
return str(self._data.iloc[index.row(), index.column()])
if role==QtCore.Qt.CheckStateRole:
if index.column()==4:#had to add this check to get the check boxes only in column 10
if self._data.iloc[index.row(), index.column()] == True:
return QtCore.Qt.Checked
else:
return QtCore.Qt.Unchecked
def getMinimum(self, row):
return self._data.iloc[row, self.getColumnNumber('MIN')]
def getMaximum(self, row):
return self._data.iloc[row, self.getColumnNumber('MAX')]
def getColumnNumber(self, string):
'''
Given a string that identifies a label/column,
return the location of that label/column.
This enables the config file columns to be moved around.
'''
return self._data.columns.get_loc(string)
def headerData(self, col, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return self._data.columns[col]
return None
def flags(self, index):
'''
The returned enums indicate which columns are editable, selectable,
checkable, etc.
The index is a QModelIndex.
'''
if index.column() == self.getColumnNumber('Check'):
#print(index.column())
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsUserCheckable
else:
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable
return QtCore.Qt.ItemIsEnabled
def setData(self, index, value, role=QtCore.Qt.DisplayRole):
"""Set the value to the index position depending on Qt::ItemDataRole and data type of the column
Args:
index (QtCore.QModelIndex): Index to define column and row.
value (object): new value.
role (Qt::ItemDataRole): Use this role to specify what you want to do.
Raises:
TypeError: If the value could not be converted to a known datatype.
Returns:
True if value is changed. Calls layoutChanged after update.
False if value is not different from original value.
"""
if not index.isValid():
return False
if role == QtCore.Qt.DisplayRole: #why not edit role?
self._data.iat[index.row(),index.column()]= value
self.layoutChanged.emit()
return True
elif role == (QtCore.Qt.CheckStateRole | QtCore.Qt.DisplayRole):
#this block does get executed when toggling the check boxes,
#verified with debugger. Although the action is the same
#as the block above!
self._data.iat[index.row(),index.column()]= value
self.layoutChanged.emit()
return True
else:
return False
【问题讨论】:
【参考方案1】:默认情况下,委托使用 BackgroundRole 信息(如果可用),因此解决方案只是返回 QColor、QBrush 或类似的。
from PySide2 import QtCore, QtGui
class PandasModel2(QtCore.QAbstractTableModel):
# ...
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid():
return
if not (0 <= index.row() < self.rowCount() and 0 <= index.column() <= self.columnCount()):
return
value = self._data.iloc[index.row(), index.column()]
if role == QtCore.Qt.DisplayRole:
if index.column() != 4:
if index.column() in [1,2,3]:
return ':.3f'.format(value)
if index.column() == 0:
return ':.2f'.format(value)
return str(value)
elif role == QtCore.Qt.CheckStateRole:
if index.column() == 4:
return QtCore.Qt.Checked if value else QtCore.Qt.Unchecked
elif index.column() == self.getColumnNumber('MEASURED'):
if role == QtCore.Qt.BackgroundRole:
if self.getMinimum(index.row()) <= value <= self.getMaximum(index.row()):
return QtGui.QColor("red")
【讨论】:
@ErikIverson 如果我的回答对您有帮助,请不要忘记将其标记为正确,如果您不知道该怎么做,请查看tour。 我确实将其标记为已接受。我只有 25 业力点,所以可能不会被其他人接受。 抱歉耽搁了@eyllanesc,我终于注意到了复选标记以上是关于QTableview,PySide2中单元格的背景颜色的主要内容,如果未能解决你的问题,请参考以下文章
更改值后使用代理模型更改 QTableView 的单元格的背景颜色
如何在 QTableView 中发出输入单元格和离开单元格的信号
如何在 QTableview 单元格的值更新后及时为它的颜色设置动画?