qt GUI线程和其他线程的信号槽以及不同线程通信

Qt所有的对于GUI的操作只能在一个GUI线程中执行,也就是return QApp::exec的线程。


一般main里面这样写。那么所有的GUI的操作只能在main主线程中执行。

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

WidgetUi w;
w.show();

return a.exec();
}

执行a.exec()程序进入消息循环。开始处理消息


如果打算CreateThread,把ui的指针传过去 在thread里面操作UI。是不行的

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

WidgetUi w;
w.show();

       CreateThread(thread_proc,&w);

return a.exec();
}

thread_proc(void* arg)

{

      ui=(WidgetUi *)arg;

     ui->textedit.settext(xxx);

}

在thread_proc中的ui的确是有效的指针。但是这么操作ui。容易崩溃并且不一定达到想要的效果。

1可能崩溃的原因是 没有加锁同步操作某个数据。比如主GUI线程正在读取一个list。此时另一个非gui线程删除了同一个list当中的某项。就崩溃了。

所有GUI操作只在一个线程内进行。这样就不用加考虑锁,思路简单清晰。一旦加锁。各种难以理解的问题就来了。

老师在批改作业。数了一下一共20本。老师说小明你的作业有问题,先拿下去修改。小明拿走一本了作业。

老师知道还剩19本。这是同一线程操作

如果小明自己回忆作业有问题,没告诉老师。而是直接拿走了。老师数来数去少了一本,老师就迷糊了。


2达不到预期的效果。

比如非gui线程用settext设置了 text。但是界面上可能不会显示。

因为你的线程修改了text的内容,但是没有通知GUI线程,所以GUI线程不会画出来,直到他下次处理某些事件的时候才会一并刷新。

老师还在改作业,别的同学告诉老师作业做好了。老师说你放到。我一个个改。通知一个就改一个。小明没告诉老师,

而是直接把作业放到那一堆本子里。老师不知道,所以没改。直到另一个同学说交作业了。老师才批改。才发现小明的也在这里。然后才一起批改了



其他线程和GUI线程通信。

如果想在createThread的线程里面通知UI进行操作怎么办。通过信号和槽实现。

如果要用信号和槽。那么必须继承QObject 必须在类里面

所以可以定义一个信号发射类。

class Msg:public QObject

   Q_OBJECT

 public:

  void sendsig(int arg)

  {

      emit sig(arg);

  };

signals:

 void sig(int arg);

}

connect(sig(),someslot());

Qt5以后signals变成public了。可以直接调用emit

Qt4是protected。不能直接调用。要写个public函数调用。


在外部定义一个 Msg  msgsender

这样在 thread_proc里面

{

     msgsender.sendsig(arg);

}

这样是可以的。



特别注意。这样的信号发射类一般只能做发射。不能接受信号。

因为如果要能发送和接受的都可以。这个QObject必须存在于一个生存的线程中。并且这个线程拥有事件循环。

也就是qt说的线程亲和性

http://doc.qt.io/qt-5/qobject.html#thread-affinity

如果QObject的-thread返回0或者生存在一个没有事件循环的线程当中。那么这个Qobject无法接受队列信号。和post过来的event

这个理解起来很简单。如果没有事件循环机制。线程去哪里取得投递到他队列里面的消息呢?

例如

thread_proc

{

      p=new QObject

      while(1)

     {

    sleep(100);       

     }

}

只要外部投递的是队列形式的信号。p的相关联的槽都不会被执行。因为线程一直在死循环。根本没机会从队列中取消息

但是通过指定DirectionConnection到p的槽是会执行的。只是并不运行在这个thread_proc的上下文当中。


如果想要这个线程可以接受槽。可以继承使用Qthread类。

在类的run方法里面调用this->exec。执行messageloop 。所以上面的写法可以改成

QSonThread::run()

{

       p=new QObject

     this->exec()

}









你可能感兴趣的:(qt GUI线程和其他线程的信号槽以及不同线程通信)