QT中QThread的各个方法,UI线程关系,事件关系详解(4)

55 篇文章 27 订阅
37 篇文章 18 订阅

QT-多线程与界面之间交互总结

1. 线程与界面组件需要注意的地方

  • 在QThread子线程中不能直接创建QWidget之类的界面组件.
  • 因为在QT中,所有界面组件相关的操作都必须在主线程中(也就是GUI thread)
  • 所以, QThread线程不能直接操作界面组件.

2.QThread线程如何操作界面组件-方法1

  • 将多线程类对象封装为GUI界面类的类成员
  • 然后在子线程定义信号函数,通过信号槽机制,向界面组件emit发射信号,从而实现间接操作.

3.QThread线程如何操作界面组件-方法2

  • 使用QApplication::postEvent()实现向界面发送事件,从而能够封装一个自定义类

4.使用Invokes()函数来调用界面组件的信号槽-方法3

一般使用该函数(用来调用对方的私有信号或槽):

该函数的连接方式默认使用的是Qt::AutoConnection

  • 表示如果接收者和发送者在同一个线程,则自动使用Qt::DirectConnection类型。如果接收者和发送者不在一个线程,则自动使用Qt::QueuedConnection类型。

比如,当我们想调用一个obj下的compute(QString, int, double)槽函数时:

则只需要写入:

QMetaObject::invokeMethod(obj, "compute",
                            Q_ARG(QString, "sqrt"),                        
                            Q_ARG(int, 42),
                            Q_ARG(double, 9.7));

示例如下所示:

在Testtherd线程类里通过invokeMethod向父界面类的paintMsg槽函数发送信息

void Testtherd::run()
{
    int count=0;
    while(1)
    {
        QString str="请稍等,正在验证用户,登录中";
        for(int i =0;i<count;i++)
           str.append('.');                   //循环添加小数点
        count=(count+1)%7;
        QMetaObject::invokeMethod(this->parent(), "paintMsg",
                                            Q_ARG(QString, str));

        msleep(500);
    }
}

父界面类的paintMsg槽函数如下所示:

void loginwindow:: paintMsg(QString msg) {
this->LineHint->setText(msg);
}

运行效果如下:

 

/******************************

qt 线程更新UI界面

ui操作必须在主线程做的,分支线程只能发送消息给主线程进行引导操作

想在别的线程刷新UI,可以发送事件给UI线程,通知它更新。
或者在线程内的worker对象上定义一个信号,连接到Widget的update()上,然后你在合适的时候emit 你的信号即可。


在做QT编程的时候,有一点很重要的就是一个QT进程只能有一个UI线程,而且所有关于UI的操作只能在这个线程上进行。
  
一个例子,程序需要一个后台线程进行耗时操作,前台用一个Dialog显示进度,在Windows下面,可以让这个后台线程直接更改这个Dialog显示的进度,但在QT下,这样会产生无法预期的结果,正确的做法是让后台线程postEvent给UI线程,让UI线程去更新进度显示。
  
为什么QT有这样的限制而windows没有呢?
因为QT最初设计成可以可以编译成只支持单线程或者可以支持多线程,因为大多数工作一个线程就足够了。更关键的是,UI的操作最终是要操作于显存(或者系统内存),对于X系统而言,client和server的通讯需要socket,而这些都是资源,多个线程需要访问同一资源的时候,需要线程间同步。线程间同步是耗时的,QT设计之初不想消耗这样的效率,于是决定干脆只让一个线程做UI操作。Windows到底怎么让多个线程访问UI资源的,不大清楚细节,但是肯定要用进程间同步。QT发展到4.0beta,每个线程都可以有自己的event loop,但是还是保留了只有一个UI线程的设计。
  
实际上,只容许一个UI线程是一个好的系统设计,这样一方面提高了效率,另一方面也明显区分了worker和UI之间的逻辑。Java AWT一开始是多UI线程的设计,现在AWT逐渐被SWT取代,SWT采用的就是单UI线程的设计。不象SWT,QT并没有运行时强制检查当前线程,这样减少了冗余代码,但是也让一些在非UI线程上做UI操作的问题难以发现。
 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值