QT 绘制根据外部数据动态更新的仪表盘

场景需求:想做一个能根据外部数据动态更新的仪表盘,作为窗体的子控件显示。实际效果:

第一步:要在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);
}

猜你喜欢

转载自blog.csdn.net/L1114187703/article/details/106915427
今日推荐