码上通QT实战10--监控页面02-绘制温度盘

1、前言

Qt绘图基础概述

Qt提供了强大的绘图功能,主要通过QPainter类实现。绘图可以在QPaintDevice的子类上进行,例如QWidgetQPixmapQImage等。绘图操作通常在paintEvent事件中完成。

基本绘图类

  • QPainter: 核心绘图工具,提供绘制线条、形状、文本和图像的方法。
  • QPaintDevice : 绘图设备的基类,如QWidgetQPixmap等。
  • QPaintEngine: 底层绘图引擎,通常不需要直接使用。
  • QPen: 定义绘图的线条样式、颜色和宽度。
  • QBrush: 定义填充样式和颜色。

基本绘图步骤

创建QPainter对象:paintEvent中创建QPainter对象,并指定绘图设备:

设置绘图属性: 使用QPenQBrush设置绘图样式:

**绘制基本图形:**绘制线条:绘制矩形:绘制椭圆:绘制文本:

坐标系统与变换

Qt的坐标系统默认以左上角为原点,X轴向右,Y轴向下。可以通过QPainter的变换方法调整坐标

自定义绘图控件

通常需要继承QWidget并重写paintEvent

cpp 复制代码
#include <QWidget>
#include <QPainter>

class MyWidget : public QWidget {
protected:
    void paintEvent(QPaintEvent *) override {
        QPainter painter(this);
        painter.setPen(Qt::red);
        painter.setBrush(Qt::blue);
        painter.drawRect(QRect(10, 10, 100, 50));
        painter.drawText(QPoint(20, 30), "Qt Drawing");
    }
};

QPainter提供丰富的绘图功能:

  • 基本图形:drawLine(), drawRect(), drawEllipse()
  • 路径绘制:QPainterPath可创建复杂形状
  • 文本绘制:drawText()
  • 图像绘制:drawImage(), drawPixmap()

通过以上方法,可以快速掌握Qt的绘图基础并实现复杂的图形界面效果。

2、立即干

1、新建绘图文件

2、添加有关属性

Q_PROPERTY 概述

Q_PROPERTY 是 Qt 框架中的一个宏,用于在类声明中定义属性(Property)。这些属性可以通过 Qt 的元对象系统(Meta-Object System)动态访问,支持信号与槽机制、属性绑定、动画等高级功能。属性通常包含一个成员变量及其对应的读写方法(Getter/Setter),并可附加元数据(如通知信号、是否可编辑等)。

cpp 复制代码
Q_PROPERTY(type name  
           READ getter  
           [WRITE setter]  
           [RESET resetFunction]  
           [NOTIFY notifySignal]  
           [DESIGNABLE bool]  
           [SCRIPTABLE bool]  
           [STORED bool]  
           [USER bool]  
           [CONSTANT]  
           [FINAL])
  • type name :属性类型和名称(如 QString text)。
  • READ getter :必须项,指定读取属性的函数(如 text())。
  • WRITE setter :可选项,指定设置属性的函数(如 setText(const QString&))。
  • NOTIFY notifySignal :可选项,指定属性变化时触发的信号(如 textChanged())。

通过 Q_PROPERTY,Qt 实现了属性系统的动态性和灵活性,广泛应用于数据绑定、UI 控件属性暴露等场景

完整代码

cpp 复制代码
#ifndef METER_H
#define METER_H
#include <QPaintEvent>
#include <QWidget>


class Meter : public QWidget
{
    Q_OBJECT
    //定义相关属性
    Q_PROPERTY(qreal minimum READ minimum WRITE setMinimum);//最小值
    Q_PROPERTY(qreal maximum READ maximum WRITE setMaximum);//最大值
    Q_PROPERTY(double value READ value WRITE setValue);//当前值
    Q_PROPERTY(QString unit READ unit WRITE setUnit);//单位
    Q_PROPERTY(QString header READ header WRITE setHeader);//标题

public:
    explicit Meter(QWidget *parent = nullptr);
    qreal minimum() const
    {
        return m_minimum;
    }

    qreal maximum() const
    {
        return m_maximum;
    }

    double value() const
    {
        return m_value;
    }

    QString unit() const
    {
        return m_unit;
    }

    QString header() const
    {
        return m_header;
    }

public slots:
    void setMinimum(qreal minimum)
    {
        if(minimum==m_minimum)
            return;
        m_minimum = minimum;
        update();
    }

    void setMaximum(qreal maximum)
    {
        if(maximum==m_maximum)
            return;
        m_maximum = maximum;
        update();
    }

    void setValue(double value)
    {
        if(value==m_value)
            return;
        m_value = value;
        update();
    }

