场景需求:想做一个能根据外部数据动态更新的仪表盘,作为窗体的子控件显示。实际效果:
第一步:要在label显示的图片上二次绘图。
方法:重载QLabel为pgxtlabel,新建pgxtlabel,继承QLabel类。然后在pgxtlabel重写QPainter。
pgxtlabel.h
#ifndef PGXTLABEL_H
#define PGXTLABEL_H
#include <QLabel>
#include <QSlider>
#include <QStyle>
#include <QPainter>
class pgxtlabel : public QLabel
{
Q_OBJECT //一定要有,否则无法连接信号槽
public:
pgxtlabel(QWidget *parent);
virtual void paintEvent(QPaintEvent *event) override;
int rotate_value=0; //默认指针处在0刻度处
private:
private slots:
void slot_updateLabel(int value);
};
#endif // PGXTLABEL_H
pgxtlabel.cpp
#include "pgxtlabel.h"
pgxtlabel::pgxtlabel(QWidget *parent):QLabel(parent)
{
this->setStyleSheet("border-image: url(:/pgxt/pgxtpanel1.png)");//面板图片
}
void pgxtlabel::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing);
painter.save();
QTransform trans;
trans.translate(this->width()/2, this->height()/2);//设置坐标系中心位置,即旋转中心
trans.rotate(((rotate_value) * (360.0 / 200)));//机械臂位置变化转化为实际转动角度
trans.translate(-(this->width()/2), -(this->height()/2));
painter.setWorldTransform(trans);
QPixmap pix;
pix.load(":/pgxt/pgxtpointer.png");//指针图片
painter.drawPixmap(this->width()/2-23, this->height()/2-197, 46, 220, pix);
painter.restore();
painter.end();
}
void pgxtlabel::slot_updateLabel(int value) //外部接口函数,用于接收外部数据,动态更新label
{
rotate_value = value;
update();
}
以上就可以实现在Label显示的图片上绘图,即在label显示的表盘上绘制表盘指针,并且留了一个外部接口函数,用于接收外部数据,动态更新Label上的图片。
第二步:接下来实现外部数据的传入。
方法:新建一个线程类pgxtThread,基类为QThread。将机械臂的运动函数放在新建的线程里,防止阻塞主线程,导致程序崩溃。
pgxtThread.h
#pragma once
#include <QObject>
#include <QWidget>
#include <QThread>
#include "stdafx.h"
#include "Definitions.h"
#include <iostream>
#include <QMutex>
class pgxtThread : public QThread
{
Q_OBJECT
public:
explicit pgxtThread(QObject *parent = nullptr);
void threadPause();
void threadResume();
QMutex m_mutex;//互斥量
private:
//声明机械臂运动函数所需参数
...
protected:
void run();
signals:
void RotateAngle(int); //转动角度信号
};
pgxtThread.cpp
#include "pgxtThread.h"
pgxtThread::pgxtThread(QObject *parent) : QThread(parent)
{
}
void pgxtThread::run()
{
//机械臂设备激活函数
...
//机械臂当前位置返回函数
...
int positionls1 = positionls;//设备当前位置
while (1 == 1)
{
m_mutex.lock();
//机械臂设备运动函数
...
//机械臂当前位置返回函数
...
int positionls2 = positionls;
int angle = (positionls2 - positionls1)/(1024*8.5);//位置转化成角度
emit RotateAngle(angle);//发射设备转动角度信号
m_mutex.unlock();
}
}
void pgxtThread::threadPause()
{
m_mutex.lock();//互斥锁控制线程的开始与暂停
}
void pgxtThread::threadResume()
{
m_mutex.unlock();
}
第三步:主窗体pgsystem作如下更改。
pgsystem.h中加入
private:
pgxtlabel *pgxtimage1;//要显示仪表盘的label
pgxtThread *pgxtthread;//新线程
pgsystem.cpp中加入
pgsystem::pgsystem(QWidget *parent) : QWidget(parent)
{
pgxtimage1=new pgxtlabel(this);
pgxtthread = new pgxtThread(this);
connect(pgxtthread, SIGNAL(RotateAngle(int)), pgxtimage1, SLOT(slot_updateLabel(int)));
connect(pgxtthread, SIGNAL(RotateAngle(int)), this, SLOT(angleupdate(int)));
}
//开始按钮的槽函数
void pgsystem::starttime()
{
...
//在开始按钮的槽函数加入以下代码
pgxtthread->start();
}
//暂停按钮的槽函数
bool pgsystem::clicked = false;
void pgsystem::stoptime()
{
if(clicked == false)
{
...
//在暂停按钮的槽函数加入以下代码
pgxtthread->threadPause();
}
else if(clicked == true)
{
...
//在继续按钮的槽函数加入以下代码
pgxtthread->threadResume();
}
}
void pgsystem::angleupdate(int angle)
{
QString sz = QString("%1°").arg(QString::number(angle));
szAngle->setText(sz);
}