PyQt5 中 QAbstractTableModel 给定行号的特定 table 行的背景颜色
Background color a specific table row given row number for QAbstractTableModel in PyQt5
在 PyQt5 中,我使用模型视图来显示 table。该模型是 QAbstractTableModel,我想用第 0 行作为背景颜色。着色有效,但所有行都会着色,而不是我指定的行。此外,当我更改为 Qt.Background 角色时,我的单元格中出现了一些我不想要的 "tickbox"。我想,正是我对 QAbstractTableModel 的 def 数据部分中实际发生的事情的理解阻止了我达到预期的效果。
这是我已经尝试过的代码片段部分。请注意,在我的例子中,状态 1 和状态 2 实际上是 True 或 False。如果为真,则整行的背景颜色应为绿色,否则应保持白色。
#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 class 中,我在 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
就是这个"something more"不知道怎么解析成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() 方法的逻辑是过滤信息,在这种情况下,我将使用一个字典,同时考虑到您想要绘制完整的行,然后保存一个与所选行关联但与列关联的 QPersistentModel 0,最后 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
在 PyQt5 中,我使用模型视图来显示 table。该模型是 QAbstractTableModel,我想用第 0 行作为背景颜色。着色有效,但所有行都会着色,而不是我指定的行。此外,当我更改为 Qt.Background 角色时,我的单元格中出现了一些我不想要的 "tickbox"。我想,正是我对 QAbstractTableModel 的 def 数据部分中实际发生的事情的理解阻止了我达到预期的效果。
这是我已经尝试过的代码片段部分。请注意,在我的例子中,状态 1 和状态 2 实际上是 True 或 False。如果为真,则整行的背景颜色应为绿色,否则应保持白色。
#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 class 中,我在 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
就是这个"something more"不知道怎么解析成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() 方法的逻辑是过滤信息,在这种情况下,我将使用一个字典,同时考虑到您想要绘制完整的行,然后保存一个与所选行关联但与列关联的 QPersistentModel 0,最后 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