Qt ⑦ 定制控件&线程
Qt ⑦ 定制控件&线程
一、定制控件
定制控件——定制控件一般是将继承自QWidget的类,封装成一个独立的类,供开发者使用。
1、将要定制的控件类封装
2、加入本工程,引用头文件
#include <mypainter.h>
3、有两种方法实现构造定制控件类
①方法1:在主界面内实例化
Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //定制类 MyPainter *mp = new MyPainter(); } ②方法2:对UI设计界面的Widget容器提升
4、具体的使用
当使用
"3"中的方法定制好类后,我们需要给定制类去实现一些公有接口和信号以及槽函数等,以便我们能够在widget主界面类中去通过这些接口和信号对定制类实现一些定制化的操作。
部分对定制化类的操作示例:Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); ui->lcdNumber->display(QString("00:00:00")); //绑定当前界面的滑动条控件与定制类Mypainter的信号与槽 connect(ui->horizontalSlider , &QSlider::sliderMoved , ui->clockWidget , &MyPainter::setSecond); //绑定Mypainter相关信号与槽 connect(ui->clockWidget , &MyPainter::timeShow , ui->lcdNumber , QOverload<const QString &>::of(&QLCDNumber::display)); } Widget::~Widget() { delete ui; } //当前界面控件去调用clock类的public接口 void Widget::on_btn_start_clicked() { ui->clockWidget->startTimerPSlot(1000); } //调用public接口 void Widget::on_btn_stop_clicked() { ui->clockWidget->stopTimerPSlot(); }5、具体展示
二、线程
1、线程创建方法(两种)
①方法1:继承自QThread类的方法
第一种是新建一个类,该类继承于QThread基类,并且在新建类中重写
run()函数(当线程启动时,会自动调用run()函数)。
示例代码:class MyThread : public QThread { Q_OBJECT public: //资源交给父对象来管理,进行资源的释放 MyThread(QObject *parent):QThread(parent){} //重写run方法,当线程启动时,系统自动调用该函数 void run(){ qDebug() << "id : " << this->currentThread(); while(1) { if(count > 100) count = 0; if(!pause) //设计暂停emit属性 emit valueChanged(count++); //手动触发信号 msleep(10); //睡眠10毫秒,防止卡死 } } signals: void valueChanged(int); public slots: void setPause(bool flag) { pause = flag; } private: int count = 0; bool pause = false; };②方法2:moveToThread() 方法实现
第二种方法,我们新建一个类,该类继承自
QObject(这里不能继承自QThreat或者QWidget),然后用moveToThread(对象名),将新建类的实例对象传入,然后启动线程就可以将该类的功能交给线程运行,从而也可以实现多线程的功能。
自定义Work类#ifndef WORK_H #define WORK_H #include <QWidget> #include <QThread> #include <QApplication> class Work : public QObject { Q_OBJECT public: explicit Work(QObject *parent = nullptr) :QObject{parent} {} signals: void valueChanged(int); public slots: void doWork() { qDebug() << "id : " << QThread::currentThreadId(); while(1) { if(count > 100) count = 0; if(!pause) emit valueChanged(count++); //响应外部事件 QApplication::processEvents(); QThread::msleep(1); } } void setPasue(bool flag) { pause = flag; } private: int count = 0; bool pause = false; }; #endif // WORK_H
主界面类注意,当使用moveToThread的时候,我们需要通过信号与槽等方法,让系统去调用线程资源,手动调用线程的启停可能会导致一些不可预知的程序错误。
Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); work = new Work; work->moveToThread(&th); //将work对象交给th线程 connect(work , &Work::valueChanged , ui->progressBar , &QProgressBar::setValue); //绑定信号 通过触发信号,让系统来调用使用线程 connect(this , &Widget::operate , work , &Work::doWork); connect(this , &Widget::setPause , work , &Work::setPasue); } Widget::~Widget() { delete ui; } void Widget::on_btn_start_clicked() { //work->doWork(); //错误写法,doWork在主进程空间被调用 th.start(); //启动线程,线程处于挂起状态 //触发信号,让系统调用doWork emit operate(); } void Widget::on_btn_stop_clicked() { emit setPause(true); } void Widget::on_btn_continue_clicked() { emit setPause(false); } void Widget::on_btn_end_clicked() { th.terminate(); //强制杀死线程 }
三、互斥锁
QMutex互斥锁类
互斥锁一般用在临界资源上,在Qt中用QMutex类来实现互斥锁的功能。
以下是使用示例:
线程1 加锁#ifndef THREAD_1_H #define THREAD_1_H #include <QThread> #include <iostream> #include <QMutex> using namespace std; class Thread_1 : public QThread { public: Thread_1(int *a , int size , QMutex &m):a(a) , size(size) , m(m){} void run(){ //加锁 m.lock(); for(int i = 0 ; i < size / 2 ; i++) { int temp = a[i]; a[i] = a[size - 1 - i]; a[size - 1 - i] = temp; } cout << "Thread 1 : "; for(int i = 0 ; i < size ; i++) { cout << a[i] << " "; } cout << endl; //解锁 m.unlock(); } private: int *a; int size; QMutex &m; }; #endif // THREAD_1_H
线程2 加锁#ifndef THREAD_2_H #define THREAD_2_H #include <QThread> #include <iostream> #include <QMutex> using namespace std; class Thread_2 : public QThread { public: Thread_2(int *a , int size , QMutex &m):a(a) , size(size) , m(m){} void run(){ //加锁 m.lock(); cout << "Thread 2 : "; for(int i = 0 ; i < size ; i++) { cout << a[i] << " "; } cout << endl; //解锁 m.unlock(); } private: int *a; int size; QMutex &m; }; #endif // THREAD_2_H
主函数#include <QCoreApplication> #include <thread_1.h> #include <thread_2.h> #include <QMutex> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QMutex mutex; //构造互斥锁 int buf[] = {1,2,3,4,5}; //线程1 倒置 打印 Thread_1 *t1 = new Thread_1(buf,5,mutex); t1->start(); //线程2 只遍历打印 Thread_2 *t2 = new Thread_2(buf,5,mutex); t2->start(); return a.exec(); }
查看8道真题和解析