如何彻底改变 QAbstractTableModel 的底层数据?

Posted

技术标签:

【中文标题】如何彻底改变 QAbstractTableModel 的底层数据?【英文标题】:How to change underlying data of QAbstractTableModel completely? 【发布时间】:2016-05-13 18:31:05 【问题描述】:

这是我在这里的第一篇文章,但是自从我开始编程以来,我得到了你们所有人的很多帮助。

我是 Qt 新手,目前正在尝试制作我的第一个项目。我的问题是关于模型、底层数据和视图之间的通信。

我首先将后台内容(数据存储等)与 GUI 分开。 现在我有一个模板类Matrix,我写了一个模板类MatrixModel,它继承自QAbstractTableModel。这工作正常,意味着我可以在视图和模型数据中编辑表格和刷新值。

现在我的问题是:如何在不编写新方法的情况下更改模型中的数据?

主窗口.cpp:

matrix<int> m = 1,2,3,4,5,6,7,8,9;
MatrixModel<int>* model = new MatrixModel<int>(m);
QTableView* tableView = new QTableView;
tableView->setModel(model);

有什么方法可以调用m.transpose() 到模型的底层数据?如果我更改m 会怎样?它会影响模型的数据吗?我尝试了很多东西,但没有任何效果。一个“问题”是我不能使用标准的信号/槽语法,因为我正在使用模板类。

我最后一次尝试是在模型中创建一个更新类:

template<typename T>
void MatrixModel<T>::updateAll() 
    QModelIndex topLeft = index(0,0);
    QModelIndex bottomRight = index(rowCount()-1, columnCount()-1);
    emit dataChanged(topLeft, bottomRight);

我尝试将它与一个按钮和一个 lambda 函数连接起来:

connect(transposeButton, &QPushButton::clicked, [=,&m,&model]() 
m.transpose(); model->updateAll();
);

但是如果我按下按钮,那似乎会使我的程序崩溃。我真的很绝望xD希望你能帮助我。如果您需要更多信息,请询问^^

最好的问候

丹尼斯

编辑 1:好的,到目前为止,我发现(在您的帮助下 :)),我必须在模型中再次编写矩阵的函数(例如 transpose())并从那里发出数据更改(使用发出 dataChanged或 beginResetModel()...) 但我无法修改模型底层数据。如果我写

这在主窗口中:

connect(transposeButton, &QPushButton::clicked, [&model]() 
    model->transpose();
);

模型中的这个:

template<typename T>
void MatrixModel<T>::transpose() 
    m(0,0) = 5;

如果我按下按钮转置,我的程序就会崩溃。如果我评论该行

m(0,0) = 5;

出来,一切正常。

编辑 2: 可能是数据存储有问题,所以这里是我的复制构造函数和我的矩阵类的私有变量:

private:
std::vector <T> data;
size_t rows, columns;

//Copy constructor
template<typename T>
matrix<T>::matrix(const matrix<T>& other)
    : rows(other.rows), columns(other.columns) 
    data = other.data;

【问题讨论】:

如果您的模型尺寸发生变化,dataChanged() 信号是不够的。您应该在更改数据之前调用beginResetModel(),然后在完成后调用endResetModel()。 . . 因此,如果您的矩阵不是平方矩阵,则调用 transpose() 然后仅发出 dataChanged() 信号可能会导致崩溃并访问矩阵中的无效索引 好的,我明白了,但我可以从我的模型中调用它。但是我从我的 mainwindow.cpp 调用函数 m.transpose() ,我无法调用 beginResetModel (因为它受到保护)。而且我不想在我的矩阵模型中再次编写所有函数。 除此之外,我正在尝试使用方形来减少我必须注意的问题。但你猜一件事。如果我发出 layoutChanged 会发生什么?不是要重新排列维度吗? 【参考方案1】:

您应该将 matrix 变量作为模型中的私有成员,以便对 matrix 的所有编辑都应通过模型中的函数完成。这意味着您的模型将有一个公共的transpose 函数,该函数在您的matrix 数据上调用transpose,然后发出dataChanged() 信号。而且您不应该直接访问您的matrix,因为在模型不知情的情况下更改它不会提供您想要的。这样,在每次更改 matrix 变量后调用 updateAll 不是您的责任,因为您的模型进行了更改并相应地更新了自身。 . .

【讨论】:

好吧,只是这么想:P 所以我必须为我的模型重写函数。但是我读到我们不应该使用resetmodel,因为它会再次绘制所有内容。从左上到右下发射不是更好吗?除此之外,如果我尝试调用模型函数(即使是简单的函数,例如我 beginResetModel transpose endResetModel 的新转置函数。谢谢您的帮助:) 我发现,删除 beginResetModel() 和 endResetModel() 是可行的。所以在模型中编辑 m 是有效的。 如果你的模型的尺寸没有改变,发出 dataChanged() 就足够了,但是如果你的尺寸正在改变,你应该调用像beginRemoveRowbeginResetModel这样的函数,或者..然后@ 987654333@或endRemoveRow...改变数据结构后 对不起....不是我把它注释掉了 xD 也许连接语句有问题? 它只是崩溃了。如果我从连接 lambda 函数调用模型函数,似乎就是这种情况【参考方案2】:

我明白了……

connect(transposeButton, &QPushButton::clicked, [model]() 
    beginResetModel();
    m(0,0)=50;
    endResetModel();
);

works...模型已经是一个指针,所以我将相同的指针指向 lambda 函数。现在我只需要弄清楚我的转置功能有什么问题,因为这仍然无法正常工作,但是崩溃已经消失了:P 谢谢你的建议 :)

【讨论】:

以上是关于如何彻底改变 QAbstractTableModel 的底层数据?的主要内容,如果未能解决你的问题,请参考以下文章

区块链如何在2022年及以后彻底改变世界

linuxio_uring 和 eBPF 将如何彻底改变 Linux 中的编程

数字经济之父TED演讲:区块链将如何彻底改变我们的经济?(附视频&演讲稿)

听~英语数字经济之父TED演讲:区块链将如何彻底改变我们的经济?(附视频&演讲稿)

Cyber​​Vein 如何修改 DAG 以彻底改变去中心化数据库

Cyber​​Vein 如何修改 DAG 以彻底改变去中心化数据库