简体   繁体   English

TextEdit setPalette 上的 Qt InvokeMethod

[英]Qt InvokeMethod on TextEdit setPalette

Similar to C# I have used a working snippet such as:与 C# 类似,我使用了一个工作片段,例如:

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

... in order to change GUI elements not from the main thread. ...为了不从主线程更改 GUI 元素。 However, it does not appear to be working in the same way with setPalette for the textEdit.但是,它似乎与 textEdit 的 setPalette 以相同的方式工作。

With:和:

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

How does one go about to change the color of this gui element from another thread?如何从另一个线程更改此 gui 元素的颜色?

Edit1: I forgot to mention the output spits out: Edit1:我忘了提到输出吐出来的:

"QMetaObject::invokeMethod No such Method QTextEdit:setpalette(const QPalette&)" “QMetaObject::invokeMethod 没有这样的方法 QTextEdit:setpalette(const QPalette&)”

As per Qt Documentation, invokeMethod() invokes the member (a signal or a slot name) on the object.根据 Qt 文档, invokeMethod()调用对象上的成员(信号或槽名称)。
Since in the first case, setText() is a slot of QTextEdit and hence it works perfect.因为在第一种情况下, setText()QTextEdit一个插槽,因此它工作得很好。 However in the second case, setPalette() is neither a signal nor a slot and hence you get "QMetaObject::invokeMethod No such Method QTextEdit:setpalette(const QPalette&)" as output.但是,在第二种情况下, setPalette()既不是信号也不是槽,因此您会得到“QMetaObject::invokeMethod No such Method QTextEdit:setpalette(const QPalette&)”作为输出。
Moreover it returns false if there is no such member (a signal or a slot name) or the parameters did not match.此外,如果没有这样的成员(信号或插槽名称)或参数不匹配,则返回 false。

see here看这里

If you're using Qt 5.10 or later, you can call invokeMethod on any invokable, such as a lambda:如果您使用的是 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);

The OP used the QMetaObject::invokeMethod() which relies on registered slots (as they were usual in Qt4). OP 使用了QMetaObject::invokeMethod() ,它依赖于注册的插槽(就像在 Qt4 中一样)。 QTextEdit::setText() is such a slot but QTextEdit::setPalette() is not. QTextEdit::setText()是这样一个插槽,但QTextEdit::setPalette()不是。

Hence, the QTextEdit::setPalette() cannot be found at runtime by its name given as string.因此,在运行时无法通过以字符串形式给出的名称找到QTextEdit::setPalette()

With Qt5, the signal-slot concept was extended to support the connection of signals and slots with compile-time checking.在 Qt5 中,信号槽概念得到了扩展,以支持通过编译时检查连接信号和槽。

Out of curiosity, I had a look into the doc.出于好奇,我查看了文档。 and found QMetaObject::invokeMethod() which accepts a functor:并找到接受函子的QMetaObject::invokeMethod()

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

This is an overloaded function.这是一个过载功能。

Invokes the function in the event loop of context.在上下文的事件循环中调用函数。 function can be a functor or a pointer to a member function.函数可以是函子或指向成员函数的指针。 Returns true if the function could be invoked.如果可以调用该函数,则返回 true。 Returns false if there is no such function or the parameters did not match.如果没有这样的函数或参数不匹配,则返回 false。 The return value of the function call is placed in ret.函数调用的返回值放在 ret 中。

Note: This function is thread-safe.注意:这个函数是线程安全的。

This function was introduced in Qt 5.10.这个函数是在 Qt 5.10 中引入的。

Thereby, I would like to emphasize Note: This function is thread-safe.因此,我想强调一下这个函数是线程安全的。

So, I made an MCVE to check this out:所以,我做了一个 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;
}

Output:输出:

testQWidgetSetPaletteThreadSafe 的快照(动画)

Please, note that I (carefully) did every access to qTextEdit exclusively请注意,我(小心地)专门对qTextEdit进行了每次访问

  • either in the main thread无论是在主线程中
  • or inside the lambda which is passed to QMetaObject::invokeMethod() .或在传递给QMetaObject::invokeMethod()的 lambda 内部。

Qt widgets are by default not thread-safe. Qt 小部件默认不是线程安全的。 So, I have to ensure that the accesses to widgets happen in the GUI thread only (or had to be appropriately guarded).因此,我必须确保对小部件的访问仅发生在 GUI 线程中(或者必须得到适当的保护)。

The reference of qTextEdit is captured in the functor of threadPal . qTextEdit的引用被捕获在threadPal的函子中。 It is used to provide the address of qTextEdit to QMetaObject::invokeMethod() as context.它用于将qTextEdit的地址作为上下文提供给QMetaObject::invokeMethod() That's necessary to make QMetaObject::invokeMethod() aware that the provided functor has to be executed in a different thread (the GUI thread to which qTextEdit is associated to).这对于使QMetaObject::invokeMethod()知道提供的函子必须在不同的线程( qTextEdit关联到的 GUI 线程)中qTextEdit是必要的。 (In opposition to qTextEdit itself, the address of qTextEdit is immutable while the thread is running. Hence, an unguarded access is thread-safe.) (在反对qTextEdit本身的地址qTextEdit线程运行时是不变的。因此,一不留神访问是线程安全的。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM