繁体   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