[英]PyQt5 : Change font color in one cell if row is selected (QAbstractTableModel)
[英]Background color a specific table row given row number for QAbstractTableModel in PyQt5
在PyQt5中,我使用模型视图来显示表格。 该模型是QAbstractTableModel,我想将背景色设为第0行。着色有效,但是所有行都变为有色,而不是我指定的行。 另外,当我更改为Qt.Background角色时,我的单元格中出现了一些不需要的“复选框”。 我猜想,这是我对QAbstractTableModel的def数据部分中实际发生的事情的理解,导致我无法达到预期的效果。
正如我已经尝试过的,这是我的代码片段部分。 请注意,在我的情况下,状态1和状态2实际上是True或False。 如果为True,则应将整个行的背景色设为绿色,否则应保持白色。
#Make some dummy data
tabledata = list()
tabledata.append(('item 1', 'amount 1', 'price 1', 'status 1'))
tabledata.append(('item 2', 'amount 2', 'price 2', 'status 2'))
#The self.model below is QAbstractTableModel subclassed
self.model.modelTableData = tabledata
#try set data for just one cell
self.model.setData(self.model.index(0,0), QtCore.Qt.BackgroundRole)
self.model.layoutChanged.emit()
然后在我的QAbstractTableModel类中,我在def数据中具有以下内容
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, parent, header, tabledata):
#inhert from QAbstractTableModel
QtCore.QAbstractTableModel.__init__(self, parent)
self.modelTableData = tabledata
self.header = header
def rowCount(self, parent):
return len(self.modelTableData)
def columnCount(self, parent):
return len(self.header)
def data(self, index, role):
if not index.isValid():
return None
if role == QtCore.Qt.BackgroundRole:
print('Qt.BackgroundRole at ' + str(index.row()))
return QtCore.QVariant(QtGui.QColor(QtCore.Qt.green))
print('Not Qt.BackgroundRole at ' + str(index.row()))
return self.modelTableData[index.row()][index.column()]
def headerData(self, col, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return self.header[col]
return None
我已经搜索了类似的示例并特别研究了这个示例https://python-forum.io/Thread-Change-color-of-a-row-of-a-QTableView
他们似乎要做的是
if role == QtCore.Qt.BackgroundRole and "something more":
#then do something
我不知道该如何解析为def数据方法。 理想情况下,应该是我的行数据状态1可以为True或False,但是我的理解是def数据部分实际上正在为查看器返回数据吗?
另外,我在代码中对此感到困惑,当我执行打印时,即使我在数据中声明仅将QModelIndex(0,0)的一个单元格设置为绿色,但下一行也设置为绿色。 这种行为的原因是什么?
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'main_v00.ui'
#
# Created by: PyQt5 UI code generator 5.9.2
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
import POSTools as tool
import json
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1680, 1050)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.cb_OrderList = QtWidgets.QComboBox(self.centralwidget)
self.cb_OrderList.setGeometry(QtCore.QRect(160, 30, 111, 31))
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(2)
sizePolicy.setHeightForWidth(self.cb_OrderList.sizePolicy().hasHeightForWidth())
self.cb_OrderList.setSizePolicy(sizePolicy)
self.cb_OrderList.setObjectName("cb_OrderList")
self.le_NewTable = QtWidgets.QLineEdit(self.centralwidget)
self.le_NewTable.setGeometry(QtCore.QRect(30, 30, 113, 35))
self.le_NewTable.setObjectName("le_NewTable")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(30, 10, 60, 16))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(14)
self.label.setFont(font)
self.label.setObjectName("label")
self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setGeometry(QtCore.QRect(170, 10, 60, 16))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(14)
self.label_2.setFont(font)
self.label_2.setObjectName("label_2")
self.le_ItemName = QtWidgets.QLineEdit(self.centralwidget)
self.le_ItemName.setGeometry(QtCore.QRect(30, 100, 171, 35))
self.le_ItemName.setObjectName("le_ItemName")
self.le_ItemAmount = QtWidgets.QLineEdit(self.centralwidget)
self.le_ItemAmount.setGeometry(QtCore.QRect(220, 100, 113, 35))
self.le_ItemAmount.setObjectName("le_ItemAmount")
self.le_UnitPrice = QtWidgets.QLineEdit(self.centralwidget)
self.le_UnitPrice.setGeometry(QtCore.QRect(350, 100, 113, 35))
self.le_UnitPrice.setObjectName("le_UnitPrice")
self.label_3 = QtWidgets.QLabel(self.centralwidget)
self.label_3.setGeometry(QtCore.QRect(30, 70, 101, 21))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(14)
self.label_3.setFont(font)
self.label_3.setObjectName("label_3")
self.label_4 = QtWidgets.QLabel(self.centralwidget)
self.label_4.setGeometry(QtCore.QRect(220, 70, 101, 21))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(14)
self.label_4.setFont(font)
self.label_4.setObjectName("label_4")
self.label_5 = QtWidgets.QLabel(self.centralwidget)
self.label_5.setGeometry(QtCore.QRect(350, 70, 101, 21))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(14)
self.label_5.setFont(font)
self.label_5.setObjectName("label_5")
self.label_6 = QtWidgets.QLabel(self.centralwidget)
self.label_6.setGeometry(QtCore.QRect(480, 70, 101, 21))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(14)
self.label_6.setFont(font)
self.label_6.setObjectName("label_6")
self.tableView = QtWidgets.QTableView(self.centralwidget)
self.tableView.setGeometry(QtCore.QRect(30, 150, 711, 461))
self.tableView.setObjectName("tableView")
self.pb_remove = QtWidgets.QPushButton(self.centralwidget)
self.pb_remove.setGeometry(QtCore.QRect(750, 250, 151, 101))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(18)
self.pb_remove.setFont(font)
self.pb_remove.setObjectName("pb_remove")
self.pb_receipt = QtWidgets.QPushButton(self.centralwidget)
self.pb_receipt.setGeometry(QtCore.QRect(590, 620, 151, 101))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(18)
self.pb_receipt.setFont(font)
self.pb_receipt.setObjectName("pb_receipt")
self.label_TotalPrice = QtWidgets.QLabel(self.centralwidget)
self.label_TotalPrice.setGeometry(QtCore.QRect(480, 100, 121, 35))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(18)
self.label_TotalPrice.setFont(font)
self.label_TotalPrice.setObjectName("label_TotalPrice")
self.le_Discount = QtWidgets.QLineEdit(self.centralwidget)
self.le_Discount.setGeometry(QtCore.QRect(610, 100, 131, 35))
self.le_Discount.setObjectName("le_Discount")
self.label_7 = QtWidgets.QLabel(self.centralwidget)
self.label_7.setGeometry(QtCore.QRect(610, 70, 101, 21))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(14)
self.label_7.setFont(font)
self.label_7.setObjectName("label_7")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(750, 150, 151, 101))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(18)
self.pushButton.setFont(font)
self.pushButton.setObjectName("pushButton")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1680, 22))
self.menubar.setObjectName("menubar")
self.menuMore_Options = QtWidgets.QMenu(self.menubar)
self.menuMore_Options.setObjectName("menuMore_Options")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.actionCount_Up = QtWidgets.QAction(MainWindow)
self.actionCount_Up.setObjectName("actionCount_Up")
self.menuMore_Options.addSeparator()
self.menuMore_Options.addAction(self.actionCount_Up)
self.menubar.addAction(self.menuMore_Options.menuAction())
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
MainWindow.setTabOrder(self.le_NewTable, self.cb_OrderList)
MainWindow.setTabOrder(self.cb_OrderList, self.le_ItemName)
MainWindow.setTabOrder(self.le_ItemName, self.le_ItemAmount)
MainWindow.setTabOrder(self.le_ItemAmount, self.le_UnitPrice)
MainWindow.setTabOrder(self.le_UnitPrice, self.le_Discount)
MainWindow.setTabOrder(self.le_Discount, self.pushButton)
MainWindow.setTabOrder(self.pushButton, self.pb_remove)
MainWindow.setTabOrder(self.pb_remove, self.pb_receipt)
MainWindow.setTabOrder(self.pb_receipt, self.tableView)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label.setText(_translate("MainWindow", "Order"))
self.label_2.setText(_translate("MainWindow", "Order List"))
self.label_3.setText(_translate("MainWindow", "Item Name"))
self.label_4.setText(_translate("MainWindow", "Item Amount"))
self.label_5.setText(_translate("MainWindow", "Unit Price"))
self.label_6.setText(_translate("MainWindow", "Price"))
self.pb_remove.setText(_translate("MainWindow", "Remove"))
self.pb_receipt.setText(_translate("MainWindow", "Receipt"))
self.label_TotalPrice.setText(_translate("MainWindow", "0"))
self.label_7.setText(_translate("MainWindow", "Discount [%]"))
self.pushButton.setText(_translate("MainWindow", "Print Kitchen"))
self.menuMore_Options.setTitle(_translate("MainWindow", "More Options"))
self.actionCount_Up.setText(_translate("MainWindow", "Count Up"))
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super(MainWindow,self).__init__()
self.setupUi(self)
#Start by reading in the menu items
self.URL_MenuDB = "somewhere"
self.path_OrderDB = "somewhere"
header, menudb = tool.load_MenuDB(self.URL_MenuDB)
self.MenuHeader = header
#Prepare the completer by first creating the model
self.completermodel = QtGui.QStandardItemModel()
for item in menudb:
row = list()
for col in item:
cell = QtGui.QStandardItem(str(col))
row.append(cell)
self.completermodel.appendRow(row)
self.completer = QtWidgets.QCompleter()
self.completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.completer.setCompletionColumn(0)
self.completer.setModel(self.completermodel)
self.completer.setFilterMode(QtCore.Qt.MatchContains)
self.completer.activated[QtCore.QModelIndex].connect(self.onActivated)
self.le_ItemName.setCompleter(self.completer)
#Setup model view
self.TableViewHeader = ['Item', 'Qty', 'Price', 'Print status']
self.TableData = list()
self.model = TableModel(self, header = self.TableViewHeader, tabledata = self.TableData)
self.model.layoutChanged.emit()
self.tableView.setModel(self.model)
#Upon program starts up, check if OrderDB.txt exists
status, AllTables = tool.importOrderDB(self.path_OrderDB)
if status is True: #OrderDB.txt exists
#check if there is incomplete orders
self.AllTables = AllTables
#A list of all active tables
tablenames = tool.getincompleteOrder(AllTables)
if tablenames:
#update the list of tablenames into drop down list
self.cb_OrderList.clear()
self.cb_OrderList.addItems(tablenames)
#get the index of the current active tablename
self.cb_OrderList.currentText()
#Define what happens when the user press enter og return for item amount
self.le_ItemAmount.returnPressed.connect(self.ItemAmountEnterKeyPress)
#If enter is pressed at unit price, it also connects with self.ItemAmountEnterKeyPress
self.le_UnitPrice.returnPressed.connect(self.ItemAmountEnterKeyPress)
#Define what happens when input table edit field is activated
self.le_NewTable.returnPressed.connect(self.input_newTable)
def input_newTable(self): #When the user create a new order
if not self.le_NewTable.text():
return
else:
#check if OrderDB already exists, if not one will be created. If exists is True, AllTables will be returned
status, AllTables, tablename, nameclash = tool.ExistOrderDB(self.path_OrderDB, self.le_NewTable.text().strip())
if nameclash is True:
tool.msgbox(self,'Bord navn eksisterer. Valg et nyt!')
self.le_NewTable.clear()
return
if status is False: #OrderDB.txt has just been created, and AllTables containing the tableName is returned
self.AllTables = AllTables
#Sort all the incomplete tables from All Tables and return the sorted tablename as pandas DataFrame
tablename = tool.getincompleteOrder(AllTables)
#insert the tablename as list to drop down list
self.cb_OrderList.clear()
self.cb_OrderList.addItems(tablename)
self.le_NewTable.clear()
else: #OrderDB.txt exists, continue to create the new table
#create the tabledict
tabledict = tool.CreateTableDict(self.le_NewTable.text())
self.AllTables.append(tabledict)
#save to data base
tool.saveOrderDB(self.path_OrderDB, self.AllTables)
tablename = tabledict["Name"]
#get a list of all incomplete order names
ordernames = tool.getincompleteOrder(self.AllTables)
self.cb_OrderList.clear()
self.cb_OrderList.addItems(ordernames)
index = self.cb_OrderList.findText(tablename, QtCore.Qt.MatchFixedString)
#set the drop down list to the current active index
self.cb_OrderList.setCurrentIndex(index)
#Set focus to item field
self.le_ItemName.setFocus()
self.le_NewTable.clear()
def ItemAmountEnterKeyPress(self): #insert the item into the table and update the data base behind the scene
if not self.cb_OrderList.currentText():
tool.msgbox(self, 'Select an order first')
return
else:
#Update the selected item into the AllTable
#Do a match to see if self.selected matches the fields
inputtext = self.le_ItemName.text()
if inputtext.strip() == self.selected[0]:
#the selected is the same as what appears in the field. Check the remaining fields
qty = tool.isfloat(self.le_ItemAmount.text())
price = tool.isfloat(self.le_UnitPrice.text())
if qty is not False and price is not False:
#submit the fields to be input into the modelview
index = tool.getTableDict(self)
#Do the visualization
price = [item for item in self.AllTables[index]["orderPrice"]]
totalprice = sum(price)
self.TableData = list(
zip(self.AllTables[index]['itemName'],
self.AllTables[index]['orderQty'],
price,
self.AllTables[index]['PrintStatus_send2kitchen']
))
#Update into the model
tabledata = list()
tabledata.append(('item 1', 'amount 1', 'price 1', 'status 1'))
tabledata.append(('item 2', 'amount 2', 'price 2', 'status 2'))
self.model.modelTableData = tabledata
#self.model.modelTableData = self.TableData
#try set data for just one cell
self.model.setData(self.model.index(0,0),
QtCore.Qt.BackgroundRole)
self.model.layoutChanged.emit()
#tool.plotTable(self, totalprice)
#clear
self.clearInputFields()
self.le_ItemName.setFocus()
else: #the item in the fields is different from self.selected, ask the user to try again
tool.msgbox(self, 'Item er ikke korrekt valgt, prøv igen.')
self.clearInputFields(self)
self.le_ItemName.setFocus()
return
else: #User has not selected from the list
tool.msgbox(self,'Prøv igen. Du skal vælge fra listen når du indsætter item')
self.clearInputFields(self)
self.le_ItemName.setFocus()
return
def clearInputFields(self):
self.le_ItemName.clear()
self.le_ItemAmount.clear()
self.le_UnitPrice.clear()
@QtCore.pyqtSlot(QtCore.QModelIndex)
def onActivated(self, index):
self.selected = list()
for i in range(0, len(self.MenuHeader) +1):
self.selected.append(index.sibling(index.row(),i).data())
#display the selected item in the editfield
self.le_UnitPrice.setText(self.selected[3])
#change focus to amount
self.le_ItemAmount.setFocus()
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, parent, header, tabledata):
#inhert from QAbstractTableModel
QtCore.QAbstractTableModel.__init__(self, parent)
self.modelTableData = tabledata
self.header = header
def rowCount(self, parent):
return len(self.modelTableData)
def columnCount(self, parent):
return len(self.header)
def data(self, index, role):
if not index.isValid():
return None
if role == QtCore.Qt.BackgroundRole:
return QtCore.QVariant(QtGui.QColor(QtCore.Qt.green))
return self.modelTableData[index.row()][index.column()]
def headerData(self, col, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return self.header[col]
return None
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
预期的结果是仅对指定的行进行着色。 此外,我假设与Qt.Background相关的每个单元格上的刻度线也被删除。
谢谢!
data()方法的逻辑是过滤信息,在这种情况下,我将使用字典,同时考虑到您希望绘制完整的行,然后保存与所选行关联但与列0关联的QPersistentModel,最后是该方法setData()默认情况下不执行任何操作,因此您必须重写。
指示该复选框的错误是因为您正在返回其他角色(例如Qt :: CheckStateRole)的文本,相反,您必须按照我已经指出的那样过滤信息
from PyQt5 import QtCore, QtGui, QtWidgets
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, parent, header, tabledata):
QtCore.QAbstractTableModel.__init__(self, parent)
self.modelTableData = tabledata
self.header = header
self.background_colors = dict()
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.modelTableData)
def columnCount(self, parent=QtCore.QModelIndex()):
return len(self.header)
def data(self, index, role):
if not index.isValid():
return None
if (
0 <= index.row() < self.rowCount()
and 0 <= index.column() < self.columnCount()
):
if role == QtCore.Qt.BackgroundRole:
ix = self.index(index.row(), 0)
pix = QtCore.QPersistentModelIndex(ix)
if pix in self.background_colors:
color = self.background_colors[pix]
return color
elif role == QtCore.Qt.DisplayRole:
return self.modelTableData[index.row()][index.column()]
def setData(self, index, value, role):
if not index.isValid():
return False
if (
0 <= index.row() < self.rowCount()
and 0 <= index.column() < self.columnCount()
):
if role == QtCore.Qt.BackgroundRole and index.isValid():
ix = self.index(index.row(), 0)
pix = QtCore.QPersistentModelIndex(ix)
self.background_colors[pix] = value
return True
return False
def headerData(self, col, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return self.header[col]
return None
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QTableView()
header = ["Item", "Qty", "Price", "Print status"]
tabledata = [
("item 1", "amount 1", "price 1", "status 1"),
("item 2", "amount 2", "price 2", "status 2"),
]
model = TableModel(None, header, tabledata)
model.setData(
model.index(0, 0), QtGui.QColor(QtCore.Qt.green), QtCore.Qt.BackgroundRole
)
w.setModel(model)
w.show()
sys.exit(app.exec_())
@eyllanesc非常感谢您给我另一个学习的机会。 意识到我需要过滤信息,这对我们有所帮助。 另外,我意识到我实际上不需要setData即可工作。 以下是我根据您的评论和示例重写代码的方式。 我只剩下一个问题,我在下面实现def数据的方式,这不会使代码变得非常昂贵,在某种意义上说,需要执行枚举器循环来识别每次def数据需要着色的行叫做?
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, parent, header, tabledata):
#inhert from QAbstractTableModel
QtCore.QAbstractTableModel.__init__(self, parent)
self.modelTableData = tabledata
self.header = header
def rowCount(self, parent):
return len(self.modelTableData)
def columnCount(self, parent):
return len(self.header)
def data(self, index, role):
if not index.isValid():
return None
if role == QtCore.Qt.CheckStateRole:
return None
#get rows to be colored
rowscolor = list()
for item in enumerate(self.modelTableData):
if item[1][-1] == False:
rowscolor.append(item[0])
if role == QtCore.Qt.BackgroundRole and index.row() in rowscolor:
return QtCore.QVariant(QtGui.QColor(QtCore.Qt.green))
return self.modelTableData[index.row()][index.column()]
def headerData(self, col, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return self.header[col]
return None
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.