因为 qt 子线程中部分ui更新的接口不能用,就需要使用信号槽,让子线程通知进程更新UI。
1. 在线程类当中添加信号的定义
线程是信号的发出方,因此信号函数的定义在线程内。信号函数的声明在.h文件中,可以带参数。
class led_thread : public QThread {
Q_OBJECT
public:
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_OBJECT
public:
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)");