因为 qt 子线程中部分ui更新的接口不能用,就需要使用信号槽,让子线程通知进程更新UI。
1. 在线程类当中添加信号的定义
线程是信号的发出方,因此信号函数的定义在线程内。信号函数的声明在.h文件中,可以带参数。
class led_thread : public QThread {Q_OBJECTpublic:int btn_cnt;protected:void run();signals:void update_btn(int num); // 声明信号};
void update_btn(int) 就是定义的信号函数,注意返回值是void
2. 在线程类当发送信号
以更新按钮为例子,要轮流发送信号,通知槽函数更新某个按钮。发送信号时可以带一个int值,对应更新这个int下标的按钮:
void led_thread::run() {while(true) {for(int i = 0; i < btn_cnt; i++) {emit update_btn(i);// 发送信号,参数值是对应下标的标号sleep(1);}}}
3. 在界面进程里面添加槽函数
首先在mainwindows.h 定义槽函数,注意要和信号函数一样,定义参数值
private slots:void updateBtnSlot(int num);
然后在.cpp文件中实现这个槽函数。在槽函数中,通过接收到的num,在mainwindows的btn数组内找到对应下标的按钮,设置颜色。并且把上一个按钮颜色清空。如果当前是0,就把最后一个按钮清空(上次循环的末尾)。
void MainWindow::updateBtnSlot(int num) {btn_list[num]->setStyleSheet("background-color:rgb(255,255,255)");if(num == 0) {btn_list[btn_list.size() - 1]->setStyleSheet("background-color:rgb(255,255,255)");} else {btn_list[num - 1]->setStyleSheet("background-color:rgb(255,255,255)");}}
4. 初始化,并连接信号槽
在mainwindows.cpp的初始化函数里面,连接子线程的信号,和ui进程的槽
led_th->btn_cnt = btn_list.size();connect(led_th, SIGNAL(update_btn(int)), this, SLOT(updateBtnSlot(int)));led_th->start();
5. 在ui进程类里面,保存按钮数组
因为界面更新在ui类里面,所以按钮数组定义在mainwindows.h 里面
class MainWindow : public QMainWindow {Q_OBJECTpublic:explicit MainWindow(QWidget *parent = nullptr);~MainWindow();QTimer *timer1;my_thread * blink_th;led_thread * led_th;QVector<QPushButton*> btn_list; // 按钮数组private:Ui::MainWindow *ui;private slots:void time_out();void updateBtnSlot(int num);};
然后在初始化函数里面,存入按钮。注意要先存入按钮,后再给线程类里面的btn_cnt赋值
btn_list.append(ui->pushButton_1);btn_list.append(ui->pushButton_2);btn_list.append(ui->pushButton_3);btn_list.append(ui->pushButton_4);btn_list.append(ui->pushButton_5);btn_list.append(ui->pushButton_6);btn_list.append(ui->pushButton_7);btn_list.append(ui->pushButton_8);btn_list.append(ui->pushButton_9);btn_list.append(ui->pushButton_10);btn_list.append(ui->pushButton_11);btn_list.append(ui->pushButton_12);led_th->btn_cnt = btn_list.size();connect(led_th, SIGNAL(update_btn(int)), this, SLOT(updateBtnSlot(int)));led_th->start();
6. 在进程里面自定义延时函数
由于主进程没有sleep函数,可以用QTime和事件循环来实现不阻塞的延时:
先获取要定时的时间,然后在循环中不断判断是否到达那个时间。
.h中定义
private:Ui::MainWindow *ui;void Sleep(int msec);
.cpp中实现延时
#include <QTime>#include <QEventLoop>#include <QCoreApplication>void MainWindow::Sleep(int msec){// 用QTime 设定结束的时间QTime dieTime = QTime::currentTime().addMSecs(msec);// while循环直到时间到while( QTime::currentTime() < dieTime )QCoreApplication::processEvents(QEventLoop::AllEvents, 100);// 执行事件循环,防止阻塞ui}
调用如下:
btn_list[num]->setStyleSheet("background-color:rgb(255,0,0)");Sleep(400);btn_list[num]->setStyleSheet("background-color:rgb(255,255,255)");
