Qt ⑦ 定制控件&线程

Qt ⑦ 定制控件&线程

一、定制控件

定制控件——定制控件一般是将继承自QWidget的类,封装成一个独立的类,供开发者使用。

1、将要定制的控件类封装

alt

2、加入本工程,引用头文件

#include <mypainter.h>

alt

3、有两种方法实现构造定制控件类

①方法1:在主界面内实例化

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
	//定制类    
    MyPainter *mp = new MyPainter();
}

​ ②方法2:对UI设计界面的Widget容器提升

alt

alt

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、具体展示

alt

二、线程

alt

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();
}

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务