码上通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()方法实现动态更新。

复制代码
原创不易,打字不易,截图不易,撸码不易,整理不易,走过路过,不要错过,欢迎点赞,收藏,转载,复制,抄袭,留言,灌水,请动动你的金手指,祝您早日实现财务自由。
相关推荐
m0_6265352016 小时前
快速排序学习 l方法 h方法
开发语言·python
superman超哥16 小时前
Rust String与&str的内部实现差异:所有权与借用的典型案例
开发语言·后端·rust·rust string·string与str·内部实现·所有权与借用
xiaowu08016 小时前
C#调用 C++ DLL 加载地址方式选择
开发语言·c++·c#
cn_mengbei16 小时前
鸿蒙PC开发实战:Qt环境搭建保姆级教程与常见问题避坑指南(HarmonyOS 4.0+DevEco Studio 3.1最新版)
qt·华为·harmonyos
非凡ghost16 小时前
MPC-QT视频播放器(基于Qt框架播放器)
开发语言·windows·qt·音视频·软件需求
转基因16 小时前
C++的IO流
开发语言·c++
一碗绿豆汤16 小时前
Java语言概述和开发环境-1
java·开发语言
愈努力俞幸运16 小时前
rust安装
开发语言·后端·rust
cn_mengbei17 小时前
从零到一:基于Qt on HarmonyOS的鸿蒙PC原生应用开发实战与性能优化指南
qt·性能优化·harmonyos