我将从解释我的目标开始。包含多个产品的电子商务订单被加载到qtableview中。程序的用户将扫描产品的ean代码,如果ean代码存在于qtableview中,则该行应将颜色更改为绿色或黄色。如果一种产品的数量大于1,则颜色应变为黄色,直到扫描的产品数量等于订单中的数量为止。
总体目标是提供一种快速简便的方法来确保以正确的顺序放置正确的产品。
我找到了很多关于如何永久更改行颜色的答案,但没有找到如何根据用户输入和模型中的值更改颜色的答案。
答案 0 :(得分:0)
有以下几种选择:
QIdentityProxyModel
:必须覆盖数据方法,然后使用这些值计算颜色,如果颜色与预设不同,则将背景颜色设置为原始模型。
import sys
import random
from functools import partial
from PyQt5 import QtCore, QtGui, QtWidgets
def calculate_color(model, row):
max_value = int(model.index(row, 2).data())
current_value = int(model.index(row, 3).data())
if current_value == 0:
return QtGui.QBrush(QtCore.Qt.white)
elif max_value == current_value:
return QtGui.QBrush(QtCore.Qt.green)
else:
return QtGui.QBrush(QtCore.Qt.yellow)
class IdentityProxyModel(QtCore.QIdentityProxyModel):
def data(self, index, role=QtCore.Qt.DisplayRole):
if role == QtCore.Qt.DisplayRole and index.column() in (2, 3):
sm = self.sourceModel()
row = index.row()
color = calculate_color(sm, row)
if color is not None and color != index.data(QtCore.Qt.BackgroundRole):
for i in range(sm.columnCount()):
sm.setData(sm.index(row, i), color, QtCore.Qt.BackgroundRole)
return super(IdentityProxyModel, self).data(index, role)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.tableView = QtWidgets.QTableView()
self.setCentralWidget(self.tableView)
self.model = QtGui.QStandardItemModel()
self.model.setHorizontalHeaderLabels(["Prod Name", "EAN","Quanyity", "Counted"])
proxy = IdentityProxyModel(self)
proxy.setSourceModel(self.model)
self.tableView.setModel(proxy)
data = [["Prod1", "123456", 0, 0],
["Prod2", "234567", 0, 0],
["Prod3", "345678", 0, 0]]
for r, rowData in enumerate(data):
for c, d in enumerate(rowData):
it = QtGui.QStandardItem(str(d))
self.model.setItem(r, c, it)
# launch test
for i in range(self.model.rowCount()):
self.reset(i)
def reset(self, row):
max_value = random.randint(1, 10)
self.model.item(row, 2).setText(str(max_value))
self.model.item(row, 3).setText("0")
QtCore.QTimer.singleShot(1000, partial(self.start_test, row))
def start_test(self, row):
max_value = int(self.model.item(row, 2).text())
time_line = QtCore.QTimeLine(1000*max_value, self)
time_line.setFrameRange(0, max_value)
time_line.frameChanged.connect(partial(self.update_value, row))
# reset after 3 seconds of completion
time_line.finished.connect(lambda r=row: QtCore.QTimer.singleShot(3000, partial(self.reset, r)))
time_line.start()
def update_value(self, r, i):
model = self.tableView.model()
ix = model.index(r, 3)
model.setData(ix, str(i))
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
委托:您必须覆盖模型发生变化时调用的paint方法,并使用这些值计算颜色,如果颜色与预设不同,则将背景颜色设置为原始模型。
import sys
import random
from functools import partial
from PyQt5 import QtCore, QtGui, QtWidgets
def calculate_color(model, row):
max_value = int(model.index(row, 2).data())
current_value = int(model.index(row, 3).data())
if current_value == 0:
return QtGui.QBrush(QtCore.Qt.white)
elif max_value == current_value:
return QtGui.QBrush(QtCore.Qt.green)
else:
return QtGui.QBrush(QtCore.Qt.yellow)
class ColorDelegate(QtWidgets.QStyledItemDelegate):
def paint(self, painter, option, index):
if index.column() in (2, 3):
model = index.model()
r = index.row()
color = calculate_color(model, r)
if color != index.data(QtCore.Qt.BackgroundRole):
for i in range(model.columnCount()):
model.setData(model.index(r, i), color, QtCore.Qt.BackgroundRole)
super(ColorDelegate, self).paint(painter, option, index)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.tableView = QtWidgets.QTableView()
self.setCentralWidget(self.tableView)
self.model = QtGui.QStandardItemModel()
self.model.setHorizontalHeaderLabels(["Prod Name", "EAN","Quanyity", "Counted"])
self.tableView.setModel(self.model)
self.tableView.setItemDelegate(ColorDelegate(self))
data = [["Prod1", "123456", 0, 0],
["Prod2", "234567", 0, 0],
["Prod3", "345678", 0, 0]]
for r, rowData in enumerate(data):
for c, d in enumerate(rowData):
it = QtGui.QStandardItem(str(d))
self.model.setItem(r, c, it)
# launch test
for i in range(self.model.rowCount()):
self.reset(i)
def reset(self, row):
max_value = random.randint(1, 10)
self.model.item(row, 2).setText(str(max_value))
self.model.item(row, 3).setText("0")
QtCore.QTimer.singleShot(1000, partial(self.start_test, row))
def start_test(self, row):
max_value = int(self.model.item(row, 2).text())
time_line = QtCore.QTimeLine(1000*max_value, self)
time_line.setFrameRange(0, max_value)
time_line.frameChanged.connect(partial(self.update_value, row))
# reset after 3 seconds of completion
time_line.finished.connect(lambda r=row: QtCore.QTimer.singleShot(3000, partial(self.reset, r)))
time_line.start()
def update_value(self, r, i):
model = self.tableView.model()
ix = model.index(r, 3)
model.setData(ix, str(i))
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())