簡體   English   中英

TextEdit setPalette 上的 Qt InvokeMethod

[英]Qt InvokeMethod on TextEdit setPalette

與 C# 類似,我使用了一個工作片段,例如:

QString text = "Hello";
QMetaObject::invokeMethod(m_ui.textEdit_ConnectionStatus, "setText", Qt:QueuedConnection, Q_ARG(QString, text));

...為了不從主線程更改 GUI 元素。 但是,它似乎與 textEdit 的 setPalette 以相同的方式工作。

和:

QPalette pal = palette();
pal.setColor(QPalette::Base, Qt:darkGreen);
QMetaObject::invokeMethod(m_ui.textEdit_ConnectionStatus, "setPalette", Qt:QueuedConnection, Q_ARG(const QPalette&, pal));

如何從另一個線程更改此 gui 元素的顏色?

Edit1:我忘了提到輸出吐出來的:

“QMetaObject::invokeMethod 沒有這樣的方法 QTextEdit:setpalette(const QPalette&)”

根據 Qt 文檔, invokeMethod()調用對象上的成員(信號或槽名稱)。
因為在第一種情況下, setText()QTextEdit一個插槽,因此它工作得很好。 但是,在第二種情況下, setPalette()既不是信號也不是槽,因此您會得到“QMetaObject::invokeMethod No such Method QTextEdit:setpalette(const QPalette&)”作為輸出。
此外,如果沒有這樣的成員(信號或插槽名稱)或參數不匹配,則返回 false。

看這里

如果您使用的是 Qt 5.10 或更高版本,則可以對任何可調用對象(例如 lambda)調用invokeMethod

QPalette pal = palette();
pal.setColor(QPalette::Base, Qt:darkGreen);

auto setPalette = [this, pal] { m_ui.textEdit_ConnectionStatus->setPalette(pal); };
QMetaObject::invokeMethod(m_ui.textEdit_ConnectionStatus, setPalette, Qt:QueuedConnection);

OP 使用了QMetaObject::invokeMethod() ,它依賴於注冊的插槽(就像在 Qt4 中一樣)。 QTextEdit::setText()是這樣一個插槽,但QTextEdit::setPalette()不是。

因此,在運行時無法通過以字符串形式給出的名稱找到QTextEdit::setPalette()

在 Qt5 中,信號槽概念得到了擴展,以支持通過編譯時檢查連接信號和槽。

出於好奇,我查看了文檔。 並找到接受函子的QMetaObject::invokeMethod()

template <typename Functor, typename FunctorReturnType> bool QMetaObject::invokeMethod(QObject *context, Functor function, Qt::ConnectionType type = Qt::AutoConnection, FunctorReturnType *ret = nullptr)

這是一個過載功能。

在上下文的事件循環中調用函數。 函數可以是函子或指向成員函數的指針。 如果可以調用該函數,則返回 true。 如果沒有這樣的函數或參數不匹配,則返回 false。 函數調用的返回值放在 ret 中。

注意:這個函數是線程安全的。

這個函數是在 Qt 5.10 中引入的。

因此,我想強調一下這個函數是線程安全的。

所以,我做了一個 MCVE 來檢查一下:

// standard C++ header:
#include <chrono>
#include <thread>

// Qt header:
#include <QtWidgets>

// main application
int main(int argc, char **argv)
{
  qDebug() << "Qt Version:" << QT_VERSION_STR;
  QApplication app(argc, argv);
  // setup GUI
  QTextEdit qTextEdit(QString(
    "<p>Hello world.</p>"
    "<p>Hello Qt.</p>"
    "<p>Hello Stack Overflow.</p>"));
  qTextEdit.show();
  // a separate thread to manipulate qTextEdit
  std::thread threadPal([&qTextEdit]() {
    using namespace std::chrono_literals;
    const QColor qColors[] = { Qt::red, Qt::green, Qt::blue, Qt::white };
    QColor qColor;
    for (const QColor &qColor_ : qColors) {
      std::this_thread::sleep_for(1s);
      qColor = qColor_;
      QMetaObject::invokeMethod(&qTextEdit, [&qTextEdit, qColor]() {
        QPalette qPal = qTextEdit.palette();
        qPal.setColor(QPalette::Base, qColor);
        qTextEdit.setPalette(qPal);
      });
    }
  });
  // runtime loop
  const int ret = app.exec();
  // done
  threadPal.join();
  return ret;
}

輸出:

testQWidgetSetPaletteThreadSafe 的快照(動畫)

請注意,我(小心地)專門對qTextEdit進行了每次訪問

  • 無論是在主線程中
  • 或在傳遞給QMetaObject::invokeMethod()的 lambda 內部。

Qt 小部件默認不是線程安全的。 因此,我必須確保對小部件的訪問僅發生在 GUI 線程中(或者必須得到適當的保護)。

qTextEdit的引用被捕獲在threadPal的函子中。 它用於將qTextEdit的地址作為上下文提供給QMetaObject::invokeMethod() 這對於使QMetaObject::invokeMethod()知道提供的函子必須在不同的線程( qTextEdit關聯到的 GUI 線程)中qTextEdit是必要的。 (在反對qTextEdit本身的地址qTextEdit線程運行時是不變的。因此,一不留神訪問是線程安全的。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM