3

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 にアイテムを追加するためのスレッドセーフな代替手段を知っていますか?

4

1 に答える 1

4

invokeMethod() は、シグナルまたはスロットを呼び出すことができます。QListWidget::clear() はスロットであるため、機能します。QListWidget::addItem() はスロットではないため、呼び出すことはできません。

解決策は簡単です。QListWidget を引数として受け取り、その上で addItem() を呼び出すスロットを作成し、そのスロットを呼び出します。

于 2013-08-04T02:22:24.780 に答える