用于调用QListWidget时,QMetaObject :: invokeMethod()返回false :: addItem()

时间:2013-08-04 01:53:22

标签: c++ qt thread-safety

我试图通过使用QMetaObject :: invokeMethod()以线程安全的方式从后台线程向主线程拥有的QListWidget添加一个项目。

QMetaObject :: invokeMethod()在我使用它来调用QListWidget上的clear()时返回true,但当我用它来调用addItem()时返回false,如下面的代码所示:

void BlockingInvokeStringArg(QObject* widget, const char* functionName, const string& arg = "")
{
    QString argAsQString(arg.c_str());
    QGenericArgument genericArg = arg.empty() ? QGenericArgument() : Q_ARG(QString, argAsQString);
    if (!QMetaObject::invokeMethod(widget, functionName, Qt::BlockingQueuedConnection, genericArg))
    {
        throw runtime_error("QMetaObject::invokeMethod() returned false");
    }
}

void BacktestGui::on_buttonRunBacktest_clicked()
{
    auto runBacktest = [&]()
    {
        // Does not throw:
        BlockingInvokeStringArg(m_ui.listSymbols, "clear");
        // Throws:
        BlockingInvokeStringArg(m_ui.listSymbols, "addItem", "ItemName"); 
        // Does not throw but may be thread-unsafe due to a background thread interacting with a GUI component owned by the main thread:
        m_ui.listSymbols->addItem("ItemName");
    };
    QtConcurrent::run(runBacktest);
}

为什么QMetaObject :: invokeMethod()在QListWidget上调用clear()时返回true,但在调用addItem()时返回false?

如果QMetaObject :: invokeMethod()不能用于调用addItem(),你知道从后台线程向QListWidget添加项目的线程安全选择吗?

1 个答案:

答案 0 :(得分:3)

invokeMethod()能够调用信号或槽。 QListWidget :: clear()是一个插槽,因此可行。 QListWidget :: addItem()不是一个槽,因此你无法调用它。

解决方案很简单。编写一个插槽,将QListWidget作为参数,并在其上调用addItem(),并调用该插槽。