正如我从Qt文档中了解到的那样,在Qt Model / View框架中,模型及其附加视图应位于同一(GUI)线程中。这可能会导致某些不良后果,如下所示。我已经将QAbstractTableModel
子类化并实现了所需的虚函数。在内部,该模型对具有大量记录的sqlite数据库进行查询,并通过重新实现的data()
函数将数据提供给附加视图。
现在,在GUI中有一个QTableView
,我将其附加到该模型。我还有一个QLineEdit
输入字段。在此字段中打印文本会发出textChanged()
信号,该信号连接到模型的(自定义)query()
插槽。这样,在输入字段中输入新字符应使用与键入的短语匹配的记录来更新表。
好吧,由于我的数据库很大,我不希望在键入另一个字母后立即进行表更新-更新会等待查询完成,这可能需要一两秒钟。
但是令我困扰的是,由于我不得不将模型和表放在同一个GUI线程中,因此在每个字母之后输入字段也会被刷新,直到表被更新为止。我想这样做,以便我键入该短语而不会冻结效果,然后等待表更新。仅当按下Enter键输入整个短语时才通知模型对我来说不是一个选项-我需要textChanged()
信号才能工作。
那么我想-如果我忽略文档并将模型放到非GUI线程中,对Qt会有很大的冒犯吗?令我惊讶的是,它起作用了!现在键入不会冻结,并且程序也不会崩溃(至少目前是这样)。
所以我的问题是-在非GUI线程中使用模型是否仍然不安全,并且我的程序可能在其他任何一天突然崩溃?我还应该提到我想以只读方式使用模型。如果需要更改模型基础数据,则不会使用视图/代理进行操作,只会向模型的线程发送适当的信号,所有更改都将在该线程内执行。
答案 0 :(得分:0)
想象一下删除最后一行的例子:
同步(相同线程)
emit beginRemoveRows(int r = last row)
endRemoveRows()
异步(不同线程)
emit beginRemoveRows(r)
endRemoveRows()
两个信号都在GUI线程的事件队列中。
如果GUI事件队列在beginRemoveRows()
之前 包含重绘事件,则视图将调用model->data(r)
,并且您的程序可能会崩溃*。
(*)或至少遇到了data()
实现的安全性,但是还有其他诸如QPersistentModelIndex
这样的东西是您无法控制的...