QTableview,PySide2中单元格的背景颜色

时间:2019-02-25 15:41:41

标签: python python-3.x pyside2

是否可以使用PySide2有条件地更改QTableView中项目的背景颜色? 我在model view framework上读了很多东西。我无法弄清楚是否有必要使用委托。最近,我能够获得没有代表的复选框列。我相信虚拟方法setItemData(index, roles)itemData(index)可能正是我所需要的。但是,PySide2中没有QMap。我的模型必须在某个地方存储QtCore.Qt.BackgroundRole使用的额外信息(该枚举btw表示“用于使用默认委托渲染的项目的背景笔刷”)如果我未指定委托,则为使用的“默认委托”?我应该改用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 个答案:

答案 0 :(得分:2)

默认情况下,委托使用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")