QMetaObject::invokeMethod()在用于调用QListWidget::addItem()时返回fal

QMetaObject::invokeMethod() returning false when used to call QListWidget::addItem()

本文关键字:addItem 返回 fal QListWidget 用于 invokeMethod QMetaObject 调用      更新时间:2023-10-16

我正试图使用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);
}

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

如果QMetaObject::invokeMethod()不能用于调用addItem(),您知道从后台线程向QListWidget添加项的线程安全替代方案吗?

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

解决方案很简单。编写一个以QListWidget为参数并对其调用addItem()的插槽,并调用该插槽。