    void setUnit(QString unit)
    {
        if(unit==m_unit)
            return;
        m_unit = unit;
        update();
    }

    void setHeader(QString header)
    {
        if(header==m_header)
            return;
        m_header = header;
        update();
    }

private:
    qreal m_minimum;
    qreal m_maximum;
    double m_value;
    QString m_unit;
    QString m_header;

protected:
    void paintEvent(QPaintEvent *event) override;//窗体重绘事件


signals:
};

#endif // METER_H

3、绘制图形

理解 paintEvent 的基本概念

paintEvent 是 Qt 框架中 QWidget 类的一个虚函数,用于处理窗口部件的绘制事件。当部件需要重绘时(如窗口首次显示、被其他窗口遮挡后重新显示、调用 update()repaint() 方法时),系统会自动调用此函数。

重写 paintEvent 的步骤

  1. 继承 QWidget 或其子类

    创建一个自定义类并继承自 QWidget 或其子类(如 QMainWindowQLabel 等)。例如:

    cpp 复制代码
    class MyWidget : public QWidget {
        Q_OBJECT
    public:
        explicit MyWidget(QWidget *parent = nullptr);
    protected:
        void paintEvent(QPaintEvent *event) override;
    };

    2.实现 paintEvent 函数

    在函数内部使用 QPainter 进行绘制操作。QPaintEvent 参数包含需要重绘的区域信息(可通过 event->rect() 获取)。例如:

cpp 复制代码
void MyWidget::paintEvent(QPaintEvent *event) {
    QPainter painter(this);
    painter.setPen(Qt::red);
    painter.drawLine(0, 0, width(), height());
    painter.drawText(rect(), Qt::AlignCenter, "Hello, Qt!");
}

3.触发重绘

通过调用 update()repaint() 触发重绘。update() 是异步的,会将重绘请求加入事件队列;repaint() 是同步的,会立即执行重绘。

常用绘制操作

绘制基本图形

使用 QPainterdrawLinedrawRectdrawEllipse 等方法绘制线条、矩形、圆形等

设置画笔和画刷
QPen 用于设置线条样式,QBrush 用于设置填充样式。

通过合理使用 paintEvent,可以实现高度自定义的界面绘制效果,同时保持性能优化

完整代码

cpp 复制代码
#include "meter.h"
#include <QPaintEvent>
#include <QPainter>
#include <QtMath>


Meter::Meter(QWidget *parent)
    : QWidget{parent}
{
    // m_maximum=100;
    // m_minimum=0;
    // m_value=28;
    // m_unit="单位";
    // m_header="温度";
}

