[英]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;
}
輸出:
請注意,我(小心地)專門對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.