QTableview,PySide2中单元格的背景颜色 [英] background color of cells in QTableview, PySide2

查看:211
本文介绍了QTableview,PySide2中单元格的背景颜色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以使用 PySide2 有条件地更改 QTableView 中项目的背景颜色?我已经阅读了很多关于 模型视图框架.我不知道是否有必要使用委托.最近,我能够在没有委托的情况下获得一列复选框.我相信虚拟方法 setItemData(index, roles)itemData(index) 可能是我需要的.但是,PySide2 中没有 QMap.我的模型必须需要某个地方来存储 QtCore.Qt.BackgroundRole 使用的额外信息(该枚举,顺便说一句,说用于使用默认委托呈现的项目的背景画笔")如果我不不指定委托,是否使用默认委托"?.我应该改用 QStandardItemModel 吗?在下面的示例代码中,如何根据某些阈值(最小和最大列是阈值?

Is it possible to conditionally change the background color of items in a QTableView, using PySide2? I've read a lot on the model view framework . I cannot figure out if it is necessary to use a Delegate or not. Recently I was able to get a column of checkboxes without a Delegate. I believe that the virtual methods setItemData(index, roles) and itemData(index) could be what I need. However, there is no QMap in PySide2. My model must need somewhere to store the extra information to be used by QtCore.Qt.BackgroundRole (that enum, btw, says "the background brush used for items rendered with the default delegate") If I don't specify a delegate, is the "default delegate" used?. Should I be using QStandardItemModel instead? In the example code below, how would I get a particular column's background color to be red based on some thresholds (the min and max column are the thresholds?

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_())

我有一个使用熊猫数据框的自定义模型:

And I have a custom model using a 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

推荐答案

如果可用,委托默认使用 BackgroundRole 信息,因此解决方案只是返回 QColor、QBrush 或类似信息.

The delegate by default uses the BackgroundRole information if it is available so the solution is just to return a QColor, QBrush or similar.

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")

这篇关于QTableview,PySide2中单元格的背景颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