【问题标题】:QAbstractTabelModel.data() always getting index.row() == 0 and only shows 1 rowQAbstractTabelModel.data() 总是得到 index.row() == 0 并且只显示 1 行
【发布时间】:2018-10-04 00:04:32
【问题描述】:

我已经在 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)

【问题讨论】:

标签: python qtableview pyside2 qabstracttablemodel


【解决方案1】:

如果您不通知,模型无法监控数据何时被修改,在您的情况下,有两种类型的修改,第一种是行插入,另一种是更新。对于插入行,您必须使用beginInsertRows()endInsertRows() 方法,第二次您必须通过启动dataChanged 信号来通知。

另一方面,不要在类中使模型变量,您必须使其成为实例的变量。

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

【讨论】:

  • 我认为如果使用setData(),则需要调用dataChanged(),但在这里它非常有意义,基本上任何数据修改都必须调用它。
猜你喜欢
  • 2011-04-15
  • 2013-07-01
  • 1970-01-01
  • 2020-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多