传递QModelIndex交叉线程排队连接

时间:2011-07-11 19:32:48

标签: qt threadpool signals-slots qmodelindex

WMIQuery::wmiquery(WMI::WMITable* table, const QString& query, WMI::ProgressIndicator* progressIndicator)

这是功能签名。我通过QtConcurrent::run

来呼叫它
QFuture<quint32> future = QtConcurrent::run(WMI::WMIQuery::wmiquery, _table, query);

架构非常简单。 将知道查询将返回的预期行数。 并行运行查询并在每个记录上获取一行添加到table: WMI::WMITable* WMI::WMITable是一个简单的QObject表数据结构。 它会在添加行时发出rowsAboutToBeInserted(QModelIndex, int, int)rowsInserted(QModelIndex, int, int)

另一方面,ProgressIndicator在主线程上实例化,table传递给其ctor。它会从WMI::WMIQuery::wmiquery()ProgressIndicator::setRecordCount(quint64 count)获得预期的总行数。 它有一个插槽rowAdded(),通过做一些简单的数学运算可以发出100的进度。在它的连接器中连接

connect(_table, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowAdded()));

我的想法。如同WMI::WMIQuery::wmiquery()我在另一个线程上运行(在QThreadPool上),这个连接是一个跨线程排队的连接。我是对的吗?

我在运行时收到以下错误

  

QObject :: connect:无法对“QModelIndex”类型的参数进行排队   (确保使用qRegisterMetaType()注册'QModelIndex'。)

我该怎么办?由于我的SLOT(rowAdded())不需要SIGNAL(rowsInserted(QModelIndex,int,int))的3个参数,我应该发出rowInserted()之类的其他信号,并在我发出rowsInserted(QModelIndex,int,int)时发出它并使用此SIGNAL而不是这个结合

您可能会问为什么我在表格数据结构中使用像rowsInserted(QModelIndex,int,int)这样的信号模型。因为我也有一个连接到这个表的模型。它也将逐行更新。但是我认为在这方面这是更加明确的。

2 个答案:

答案 0 :(得分:2)

在使用非平凡的参数类型(如QModelIndex)跨线程边界发出信号之前,必须先调用它:

qRegisterMetaType<QModelIndex>("QModelIndex");

准备Qt能够在线程边界发出信号。

通常情况下,您会在main()或仅运行一次的地方执行此操作,在调用emit之前,但在之后 QApplication已被实例化。

这仅适用于非平凡的类型。例如,像这样的信号要求您拨打qRegisterMetaType()

signals:
   void mySignal(int foo, int bar);

但像这样的信号需要qRegisterMetaType()

signals:
   void mySignal(QModelIndex);

有关详细信息,请参阅此处的Qt文档:http://doc.qt.nokia.com/latest/qmetatype.html#qRegisterMetaType

答案 1 :(得分:2)

我知道这已经很晚了,但我想确定有人提到它:QModelIndex并不意味着排队,原因与以后其他方式无意存储和使用有关。也就是说,如果在使用QModelIndex之前模型发生更改,您将获得未定义的行为。如果您需要具有模型索引的排队事件,则应该使用QPersistentModelIndex。与原始问题不太相关,但可能对在此居住的人有用。