//重绘窗体
void Meter::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(QColor(0,0,0,0));

    //1、渲染尺寸
    int diameter=qMin(this->size().width(),this->size().height());//获取长度和宽度,取两者最小值
    qreal radius=diameter/2;//圆的半径

    //2、中心点
    QPointF center(this->size().width()/2,this->size().height()/2);//圆心坐标

    //3、底盘:径向渐变
    // painter.setPen(Qt::black);
    painter.setPen(Qt::transparent);//透明
    QRadialGradient gradient(center.x(),center.y(),radius,center.x(),center.y());
    gradient.setColorAt(0,QColor(62,155,253,60));
    gradient.setColorAt(1,QColor(33,97,216,0));
    painter.setBrush(gradient);
    painter.drawEllipse(center,radius,radius);

    //4、刻度线
    int min=this->m_minimum,max=m_maximum;
    int count=10,start_num=min;
    //     270/100 = 2.7//刻度盘角度范围为270度

    QPen pen_line(QColor("#222363DA"),2);
    QPen pen_text(QColor("#992363DA"));

    //循环产生刻度值,
    for(int i=0;i<=100;i++){
        qreal angle=i*2.7+135;//每个刻度偏转135度

        painter.setPen(pen_line);
        // 当i的值
        int offset=7;
        //每隔10个刻度线绘制一个长一点的不同颜色的刻度线
        if(i%10==0){
            QPen pen_line2(QColor(255,0,0,125),2);//设置颜色
            painter.setPen(pen_line2);
            offset=12;
        }
        //每隔5个刻度线绘制一个短一点的不同颜色的刻度线
        else if(i%5==0)
        {
            QPen pen_line3(QColor(Qt::darkGreen),1);//设置颜色
            painter.setPen(pen_line3);
            offset=8;
        }
        //计算两个点的坐标值
        qreal x1= center.x()+ qCos(angle*M_PI/180)*(radius-2);
        qreal y1= center.y()+ qSin(angle*M_PI/180)*(radius-2);
        qreal x2= center.x()+ qCos(angle*M_PI/180)*(radius-offset);
        qreal y2= center.y()+ qSin(angle*M_PI/180)*(radius-offset);
        painter.drawLine(QPointF(x1,y1),QPointF(x2,y2));//绘制刻度线

        // 每隔10个绘制刻度值文字
        if(i%10==0){
            painter.setPen(pen_text);
            qreal x= center.x()+ qCos(angle*M_PI/180)*(radius-22)-6;//文字X位置
            qreal y= center.y()+ qSin(angle*M_PI/180)*(radius-22)+3;//文字Y位置
            painter.setFont(QFont("Microsoft YaHei",9));//字体及大小
            painter.drawText(QPointF(x,y),QString::number(start_num));//绘制刻度值的文字
            start_num+=10;
        }
    }

    // 指针
    qreal value=this->value()-this->minimum();
    qreal v_angle=value*2.7+135;
    qreal p_angle_1=v_angle-90;
    qreal p_angle_2=v_angle+90;

    qreal x_v=qCos(v_angle*M_PI/180)*(radius-5)+center.x();
    qreal y_v=qSin(v_angle*M_PI/180)*(radius-5)+center.y();

    qreal x_p1=qCos(p_angle_1*M_PI/180)*2+center.x();
    qreal y_p1=qSin(p_angle_1*M_PI/180)*2+center.y();

    qreal x_p2=qCos(p_angle_2*M_PI/180)*2+center.x();
    qreal y_p2=qSin(p_angle_2*M_PI/180)*2+center.y();

    QPointF points[3]{
        QPointF(x_p1,y_p1),
        QPointF(x_v,y_v),
        QPointF(x_p2,y_p2)
    };
    // 通过多边形方法进行指针的绘制(三角形)
    painter.setPen(QPen(Qt::red,1));
    painter.setBrush(Qt::red);
    painter.drawPolygon(points,3);


    // 当前数值背景圆
    painter.setPen(QPen(QColor(0,0,0,33),3));
    QRadialGradient gradient_center(center.x(),center.y(),20,center.x(),center.y());
    gradient_center.setColorAt(0,QColor("#2F7CE9"));
    gradient_center.setColorAt(1,QColor("#3E9BFC"));
    painter.setBrush(gradient_center);
    painter.drawEllipse(center,20,20);

    // 当前值
    painter.setPen(Qt::white);
    painter.setFont(QFont("Microsoft YaHei",14));
    painter.drawText(this->rect(),Qt::AlignCenter,QString::number(this->value()));

    // 单位和标题
    painter.setFont(QFont("Microsoft YaHei",8));
    painter.setPen(QPen("#990146AE"));
    painter.drawText(QRect(0,0,this->rect().width(),this->rect().height()-25),
                     Qt::AlignHCenter|Qt::AlignBottom,this->m_unit);
    painter.drawText(QRect(0,0,this->rect().width(),this->rect().height()-10),
                     Qt::AlignHCenter|Qt::AlignBottom,this->m_header);


}

4、提升组件

提升部件概念

在Qt中,提升部件(Promoted Widgets)是一种设计时功能,允许开发者将自定义控件集成到Qt Designer中,以便在UI设计阶段直接使用。通过提升,可以将标准Qt控件(如QWidgetQLabel等)替换为自定义的子类控件。

使用场景

  • 需要在Qt Designer中直接使用自定义控件。
  • 避免手动编写代码替换UI文件中的标准控件。
  • 简化复杂控件的可视化设计流程。

注意事项

  • 提升后的控件在Qt Designer中仍显示为基类外观,但运行时会被替换为自定义控件。
  • 确保头文件路径在项目配置中正确设置,否则编译时会报错。
  • 若控件包含自定义属性,需通过Q_PROPERTY声明,并在Qt Designer中通过属性编辑器调整。

这跟前面用到的将导航按钮widget提升为navbutton意思一样,提升后的控件是一个自定义控件,一定要将自定义控件编译为动态库(或确保其头文件和实现文件在项目中可访问),以便Qt Designer能识别该类。

5、运行效果

6、小结

Qt提供了强大的绘图系统,创建自定义控件需要继承QWidget并重写paintEvent方法,通过成员变量存储绘图状态,结合update()方法实现动态更新。

复制代码
原创不易,打字不易,截图不易,撸码不易,整理不易,走过路过,不要错过,欢迎点赞,收藏,转载,复制,抄袭,留言,灌水,请动动你的金手指,祝您早日实现财务自由。
相关推荐
用户805533698032 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner2 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz7 天前
QML Hello World 入门示例
qt
xcyxiner10 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner11 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner11 天前
DicomViewer (添加模型类)3
qt
xcyxiner12 天前
DicomViewer (目录调整) 2
qt
xcyxiner12 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00614 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术14 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript