QAbstractTabelModel.data() 总是得到 index.row() == 0 并且只显示 1 行
QAbstractTabelModel.data() always getting index.row() == 0 and only shows 1 row
我在 python 中定义了我的自定义 QAbstrtactTableModel
并实现了 columnCount()
、rowCount()
、data()
和 headerData()
,并且还添加了一个add()
个新条目的函数:
import sys
from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import QApplication, QMainWindow
from PySide2.QtCore import QFile, QProcess, Signal,\
Slot, QObject, QThread, Qt, QAbstractTableModel, QModelIndex,\
QTimer
import random
class TableModel(QAbstractTableModel):
def __init__(self, values):
QAbstractTableModel.__init__(self)
self.values = values
def columnCount(self, parent=QModelIndex()):
return 2
def rowCount(self, parent=QModelIndex()):
return len(self.values)
def data(self, index, role=Qt.DisplayRole):
print("called")
if 0 <= index.row() < self.rowCount() and 0 <= index.column() < self.columnCount():
if role == Qt.DisplayRole:
print(index.row())
if index.column() == 0:
return list(self.values.keys())[index.row()]
else:
return self.values[list(self.values.keys())[index.row()]]
def add(self, data):
self.values[data[0]] = data[1]
def headerData(self, section, orientation, role=Qt.DisplayRole):
if role == Qt.DisplayRole:
if orientation == Qt.Horizontal:
if section == 0:
return "Parking,Meter"
elif section == 1:
return "Revenue"
class Monitor(QObject):
data_batch_ready = Signal(list)
def __init__(self, parent=None):
super(Monitor, self).__init__(parent)
@Slot(list)
def fill_batch(self):
my_data = []
for parking in range(4):
for index in range(10):
my_data.append([str(parking)+","+str(index), random.randint(1,101)])
self.data_batch_ready.emit(my_data)
class Gui(QMainWindow):
system_process = QProcess()
parking_model = TableModel(values={"0,0": "0"})
def __init__(self, parent=None):
super(Gui, self).__init__(parent)
file = QFile("minimal.ui")
file.open(QFile.ReadOnly)
loader = QUiLoader()
ui = loader.load(file)
self.setCentralWidget(ui)
self.centralWidget().parking_table.setModel(self.parking_model)
@Slot(list)
def update_gui_revenue(self, data):
print("fire")
for row in data:
self.parking_model.add(row)
def main():
app = QApplication(sys.argv)
gui = Gui()
gui.show()
thread = QThread()
moni = Monitor()
timer = QTimer(moni)
timer.setInterval(1)
moni.moveToThread(thread)
moni.data_batch_ready.connect(gui.update_gui_revenue, Qt.QueuedConnection)
timer.timeout.connect(moni.fill_batch, Qt.QueuedConnection)
thread.started.connect(timer.start)
thread.started.connect(lambda: print("time started"))
thread.start()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
数据是一个 python 字典,正在通过调用一个随机函数来修改该字典,该函数每 1 秒用 1 个条目填充字典,如下所示:
"0,0":[随机值]
"0,1":[随机值]
"0,2":[随机值]
"1,0":[随机值]
"1,1":[随机值]
“1,2”:[随机值]
rowCount()
正确反映了数据 values
中的行数,但 tableView
始终只显示 1 行,而 data()
仅请求 index.row() == 0
编辑:添加了 timer.setInterval(1)
如果您不通知数据修改,模型将无法监控,在您的情况下,有两种类型的修改,第一种是行插入,另一种是更新。对于行的插入,您必须使用 beginInsertRows()
和 endInsertRows()
方法,对于第二个,您必须通过启动 dataChanged
信号来通知。
另一方面,不要将模型变量设为class,你必须将其设为实例变量。
import sys
from PySide2 import QtCore, QtWidgets, QtUiTools
import random
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, values={}, parent=None):
super(TableModel, self).__init__(parent)
self.values = values
def columnCount(self, parent=QtCore.QModelIndex()):
if parent.isValid(): return 0
return 2
def rowCount(self, parent=QtCore.QModelIndex()):
if parent.isValid(): return 0
return len(self.values)
def data(self, index, role=QtCore.Qt.DisplayRole):
if 0 <= index.row() < self.rowCount() and 0 <= index.column() < self.columnCount():
if role == QtCore.Qt.DisplayRole:
if index.column() == 0:
return list(self.values.keys())[index.row()]
else:
return self.values[list(self.values.keys())[index.row()]]
def add(self, data):
key, value = data
if key in self.values:
row = list(self.values.keys()).index(key)
self.values[key] = value
self.dataChanged.emit(self.index(row, 1), self.index(row, 1))
else:
self.add_row(key, value)
def add_row(self, key, value):
self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount())
self.values[key] = value
self.endInsertRows()
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
if section == 0:
return "Parking,Meter"
elif section == 1:
return "Revenue"
class Monitor(QtCore.QObject):
data_batch_ready = QtCore.Signal(list)
@QtCore.Slot(list)
def fill_batch(self):
my_data = []
for parking in range(4):
for index in range(10):
my_data.append([str(parking)+","+str(index), random.randint(1,101)])
self.data_batch_ready.emit(my_data)
class Gui(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(Gui, self).__init__(parent)
file =QtCore.QFile("minimal.ui")
file.open(QtCore.QFile.ReadOnly)
self.parking_model = TableModel(values={"0,0": "0"}, parent=self)
loader = QtUiTools.QUiLoader()
ui = loader.load(file)
self.setCentralWidget(ui)
self.centralWidget().parking_table.setModel(self.parking_model)
@QtCore.Slot(list)
def update_gui_revenue(self, data):
for row in data:
self.parking_model.add(row)
def main():
app = QtWidgets.QApplication(sys.argv)
gui = Gui()
gui.show()
thread = QtCore.QThread()
moni = Monitor()
timer = QtCore.QTimer(moni)
timer.setInterval(10)
moni.moveToThread(thread)
moni.data_batch_ready.connect(gui.update_gui_revenue, QtCore.Qt.QueuedConnection)
timer.timeout.connect(moni.fill_batch, QtCore.Qt.QueuedConnection)
thread.started.connect(timer.start)
thread.started.connect(lambda: print("time started"))
thread.start()
app.aboutToQuit.connect(thread.quit)
sys.exit(app.exec_())
if __name__ == "__main__":
main()
我在 python 中定义了我的自定义 QAbstrtactTableModel
并实现了 columnCount()
、rowCount()
、data()
和 headerData()
,并且还添加了一个add()
个新条目的函数:
import sys
from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import QApplication, QMainWindow
from PySide2.QtCore import QFile, QProcess, Signal,\
Slot, QObject, QThread, Qt, QAbstractTableModel, QModelIndex,\
QTimer
import random
class TableModel(QAbstractTableModel):
def __init__(self, values):
QAbstractTableModel.__init__(self)
self.values = values
def columnCount(self, parent=QModelIndex()):
return 2
def rowCount(self, parent=QModelIndex()):
return len(self.values)
def data(self, index, role=Qt.DisplayRole):
print("called")
if 0 <= index.row() < self.rowCount() and 0 <= index.column() < self.columnCount():
if role == Qt.DisplayRole:
print(index.row())
if index.column() == 0:
return list(self.values.keys())[index.row()]
else:
return self.values[list(self.values.keys())[index.row()]]
def add(self, data):
self.values[data[0]] = data[1]
def headerData(self, section, orientation, role=Qt.DisplayRole):
if role == Qt.DisplayRole:
if orientation == Qt.Horizontal:
if section == 0:
return "Parking,Meter"
elif section == 1:
return "Revenue"
class Monitor(QObject):
data_batch_ready = Signal(list)
def __init__(self, parent=None):
super(Monitor, self).__init__(parent)
@Slot(list)
def fill_batch(self):
my_data = []
for parking in range(4):
for index in range(10):
my_data.append([str(parking)+","+str(index), random.randint(1,101)])
self.data_batch_ready.emit(my_data)
class Gui(QMainWindow):
system_process = QProcess()
parking_model = TableModel(values={"0,0": "0"})
def __init__(self, parent=None):
super(Gui, self).__init__(parent)
file = QFile("minimal.ui")
file.open(QFile.ReadOnly)
loader = QUiLoader()
ui = loader.load(file)
self.setCentralWidget(ui)
self.centralWidget().parking_table.setModel(self.parking_model)
@Slot(list)
def update_gui_revenue(self, data):
print("fire")
for row in data:
self.parking_model.add(row)
def main():
app = QApplication(sys.argv)
gui = Gui()
gui.show()
thread = QThread()
moni = Monitor()
timer = QTimer(moni)
timer.setInterval(1)
moni.moveToThread(thread)
moni.data_batch_ready.connect(gui.update_gui_revenue, Qt.QueuedConnection)
timer.timeout.connect(moni.fill_batch, Qt.QueuedConnection)
thread.started.connect(timer.start)
thread.started.connect(lambda: print("time started"))
thread.start()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
数据是一个 python 字典,正在通过调用一个随机函数来修改该字典,该函数每 1 秒用 1 个条目填充字典,如下所示:
"0,0":[随机值]
"0,1":[随机值]
"0,2":[随机值]
"1,0":[随机值]
"1,1":[随机值]
“1,2”:[随机值]
rowCount()
正确反映了数据 values
中的行数,但 tableView
始终只显示 1 行,而 data()
仅请求 index.row() == 0
编辑:添加了 timer.setInterval(1)
如果您不通知数据修改,模型将无法监控,在您的情况下,有两种类型的修改,第一种是行插入,另一种是更新。对于行的插入,您必须使用 beginInsertRows()
和 endInsertRows()
方法,对于第二个,您必须通过启动 dataChanged
信号来通知。
另一方面,不要将模型变量设为class,你必须将其设为实例变量。
import sys
from PySide2 import QtCore, QtWidgets, QtUiTools
import random
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, values={}, parent=None):
super(TableModel, self).__init__(parent)
self.values = values
def columnCount(self, parent=QtCore.QModelIndex()):
if parent.isValid(): return 0
return 2
def rowCount(self, parent=QtCore.QModelIndex()):
if parent.isValid(): return 0
return len(self.values)
def data(self, index, role=QtCore.Qt.DisplayRole):
if 0 <= index.row() < self.rowCount() and 0 <= index.column() < self.columnCount():
if role == QtCore.Qt.DisplayRole:
if index.column() == 0:
return list(self.values.keys())[index.row()]
else:
return self.values[list(self.values.keys())[index.row()]]
def add(self, data):
key, value = data
if key in self.values:
row = list(self.values.keys()).index(key)
self.values[key] = value
self.dataChanged.emit(self.index(row, 1), self.index(row, 1))
else:
self.add_row(key, value)
def add_row(self, key, value):
self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount())
self.values[key] = value
self.endInsertRows()
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
if section == 0:
return "Parking,Meter"
elif section == 1:
return "Revenue"
class Monitor(QtCore.QObject):
data_batch_ready = QtCore.Signal(list)
@QtCore.Slot(list)
def fill_batch(self):
my_data = []
for parking in range(4):
for index in range(10):
my_data.append([str(parking)+","+str(index), random.randint(1,101)])
self.data_batch_ready.emit(my_data)
class Gui(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(Gui, self).__init__(parent)
file =QtCore.QFile("minimal.ui")
file.open(QtCore.QFile.ReadOnly)
self.parking_model = TableModel(values={"0,0": "0"}, parent=self)
loader = QtUiTools.QUiLoader()
ui = loader.load(file)
self.setCentralWidget(ui)
self.centralWidget().parking_table.setModel(self.parking_model)
@QtCore.Slot(list)
def update_gui_revenue(self, data):
for row in data:
self.parking_model.add(row)
def main():
app = QtWidgets.QApplication(sys.argv)
gui = Gui()
gui.show()
thread = QtCore.QThread()
moni = Monitor()
timer = QtCore.QTimer(moni)
timer.setInterval(10)
moni.moveToThread(thread)
moni.data_batch_ready.connect(gui.update_gui_revenue, QtCore.Qt.QueuedConnection)
timer.timeout.connect(moni.fill_batch, QtCore.Qt.QueuedConnection)
thread.started.connect(timer.start)
thread.started.connect(lambda: print("time started"))
thread.start()
app.aboutToQuit.connect(thread.quit)
sys.exit(app.exec_())
if __name__ == "__main__":
main()