首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从线程向QObject发送信号

从线程向QObject发送信号
EN

Stack Overflow用户
提问于 2014-01-15 10:16:29
回答 2查看 2.3K关注 0票数 1

我会尽量说清楚的。我创建了一个Qt应用程序,它有一些按钮和一个QTextEdit。接下来,我创建了一个线程。并提供指向MainWindow的指针作为参数。就像这样:

代码语言:javascript
复制
MainWindow w;
pthread_create(&rThread,NULL,treat,&w);

处理是在创建线程时执行的函数。现在,如果我有一个名为pushButton的myButton,并且在myButton函数中做了一些类似的事情:

代码语言:javascript
复制
 void *treat(void *arg)
 {
  MainWindow *win = (MainWindow*)arg;
  win->ui->myButton->setEnabled(false);
  close(pthread_self());
 }

它会正常工作,我的应用程序中的myButton将被禁用。然而,如果我这样做:

代码语言:javascript
复制
 void *treat(void *arg)
 {
  MainWindow *win = (MainWindow*arg;
  win->ui->editText->setText("random string");
  close(pthread_self());
 }

我的应用程序会出现以下错误:

QObject:不能为处于不同线程中的父线程创建子线程。(父线程是QTextDocument(0x23af2e0),父线程是QThread(0x209a290),当前线程是QThread(0x7f7eec000af0)程序意外完成。

据我所知,Ui位于主线程中,并且可能无法在我创建的线程中访问,尽管我提供了指向该线程的主窗口指针。但是为什么禁用按钮是有效的呢?我很困惑。我之所以要使用QThread,是因为我们的老师告诉我不要这么做。我必须要用线程。我如何将这样的更改从线程应用到editText?我怎么能发送一个信号从一个线程到另一个线程,在Ui是“活的”。提前谢谢各位。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-01-15 13:58:25

一般来说,从object->thread()以外的线程调用任何object->thread()(或派生类)方法都是错误的--除非它们被设计和记录为线程安全。Qt本身中有一些方法被显式地记录为线程安全,例如QCoreApplication::postEvent

您所面临的行为是由于从非gui线程访问QWidget方法。它是未定义的行为,因此有些方法可能崩溃,有些方法不会崩溃,但即使它们没有崩溃,也仍然是无法依赖的未定义行为。据我们所知,这可能取决于月球的相位。

从另一个线程中做的唯一安全的事情就是向对象发送一个事件。当您在另一个线程中的对象上使用QMetaMethod::invokeQMetaObject::invokeMethod时,Qt将在内部向该对象发布一个QMetaCallEvent。由于posting事件是线程安全的(可以从其他线程执行),所以可以使用其他线程中的任何一个调用方法。QObject::event()通过执行适当的方法调用来响应这些事件。

因此,您可以从其他线程中做的唯一一件事是:

代码语言:javascript
复制
QMetaObject::invokeMethod(win->ui->editText, "setText", Q_ARG(QString, "random string"));

唉,这是个糟糕的设计,因为您正在向外部公开MainWindow的内部细节(比如ui指针)。相反,您应该在窗口上设置一个setEditText插槽:

代码语言:javascript
复制
MainWindow : public QWidget {
  ...
public:
  Q_SLOT void setEditText(const QString & str) {
    ui->editText->setText(str);
  }
  ...
};

然后,从另一个线程中,您可以:

代码语言:javascript
复制
QMetaObject::invokeMethod(win, "setEditText", Q_ARG(QString, "random string"));

我完全同意马立克R的建议,当你有QThread可用时,不要使用线程。

票数 3
EN

Stack Overflow用户

发布于 2014-01-15 10:37:05

首先,在没有必要的情况下混合库是坏习惯。Qt提供了QThread和非常方便的QtConcurrent

其次,这是糟糕的设计。创建一些QObject,它将处理线程中的计算,并在将结果传递给UI (主线程)时发出信号。然后创建连接,Qt将处理其余内容,使其线程安全(默认情况下,如果在线程之间传递信号,它将对连接进行队列连接)。

您的Qt并发代码:

代码语言:javascript
复制
void *treat(SomeClass *arg) {
    arg->doStuff();
}

QtConcurrent::run(treat, someObject);
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21134655

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档