如何在QAbstractTableModel中设置数据

19

我需要使用Qt实现一个表格。

我认为我将使用QAbstractTableModel,使用这个模型的QTableView。

我理解我将需要编辑模型的rowCount(),columnCount()和data()函数。

然而,我不明白如何确切地设置数据到模型中,以便data()函数可以检索它。

setData()函数是为此目的提供的吗?我看到它将EditRole作为其参数,但我不想要它,因为我不想让我的表格可编辑。

那么,我该如何“设置”模型内的数据,或者让模型有数据可以使用data()函数获取?

另外,data()函数是如何被调用的,即由谁调用它,它需要在哪里被调用?

请帮我解决这个问题。

谢谢。

2个回答

28

实际数据在内存中的保留方式、从数据存储中生成或查询数据完全由您决定。如果是静态数据,您可以使用Qt容器类或自定义数据结构。

对于可编辑模型,您只需要重新实现setData()方法。

在不可编辑的QAbstractTableModel子类中,您需要实现4个方法:

  • int rowCount()
  • int columnCount()
  • QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole )
  • QVariant data(const QModelIndex & index, int role = Qt::DisplayRole)
这些方法通常从视图(通常为QTableView实例)中调用。前两个方法应该返回表的维度。例如,如果rowCount()返回10columnCount()返回4,则视图将调用data()方法40次(每个单元格一次),请求您模型内部数据结构中的实际数据。
例如,假设您在模型中实现了自定义槽retrieveDataFromMarsCuriosity()。此槽填充数据结构,并连接到QPushButton实例,因此您可以通过单击按钮获取新数据。 现在,您需要让视图知道数据何时被更改,以便它可以正确更新。这就是为什么您需要发出beginRemoveRows()endRemoveRows()beginInsertRows()endInsertRows()及其列对应项的信号。 Qt Documentation中有关于此的所有信息。

非常感谢您的及时帮助。我一定会仔细研究的。 - user1173240
@dschulz,第一次初始化时使用beginInsertRows()等是绝对必要的吗?然后我不理解dataChanged()的目的。为什么Qt不能只使用rowCount()、columnCount()和data()来检索信息?为什么需要使用beginInsertRows()等来创建行和列? - Cool_Coder
@Cool_Coder 是的,如果你重新实现了 insertRows() 方法,这是必需的。在向模型的数据容器(无论是 QList 还是其他容器类)添加项目之前,你必须调用 beginInsertRows()。需要注意的是,“数据已更改”并不一定意味着正在添加或删除行或列。dataChanged() 意味着模型中现有项目的数据已更新,因此视图可以检索到这些已更新的数据。只要想象一下当你在可编辑的 QTableView 单元格中更正你的名字时会发生什么。 - dschulz
但是等一下,我认为在模型初始化期间向模型的数据存储中插入项目时,并不一定需要严格调用beginInsertRows()endInsertRows(),特别是如果您尚未将模型附加到视图上。 - dschulz
已经花了两天时间,终于让它正常工作了!看起来如果我们不使用begin...()和end...(),模型就不会创建内部索引。因此我一直得到无效的模型索引。感谢您提供有关dataChanged()的信息。到目前为止,我发现Qt的帮助非常好,但是我觉得他们在模型/视图架构方面可以做得更好。对于新程序员来说,这很容易混淆... - Cool_Coder
dataChanged()函数适用于现有模型中任何类型的数据更改,即可能更改行数和列数,也可能更改现有行中的数据。我曾遇到这样的问题,新行被插入,但是dataChanged()信号可能没有传达相同的信息,因为在我的视图中没有插入新行,只有在行内更改了现有数据时,视图中的数据才会发生变化。 - user1173240

8

您不需要使用setData(...)。相反,您需要以这样的方式对QAbstractTableModel进行子类化,使其方法rowCount()columnCount()data(index)和可能的headerData(section, horizontalOrVertical)返回您希望显示的数据。以下是一个基于PyQt5的示例:

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

headers = ["Scientist name", "Birthdate", "Contribution"]
rows =    [("Newton", "1643-01-04", "Classical mechanics"),
           ("Einstein", "1879-03-14", "Relativity"),
           ("Darwin", "1809-02-12", "Evolution")]

class TableModel(QAbstractTableModel):
    def rowCount(self, parent):
        # How many rows are there?
        return len(rows)
    def columnCount(self, parent):
        # How many columns?
        return len(headers)
    def data(self, index, role):
        if role != Qt.DisplayRole:
            return QVariant()
        # What's the value of the cell at the given index?
        return rows[index.row()][index.column()]
    def headerData(self, section, orientation, role):
        if role != Qt.DisplayRole or orientation != Qt.Horizontal:
            return QVariant()
        # What's the header for the given column?
        return headers[section]

app = QApplication([])
model = TableModel()
view = QTableView()
view.setModel(model)
view.show()
app.exec_()

这是从GitHub存储库获取的,展示了以下表格:

QAbstractTableModel example


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接