[英]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.