目的
使用Qt的绘制事件绘制一个仪表盘
思路
- 需要创建一个带绘制事件的控件
- 重写绘制事件
- 显示
实现
以下是实现代码,可复制到程序到,直接运行。
.h
cpp
// GaugeWidget.h
#ifndef GAUGEWIDGET_H
#define GAUGEWIDGET_H
#include <QWidget>
class GaugeWidget : public QWidget
{
Q_OBJECT
public:
explicit GaugeWidget(QWidget *parent = nullptr);
void setValue(qreal value){m_value = value;}
protected:
void paintEvent(QPaintEvent *event) override;
private:
qreal m_value;
};
#endif // GAUGEWIDGET_H
.h
分析
- 继承
QWidget
类,重新实现void paintEvent(QPaintEvent *event) override;
事件; - 设置仪表盘当前的数据
void setValue(qreal value){m_value = value;}
.cpp
cpp
// GaugeWidget.cpp
#include "GaugeWidget.h"
#include <QPainter>
#include <QDebug>
GaugeWidget::GaugeWidget(QWidget *parent) : QWidget(parent), m_value(0)
{
}
void GaugeWidget::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << this->size();
// 绘制表盘
painter.save();
painter.translate(width()/2, height()/2);
painter.setPen(Qt::NoPen);
painter.setBrush(QBrush(QColor(255, 255, 255)));
painter.drawEllipse(-100, -100, 200, 200);
painter.setBrush(QBrush(QColor(200, 200, 200)));
painter.drawEllipse(-95, -95, 190, 190);
static const int majorTickCount = 12;
static const int minorTickCount = 5;
QFont font;
font.setPointSize(8);
painter.setFont(font);
painter.save();
for (int i = 0; i <= majorTickCount; i++) {
qreal angle = i * 360.0 / majorTickCount;
painter.rotate(angle);
// 绘制刻度线
if (i < majorTickCount) {
painter.setPen(QPen(QColor(255, 255, 255), 2));
painter.drawLine(0, -85, 0, -95);
}
// 绘制刻度值
if (i % 2 == 0) {
painter.setPen(QPen(QColor(255, 0, 0)));
qreal value = i * 360.0 / majorTickCount;
QString text = QString::number(value, 'f', 0);
QRectF textRect(-50, -100, 100, 100);
painter.drawText(textRect, Qt::AlignTop|Qt::AlignHCenter, text);
}
painter.rotate(-angle);
}
for (int i = 0; i < majorTickCount; i++) {
for (int j = 1; j <= minorTickCount; j++) {
qreal angle = (i + j / (qreal)minorTickCount) * 360.0 / majorTickCount;
painter.save();
painter.rotate(angle);
painter.setPen(QPen(QColor(255, 255, 255), 1));
painter.drawLine(0, -90, 0, -95);
painter.restore();
}
}
painter.restore();
// 绘制指针
qreal angle = (m_value / 60.0+0.5) * 360;
painter.rotate(angle);
painter.setPen(QPen(QColor(255, 0, 0), 3));
painter.drawLine(0, 0, 0, 60);
painter.restore();
}
.cpp
分析
paintEvent
函数是继承自QWidget的paintEvent
事件处理函数,用于绘制小部件的界面。paintEvent
函数首先创建一个QPainter对象,然后设置抗锯齿渲染。其余部分主要是绘制仪表盘和指针。具体绘制过程如下:
- 绘制表盘:
-
将绘图原点平移到小部件的中心。
-
绘制外圆和内圆,用QBrush用来填充圆形。
-
根据majorTickCount(12)的值循环绘制刻度线和刻度值。每次循环需要计算出角度,然后将绘图原点旋转该角度。
-
如果当前是大刻度线,则用QPen绘制白色线条。
-
如果当前是大刻度线的偶数,则用QPen绘制红色刻度值,绘制完成后将绘图原点旋转回来。
-
根据majorTickCount(12)和minorTickCount(5)的值循环绘制小刻度线。每次循环需要计算出角度,然后将绘图原点旋转该角度,绘制小刻度线,然后将绘图原点旋转回来。
- 绘制指针:
- 根据m_value的值计算出指针应该指向的角度,并将绘图原点旋转该角度。
- 用QPen绘制红色的指针线。
- 将绘图原点旋转回来。
在MainWindow中使用自定义控件类GaugeWidget,测试表盘绘制效果:
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "GaugeWidget.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
GaugeWidget *gaugeWidget = new GaugeWidget;
setCentralWidget(gaugeWidget);
gaugeWidget->setValue(40);
}
MainWindow::~MainWindow()
{
delete ui;
}
编译运行程序,效果如下:
结论
繁华到极致,腐朽到荒凉
。