- 浏览: 3446548 次
- 性别:
- 来自: 苏州
文章分类
最新评论
-
sonichy:
Qt5改动很多,要改改了。
基于QItemDelegate的例子1 SpinBoxDelegate -
我的主页6:
楼主,2.2子查询的分页方式:SELECT * FROM ar ...
Mysql 分页语句Limit用法 -
liguoqi:
非常感谢楼主的用心指导,工具以及图片例子都提供了 赞!
两款免费DCIOM 图像浏览软件介绍和DICOM图像例子供下载 -
liguoqi:
问下这个图片怎么解压损坏呀
两款免费DCIOM 图像浏览软件介绍和DICOM图像例子供下载 -
liguoqi:
楼主讲解的非常详细,还附带工具和图片例子,非常感谢
两款免费DCIOM 图像浏览软件介绍和DICOM图像例子供下载
原文链接:http://hi.baidu.com/cyclone/blog/item/65f3f603294f2e783812bb51.html
注意:请优先考虑Qt 线程基础(QThread、QtConcurrent等)
dbzhang800 2011.06.18
本文主要内容:
在任务一中,用 四 种方式实现:点击界面按钮,开线程运行一段程序,结果显示在一个Label上。
1. 用不正确的方式得到看似正确的结果
2. 用Qt Manual 和 例子中使用的方法
3. 用一种好用但被Qt开发人员批判的方法
4. 用一种被开发人员强烈推荐,但Qt Manual和例子中只字未提的方法
-
为了简单起见,本文只讲如何做及其结果是什么,而不讲其原因是什么(估计大家对原因也不会感兴趣,详见: QThread 使用探讨 和 QThread使用方法)。
- 本文只考虑两个线程(即主线程和一个次线程)的情况。
QWidget
- QWidget及其派生类均 不能在次线程中使用或创建
Manual 中的原话:
- The GUI classes, notably QWidget and all its subclasses, are not reentrant. They can only be used from the main thread.
- 因为不允许,所以尝试这么做的,几乎很快都能回头。毕竟signals和slots用起来确实蛮方便
- 但是,回头后,就理解和用对 QThread 了么?
QThread
概念一:QThread 对象本身所依附的线程 和它管理的线程不是同一个线程。
- 前者是主线程
- 后者是次线程
概念二:你在QThread派生类中定义的槽是在主线程而不是在次线程中执行的。
- run 函数是线程的入口点,run内的代码才是在次线程中运行的代码
概念三:除了Manual和Qt例子中给出的用法外,QThread有一种更容易且被推荐的使用方法:
- QThread 应该被看做是操作系统线程的接口或控制点,而不应该包含需要在新线程中运行的代码
- 需要运行的代码应该放到一个QObject的子类中,然后将该子类的对象moveToThread到新线程中。
关于本文的例子
- 为了代码简单,所有例子都是单一的源文件,保存为 main.cpp
-
你从代码中包含的 #include“main.moc”应该能看出
-
-
为了省几行代码,头文件都是直接包含 QtCore 和 QtGui。
- 为了清楚告诉大家槽函数分别是在那个线程运行的,调用了几处 currentThreadId 函数
-
main 函数中输出主线程IDqDebug()<<"main: "<<QThread::currentThreadId();
-
run 函数中输出次线程IDqDebug()<<"thread: "<<currentThreadId();
-
槽函数中输出其在哪个线程中执行qDebug()<<"slots1: "<<currentThreadId();
-
-
因为用了qDebug,所以你的pro文件内最好加上 CONFIG+=console
- 同样为了省代码,例子中未考虑线程如何正常结束的问题。
任务一
点击界面按钮,开线程运行一段程序,结果显示在一个Label上。
- 定义一个Widget,上面放置 QPushButton 和 QLabel
- 定义一个Thread,执行我们的代码,然后通知 Widget
第一次尝试
很容易想到方法,代码可以工作,结果正确。但 ... 未必和你想得一样
- Thread 中定义一个slot1函数,接受数据,计算其立方,然后将结果通过信号发出
- Widget 中按钮每点击一次,发出的数据加1,用label接受Thread的信号
#include <QtCore> #include <QtGui> class Thread:public QThread { Q_OBJECT public: Thread(){} public slots: void slot1(int v) { qDebug()<<"slots1: "<<currentThreadId(); emit sig1(QString::number(v*v*v)); } signals: void sig1(const QString& t); protected: void run() { qDebug()<<"thread: "<<currentThreadId(); exec(); } }; class Widget:public QWidget { Q_OBJECT public: Widget():m_label(new QLabel), m_button(new QPushButton("Button")), m_thread(new Thread) { QVBoxLayout * vbox = new QVBoxLayout(this); vbox->addWidget(m_label); vbox->addWidget(m_button); setLayout(vbox); connect(m_button,SIGNAL(clicked()),this,SLOT(onButtonClicked())); connect(this,SIGNAL(clicked(int)),m_thread,SLOT(slot1(int))); connect(m_thread,SIGNAL(sig1(QString)),m_label,SLOT(setText(QString))); m_thread->start(); } signals: void clicked(int v); private slots: void onButtonClicked() { static int v = 0; emit clicked(v); v++; } private: QLabel * m_label; QPushButton * m_button; Thread * m_thread; }; #include "main.moc" int main(int argc, char** argv) { QApplication app(argc, argv); qDebug()<<"main: "<<QThread::currentThreadId(); Widget w; w.show(); return app.exec(); }
一切工作正常,但看看控制台输出呢?
main: 3055777552 thread: 3024481136 slots1: 3055777552 slots1: 3055777552 slots1: 3055777552 ...
这儿明确告诉你,slot1 是在主线程中执行的。
尝试二
我们试试 Qt Manual和 Qt 例子中采用的解决方案。
槽函数不是在主线程运行么,而run函数不是次线程么?那么我们就:
- 在槽函数中做个标记
- 在run函数中根据标记进行运行
这样以来,尽管槽函数在仍在主线程,但费时的计算代码都在次线程了。
对Thread的类的改造如下(程序其他部分和 尝试一 完全一样):
class Thread:public QThread { Q_OBJECT public: Thread(){} public slots: void slot1(int v) { qDebug()<<"slots1: "<<currentThreadId(); m_mutex.lock(); m_vals.enqueue(v); m_mutex.unlock(); } signals: void sig1(const QString& t); protected: void run() { qDebug()<<"thread: "<<currentThreadId(); while(1) { m_mutex.lock(); if (!m_vals.isEmpty()){ int v = m_vals.dequeue(); emit sig1(QString::number(v*v*v)); } m_mutex.unlock(); } } private: QQueue<int> m_vals; QMutex m_mutex; };
注意哦,因为 slot 函数在主线程中,而run函数在次线程中,所以二者需要 QMutex 实现对变量的安全访问。如果你认真看过Qt自带的例子,会发现它始终强调 QMutex 的使用。
尝试三
尝试二是"正统"的做法,但如过你用Google搜索过。那么你可能不会选择尝试二,而是会使用下面的方法(其他部分和尝试一 完全一样)
class Thread:public QThread { Q_OBJECT public: Thread(){ moveToThread(this); } ...
这样以来,slot函数确实是在次线程工作的,看看控制台输出
main: 3056785168 thread: 3024444272 slots1: 3024444272 slots1: 3024444272 ...
很有意思?不是么,一条 moveToThread(this),移动到自己。然后问题解决了。
- 因为前面说了,QThread 所依附线程 和 它管理的线程不是同一个。
- 这样,其实将自己所依附的线程改为自己所管理的线程了。
o(∩∩)o...哈哈,不要太高兴哦,这个方法看起来比较舒服,但是它是被官方人员强烈批判的用法
尝试四
终于到我想写的代码了,这是Qt线程的开发者建议的使用方式,但很可惜。直到目前(Qt4.7.0),手册和例子中对此都只字为提。
- 我们不子类话QThread了,我们只需要子类话一个QObject,然后将其move到QThread就行了,看代码:
- 不用子类化QThrad了,我们只需要子类话一个 QObject,需要在次线程中工作的代码,直接放到它的槽中
class Worker:public QObject { Q_OBJECT public: Worker(){} public slots: void slot1(int v) { qDebug()<<"slots1: "<<QThread::currentThreadId(); emit sig1(QString::number(v*v*v)); } signals: void sig1(const QString& t); };
- 因为没有Thread类了,只有Worker类,Widget代码需做点改动
class Widget:public QWidget { Q_OBJECT public: Widget():m_label(new QLabel), m_button(new QPushButton("Button")), m_worker(new Worker) { QVBoxLayout * vbox = new QVBoxLayout(this); vbox->addWidget(m_label); vbox->addWidget(m_button); setLayout(vbox); QThread * thread = new QThread(this); m_worker->moveToThread(thread); connect(m_button,SIGNAL(clicked()),this,SLOT(onButtonClicked())); connect(this,SIGNAL(clicked(int)),m_worker,SLOT(slot1(int))); connect(m_worker,SIGNAL(sig1(QString)),m_label,SLOT(setText(QString))); thread->start(); } signals: void clicked(int v); private slots: void onButtonClicked() { static int v = 0; emit clicked(v); v++; } private: QLabel * m_label; QPushButton * m_button; Worker * m_worker; };
main 函数还是和尝试一完全一样
控制台输出结果如下
main: 3056961296 slots1: 3024616304 slots1: 3024616304 ....
一共两个线程,且二者id不同,说明slot在次线程中
恩。这篇文字似乎又不短了,看来任务二要另起一篇了。
- -- dbzhang800 于 20101023
发表评论
-
Qt官网变更【2012】
2012-09-21 19:30 4215Qt最近被Digia完全收购,诺基亚这两年的不理不睬,没有魄力 ... -
【转】QT实现不规则窗体
2012-09-21 18:50 4994看到好文章,收藏一下: 看到网上有很多不规则窗体的实现 ... -
Qt应用程序如何使用DCMTK类库进行二次开发DICOM数据传输
2012-09-13 09:35 0参考文章: 1、Using DCMTK with ... -
【转】将QT开发的界面程序封装成DLL,在VC中成功调用
2012-09-11 10:33 21122最近手头的一个项目需要做一个QT界面,并且封装成DLL,然后 ... -
诺基亚挥别Qt,转手给Digia
2012-09-11 09:37 2861一家总部位于芬兰的IT业务供应商Digia今天宣布,已经签署了 ... -
Qt多线程间信号槽传递非QObject类型对象的参数
2012-09-07 15:29 21384一、以前就发现过这个问题: 在Qt项目中,有时候为了 ... -
QT样式表(QStyleSheet)
2012-08-17 10:37 17895QT样式表 (QStyleSheet) 作者:刘旭晖 ... -
FinalData磁盘文件恢复工具(绿色破解版)
2012-08-02 13:28 8591FinalData磁盘文件恢复工具(绿色破解版),使用起来很方 ... -
Eclipse Qt开发环境的建立【转】
2012-08-01 11:15 43831.下载Eclipse目前Eclipse+CDT已经可以 ... -
汽车辐射监测系统-Qt开发
2012-07-25 16:18 4694最近晚上抽空忙了两个月,才把一个小系统做完。虽然做的不是太完 ... -
Qt做发布版,解决声音和图片、中文字体乱码问题
2012-07-14 16:02 4866Qt做发布版,解决声音和图片、中文字体乱码问题 ... -
QTableView使用中的疑问,如何及时显示操作Model后的结果?
2012-06-01 14:52 0最终的解决方法:我正 ... -
【转】Qt QTableview使用
2012-06-01 09:49 9677QTableWidget是QT程序中常用的显示数 ... -
QTableView双击 单机事件信号
2012-06-01 09:47 23107双击QTableView的行,获取该行数据 代码 ... -
QMessageBox改变大小
2012-05-31 15:33 8451创建一个QMessageBox: QMessageBo ... -
更新QTableView中的进度条状态
2012-05-30 14:37 14870前段时间,我接触了,如何在一个QTableView中加入一个控 ... -
QThread 线程暂停 停止功能的实现
2012-05-29 11:56 12207为了实现Qt中线程的暂停运行,和停止运行的控制功能 需要在设 ... -
QT环境变量
2012-05-28 18:53 5594不知道为啥同事有台电脑,装完Qt-VS2008库,和VS Ad ... -
广告光
2012-05-24 18:33 0盈创广告联盟 http://www.yo114.cn/ ... -
Test
2012-05-24 18:22 2191Test<IMG SRC="cf08e32c2 ...
相关推荐
这个压缩包文件“026 QWidget类分析显示和隐藏接口说明线程类QThread使用方法”显然是针对Qt开发者的,旨在详细解释`QWidget`的显示和隐藏功能以及如何使用线程类`QThread`。下面我们将深入探讨这两个关键概念。 ...
在`mainwindow.py`中,通常会定义一个继承自`QWidget`的类,这个类包含了UI元素以及与之相关的业务逻辑。`QThread`的实例通常在这里创建,并与特定的工作对象(如槽函数)关联,以便在新线程中执行。而在`main.py`中...
在本文中,我们将深入探讨如何使用Qt库,特别是QWidget类,来实现一个模仿企业微信界面的桌面应用程序。这个项目专注于界面逻辑,不涉及实际的业务处理,因此是学习Qt UI设计和QWidget用法的理想示例。我们将讨论...
本文将深入探讨`QThread`类以及如何使用`run()`方法来实现多线程。 首先,`QThread`是QT中的一个核心类,它为创建和管理线程提供了一种面向对象的方法。与标准C++的`std::thread`不同,`QThread`允许我们在一个新的...
PyQt是Python绑定的Qt库,提供了一套全面的GUI...正确使用`QThread`能够确保UI的响应性,提高应用程序的性能和稳定性。在实际项目中,根据需求可以设计不同的线程类,以执行各种后台任务,同时保持用户界面的流畅交互。
### Python GUI 库图形界面开发之 PyQt5 线程类 QThread 详细使用方法 在 Python 的图形用户界面(GUI)开发中,PyQt5 是一个非常强大的库,能够帮助开发者快速构建出功能丰富且界面友好的应用程序。在 GUI 开发...
9. **QWidget**:作为Qt GUI编程的基础,`QWidget`是所有窗口小部件的基类,它提供了基本的绘制、事件处理和布局管理能力。 以上就是关于这个压缩包中包含的Qt知识点的详细介绍。通过这些组件,开发者可以构建功能...
4. **线程安全通信**:为了在主线程和绘图线程之间传递数据,可以使用信号与槽机制。通过在适当线程中发射信号和连接槽,可以确保在正确线程中执行对应操作,这是Qt线程间通信的核心。 5. **绘图类QPainter和...
**第一种方式:使用QThread类** 在QT中,创建一个新的线程通常涉及到继承QThread类。首先,定义一个名为`MyThread`的类,让它继承自`QThread`,并重写`run()`函数。`run()`函数是线程的主要工作区,其中放置需要在...
其中,"QWidgetDemo"可能是一个展示如何使用QWidget类创建基本窗口的实例。 QWidget是Qt GUI系统的核心类,它是所有用户界面对象的基类。通过这个案例,我们可以学习到以下关键知识点: 1. **QWidget的使用**:...
然而,值得注意的是,虽然QThread提供了一种易于使用的线程模型,但直接在run()方法中创建和操作复杂的Qt对象(如QWidget)并不是最佳实践。通常,我们建议将实际工作逻辑封装到一个不继承QThread的类中,然后在...
最简单的多线程使用方法是利用QThread函数,展示QThread函数和信号简单结合的方法 import sys from PyQt5.QtCore import * from PyQt5.QtWidgets import * class Main(QWidget): def __init__( self, parent=None ...
我们定义了一个PollTimeThread类,该类继承自QtCore.QThread。这个线程将每秒触发一次,用于更新视频播放器的时间信息。 知识点4:信号和槽 在PyQT库中,信号和槽机制是实现事件驱动编程的关键机制。我们使用信号...
- 使用QThread实现多线程 - 线程安全编程和互斥量(QMutex) 9. **第10章 Qt工具使用**: - Qt Designer用于图形化界面设计 - UIC和MOC编译工具的使用 - qmake项目构建系统 - 使用Qt Assistant和Qt Linguist...
在QT中,你可以使用`pthread_create`,但需要注意线程安全问题,因为QT的信号槽机制并不直接与`pthread_create`兼容。 ```cpp #include void* threadFunction(void* arg) { // arg参数在这里可以获取到 // 在...
使用QThread时,需要注意的是,通常不建议直接继承QThread并重写run()方法,因为这可能会导致资源管理的问题。更推荐的方式是创建一个工作类,重载start()和run()方法,并通过 moveToThread() 将工作对象移动到新...
但并不是所有Qt对象都线程安全,比如QWidget,它们通常需要在主线程中使用。 8. **最佳实践**: - 避免长时间阻塞主线程,以免影响用户界面的响应性。 - 理解并合理使用同步机制,防止数据竞争。 - 尽可能减少跨...
在上述代码中,我们创建了一个`QTimer`对象,并将其与`onTimeout`槽函数连接。当定时器的`timeout`信号触发时,`onTimeout`函数会被调用,实现了5秒的延时效果。 另外,对于更复杂的延时控制,比如在界面上显示倒...
7. **播放视频**:在Qt中,你可以使用QThread或者Qt的并发框架(如QRunnable和QtConcurrent)来处理视频流,避免阻塞主线程。视频数据通常以字节流的形式接收,然后转化为图像,显示在QLabel、QImage或QPixmap等Qt...
3. **QApplication与QWidget**: 每个QT程序都始于QApplication对象,它管理整个应用程序的生命周期,而QWidget是所有图形组件的基类,所有可见的用户界面元素都是QWidget的子类。 4. **信号与槽机制**: 这是QT的一...