类似于C#,我使用了一个工作片段,如:
QString text = "Hello";
QMetaObject::invokeMethod(m_ui.textEdit_ConnectionStatus, "setText", Qt:QueuedConnection, Q_ARG(QString, text));..。为了改变GUI元素,而不是从主线程。但是,对于setPalette,它似乎没有以相同的方式为textEdit工作。
通过以下方式:
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 &)
发布于 2020-09-16 05:56:24
OP使用的是QMetaObject::invokeMethod(),它依赖于已注册的插槽(就像在Qt4中通常的那样)。QTextEdit::setText()是这样一个插槽,但QTextEdit::setPalette()不是。
因此,在运行时,不能以字符串的名称找到QTextEdit::setPalette()。
利用Qt5,扩展了信号时隙的概念,以支持信号与时隙的连接和编译时检查.
出于好奇,我去看了看医生。并找到接受函子的QMetaObject::invokeMethod():
模板< type type函子,type type bool QMetaObject::invokeMethod(QObject *上下文,函子函数,Qt::ConnectionType = Qt::AutoConnection,FunctorReturnType *ret = nullptr) 这是一个重载的函数。 调用上下文事件循环中的函数。函数可以是函子,也可以是指向成员函数的指针。如果可以调用函数,则返回true。如果没有这样的函数或参数不匹配,则返回false。函数调用的返回值放在ret中。 注意:这个函数是线程安全的. 这一功能是在Qt5.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的地址是不可变的。因此,无保护的访问是线程安全的。)
发布于 2020-09-15 16:02:39
根据Qt文档,invokeMethod()调用对象上的成员(信号或槽名)。
因为在第一种情况下,setText()是QTextEdit的一个插槽,因此它的工作非常完美。但是,在第二种情况下,setPalette()既不是信号也不是插槽,因此您得到了输出"QMetaObject::invokeMethod No the Method QTextEdit:setpalette(const &)“。
此外,如果没有这样的成员(信号或插槽名)或参数不匹配,则返回false。
发布于 2020-09-15 19:52:47
如果使用QT5.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);https://stackoverflow.com/questions/63904176
复制相似问题