具有Qt只读模型并在不同线程中查看

时间:2019-06-11 09:28:05

标签: qt qthread qtableview qabstractitemmodel

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

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

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

但是令我困扰的是,由于我不得不将模型和表放在同一个GUI线程中,因此在每个字母之后输入字段也会被刷新,直到表被更新为止。我想这样做,以便我键入该短语而不会冻结效果,然后等待表更新。仅当按下Enter键输入整个短语时才通知模型对我来说不是一个选项-我需要textChanged()信号才能工作。

那么我想-如果我忽略文档并将模型放到非GUI线程中,对Qt会有很大的冒犯吗?令我惊讶的是,它起作用了!现在键入不会冻结,并且程序也不会崩溃(至少目前是这样)。

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

1 个答案:

答案 0 :(得分:0)

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

同步(相同线程)

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

异步(不同线程)

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

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

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

(*)或至少遇到了data()实现的安全性,但是还有其他诸如QPersistentModelIndex这样的东西是您无法控制的...