在不同的线程中具有Qt只读模型和视图



正如我从Qt文档中了解到的那样,在Qt模型/视图框架中,模型及其附加视图应该存在于同一个(GUI)线程中。这可能会导致一些不良影响,如下所示。我已经QAbstractTableModel子类化并实现了所需的虚函数。在内部,该模型对具有大量记录的sqlite数据库进行查询,并通过重新实现的data()函数向附加的视图提供相应的数据。

现在,在 GUI 中我有一个QTableView,我将其附加到该模型。我还有一个QLineEdit输入字段。在此字段中打印文本会发出textChanged()信号,该信号连接到模型的(自定义)query()槽。这样,在输入字段中键入新字符应使用与键入的短语匹配的记录更新表。

好吧,由于我的数据库很大,我不希望在键入另一个字母后立即更新表-更新等待查询完成,这可能需要一两秒钟。

但让我困扰的是,由于我必须在同一个 GUI 线程中拥有模型和表格,因此输入字段也会在每个字母之后出现,直到表格更新。我想让它能够在没有冻结效果的情况下键入短语,然后等待表格更新。仅当按 Enter 键入整个短语时才通知模型对我来说不是一个选择 - 我需要textChanged()信号才能工作。

所以后来我想 - 如果我忽略文档并将模型放入非 GUI 线程中,是否会对 Qt 造成很大的冒犯?令我惊讶的是,它奏效了!现在打字不会冻结,程序也不会崩溃(至少目前是这样)。

所以我的问题是 - 在非 GUI 线程中使用模型是否仍然不安全,我的程序可能会在其他任何一天突然崩溃?我还应该提到,我想以只读方式使用该模型。如果我需要更改模型底层的数据,我不会使用 view/delegates 来执行此操作,我只会向模型的线程发送适当的信号,所有更改都将在该线程内执行。

想象一下删除最后一行的示例:

同步(同线程)

  1. emit beginRemoveRows(int r = last row)
    • 视图反应并删除对 R 的引用
  2. 从模型中删除 R
  3. endRemoveRows()
    • 视图知道它可能会重新粉刷

异步(不同的线程)

  1. emit beginRemoveRows(r)
  2. 从模型中删除 R
  3. endRemoveRows()

这两个信号都在 GUI 线程的事件队列中。

如果 GUI 事件队列在beginRemoveRows()之前包含重绘事件,则视图将调用model->data(r)并且程序可能会崩溃*。

(*) 或者至少遇到了data()实现的安全性,但引擎盖下还有其他事情,比如QPersistentModelIndex你无法控制......

相关内容

  • 没有找到相关文章

最新更新