目录
所有界面组件的操作都只能在主线程中完成(不可以在子线程中创建界面组件);因此,主线程也叫做UI线程!
子线程对界面组件更新
1.1、信号与槽
所有的界面组件对象只能依附于主线程 ,子线程不能直接操作界面组件,但是子线程可以通过发射信号的方式更新界面组件
-在子线程类中定义界面组件的更新信号( updateUI )
-在主窗口类中定义更新界面组件的槽函数( setlnfo )
-使用异步方式连接更新信号到槽函数( updateUI → setlnfo )
子线程发射信号通知主线程界面更新请求;主线程根据具体信号以及信号参数对界面组件进行修改
UpdateThread.h
#ifndef UPDATETHREAD_H
#define UPDATETHREAD_H
#include <QThread>
class UpdateThread : public QThread
{
Q_OBJECT
protected:
void run();
public:
explicit UpdateThread(QObject *parent = 0);
signals:
void updateUI(QString text);
};
#endif // UPDATETHREAD_H
UpdateThread.cpp
#include "UpdateThread.h"
UpdateThread::UpdateThread(QObject *parent) :
QThread(parent)
{
}
void UpdateThread::run()
{
emit updateUI("Begin");
for(int i=0; i<10; i++)
{
emit updateUI(QString::number(i));
sleep(1);
}
emit updateUI("End");
}
Widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QtGui/QWidget>
#include <QPlainTextEdit>
#include "TestThread.h"
#include "UpdateThread.h"
class Widget : public QWidget
{
Q_OBJECT
UpdateThread m_thread;
QPlainTextEdit textEdit;
protected slots:
void appendText(QString text);
public:
Widget(QWidget *parent = 0);
~Widget();
};
#endif // WIDGET_H
Widget.cpp
#include "Widget.h"
#include "TestThread.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
textEdit.setParent(this);
textEdit.move(20, 20);
textEdit.resize(200, 150);
textEdit.setReadOnly(true);
connect(&m_thread, SIGNAL(updateUI(QString)), this, SLOT(appendText(QString)));
m_thread.start();
}
void Widget::appendText(QString text)
{
textEdit.appendPlainText(text);
}
Widget::~Widget()
{
}
main.cpp
#include <QtGui/QApplication>
#include "Widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
1.2、发送自定义事件
过程
-自定义事件类用于描述界面更新细节
-在主窗口类中重写事件处理函数 event ( 在event事件处理函数更新界面状态 )
-子线程使用 postEvent 函数(异步方式)发送自定义事件类对象 (子线程指定接受消息的对象为主窗口对象 )
事件对象是在主线程中被处理的,即:event函数的调用在主线程中完成
StringEvent.h
#ifndef _STRINGEVENT_H_
#define _STRINGEVENT_H_
#include <QEvent>
#include <QString>
// 自定义事件类
class StringEvent : public QEvent
{
QString m_data;
public:
const static Type TYPE = static_cast<Type>(QEvent::User + 0xFF);
explicit StringEvent(QString data = "");
QString data();
};
#endif // _STRINGEVENT_H_
StringEvent.cpp
#include "StringEvent.h"
StringEvent::StringEvent(QString data) : QEvent(TYPE)
{
m_data = data;
}
QString StringEvent::data()
{
return m_data;
}
UpdateThread.cpp
#include "UpdateThread.h"
#include <QApplication>
#include "StringEvent.h"
UpdateThread::UpdateThread(QObject *parent) :
QThread(parent)
{
}
void UpdateThread::run()
{
// 发送给当前对象的parent(),所以需要设置当前线程对象父组件为主窗口
QApplication::postEvent(parent(), new StringEvent("Begin")); // 发送自定义事件,发送的事件对象必须在堆上创建
for(int i=0; i<10; i++)
{
QApplication::postEvent(parent(), new StringEvent(QString::number(i)));
sleep(1);
}
QApplication::postEvent(parent(), new StringEvent("End"));
}
Widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QtGui/QWidget>
#include <QPlainTextEdit>
#include "UpdateThread.h"
class Widget : public QWidget
{
Q_OBJECT
UpdateThread m_thread;
QPlainTextEdit textEdit;
public:
Widget(QWidget *parent = 0);
bool event(QEvent *evt); //自定义事件处理函数
~Widget();
};
#endif // WIDGET_H
Widget.cpp
#include "Widget.h"
#include "StringEvent.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
textEdit.setParent(this);
textEdit.move(20, 20);
textEdit.resize(200, 150);
textEdit.setReadOnly(true);
m_thread.setParent(this); // 子线程创建时必须附带目标对象的地址信息
m_thread.start();
}
bool Widget::event(QEvent *evt)
{
bool ret = true;
if( evt->type() == StringEvent::TYPE )
{
StringEvent* se = dynamic_cast<StringEvent*>(evt);
if( se != NULL )
{
textEdit.appendPlainText(se->data());
}
}
else
{
ret = QWidget::event(evt);
}
return ret;
}
Widget::~Widget()
{
}