Qt自定义控件 -- 仪表盘01

转自:https://blog.csdn.net/baidu_33850454/article/details/81773323

 

简介

本文介绍一种绘制仪表盘的方法,整个仪表盘均采用绘制的方式实现,可自由伸缩大小。
本案例还加入了一个里程表,但是里程表不支持放大和缩小。
这里写图片描述

实现原理

绘制共分为边框、刻度、数字、数字速度(可选)、指针这几部分组成,后绘制的部分会覆盖之前绘制的部分。
共有以下几个要点需要注意:
1、整个页面的是相对大小为200*200,为了保证拉伸窗口时表盘随之拉伸或压缩,需要对坐标系统进行缩放;

painter.scale(scale/m_refSize,scale/m_refSize);

2、将坐标原点设置在表盘中心可以方便对各元素位置的计算;
painter.translate(m_refSize/2,m_refSize/2);
3、绘制表盘刻度数字的时候,需要注意坐标系的Y轴正方向向下,需要在Y值坐标前面添加负号;


绘制函数如下:void paintEvent(QPaintEvent */*event*/)
paintEvent()是一个父类中的虚函数,函数会在任何页面需要重绘的时候被自动调用,来绘制窗口。所有带有自定义内容的窗口都必须重新实现该函数。使用QPainter进行自定义绘制只能在paintEvent()函数或paintEvent()调用的函数中进行。
可以手动调用update()或者repaint()函数来立刻通知系统调用paintEvent()函数,但是通常update()能获得更好的显示效果,因为它允许Qt进行速度优化和最小的闪烁。

void MainWindow::paintEvent(QPaintEvent */*event*/)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    float scale = qMin(width(),height());
    //设置缩放比例和原点的先后顺序很重要
    painter.scale(scale/m_refSize,scale/m_refSize);
    painter.translate(m_refSize/2,m_refSize/2); //设置坐标原点

    drawFrame(painter); //绘制边框
    drawDividing(painter);//绘制刻度
    drawNumberIndicator(painter);//绘制指示数字
    drawNumberSpeed(painter);//显示数字速度
    drawIndicator(painter);//绘制速度指针
//    QPoint pos = m_wgt_mileage->mapFromParent(QPoint(-m_wgt_mileage->width()/2,40));

    m_wgt_mileage->setGeometry((width() - m_wgt_mileage->width()) / 2 + 30,height() - m_wgt_mileage->height() - 60,m_wgt_mileage->width(),m_wgt_mileage->height());

}

边框绘制 drawFrame(QPainter &painter)

将画笔设置为Qt::NoPen 可以去掉边框外围的边界线,否则会有一圈黑色的轮廓。
这里绘制两个圆,互相重叠,形成一个圆环,同时使用了渐变。

void MainWindow::drawFrame(QPainter &painter)
{
    painter.save();
    painter.setPen(Qt::NoPen);//确保没有边框线----填满,不留边界线
    QLinearGradient lg1(-m_radius,-m_radius,m_radius,m_radius);//渐变区域
    lg1.setColorAt(0.1,Qt::white);
    lg1.setColorAt(1,Qt::black);
//    lg1.setSpread(QGradient::ReflectSpread);//渐变样式
    painter.setBrush(lg1);
    painter.drawEllipse(-m_radius,-m_radius,m_refSize,m_refSize);

    painter.setBrush(Qt::black);
    painter.drawEllipse(QPoint(0,0),90,90);
    painter.restore();
}

绘制数字 drawNumberIndicator(QPainter &painter)

每隔20KM/H绘制一个标示;

//绘制数字指示
void MainWindow::drawNumberIndicator(QPainter &painter)
{
    painter.save();

    painter.setPen(Qt::white);

    double x,y;
    double angle, angleArc;
    double w,h;
    QFontMetricsF fm(this->font());

    for (int i = m_minSpeed; i <= m_maxSpeed; i+= 20)//每隔20Km设置一个数字
    {
        angle = 360 - (m_startAngle + (i - m_minSpeed) * m_anglePerVel); //角度
        angleArc = angle * 3.14 / 180; //转换为弧度

        x = 65 * cos(angleArc);//65是一个不断调整后得出的值,不用太在意
        y = -65 * sin(angleArc); // 负号的意义在于 Y轴正方向向下

        QString speed = QString::number(i);

        if (i % 20 == 0)
        {
            w = fm.width(speed);
            h = fm.height();
            painter.drawText(QPointF(x - w / 2,y + h/4),speed);
        }
    }

    painter.restore();
}

绘制刻度 drawDividing(QPainter &painter)

//绘制刻度
void MainWindow::drawDividing(QPainter &painter)
{
    painter.save();
    painter.rotate(m_startAngle);//将坐标系顺时针旋转150°,到达起始位置

    QPen pen(Qt::white);
    painter.setPen(pen);

    int step = (m_maxSpeed - m_minSpeed) / 5;
    double angleStep = (360.0 - (m_startAngle - m_endAngle)) / step;

    for (int i = m_minSpeed; i <= m_maxSpeed; i += 5)
    {
        if (i >= 140){ //绘制红色
            pen.setColor(Qt::red);
            painter.setPen(pen);
        }

        if (i % 20 == 0){//粗线
            pen.setWidth(2);
            painter.setPen(pen);
            painter.drawLine(88,0,75,0);

        }else if (i % 10 == 0){//中等
            pen.setWidth(1);
            painter.setPen(pen);
            painter.drawLine(88,0,80,0);

        }else if (i % 5 == 0){ //短线
            pen.setWidth(0);
            painter.setPen(pen);
            painter.drawLine(83,0,80,0);
        }
        painter.rotate(angleStep);
    }

    painter.restore();
}

绘制数字式速度 drawNumberSpeed(QPainter &painter)

void MainWindow::drawNumberSpeed(QPainter &painter)
{
    painter.save();
    painter.setPen(Qt::white);
    QString speed = QString("%1 KM/H").arg(m_curSpeed);
    QFontMetricsF fm(this->font());
    qreal w = fm.size(Qt::TextSingleLine,speed).width();
    painter.drawText(-w/2,-20,speed);

    painter.restore();
}

绘制指针 drawIndicator(QPainter &painter)

这里根据当前速度计算当前指针的角度,然后旋转坐标系到当前角度。最后绘制指针和旋转中心。

void MainWindow::drawIndicator(QPainter &painter)
{
    painter.save();
    //绘制指针

    double curAngle = m_startAngle + m_curSpeed * m_anglePerVel;
    painter.rotate(curAngle); //旋转坐标系

    QRadialGradient haloGradient(0, 0, 60, 0, 0);  //辐射渐变
    haloGradient.setColorAt(0, QColor(60,60,60));
    haloGradient.setColorAt(1, QColor(160,160,160)); //灰
    painter.setPen(Qt::white); //定义线条文本颜色  设置线条的颜色
    painter.setBrush(haloGradient);//刷子定义形状如何填满 填充后的颜色

    static const QPointF points[3] = {
        QPointF(0.0, 2),
        QPointF(0.0, -2),
        QPointF(70.0, 0),
    };
    painter.drawPolygon(points,3); //绘制指针
    painter.restore();

    painter.save();
    //绘制旋转中心
    QRadialGradient rg(0,0,10);
    rg.setColorAt(0.0,Qt::darkGray);
    rg.setColorAt(0.5,Qt::white);
    rg.setColorAt(1.0,Qt::darkGray);
    painter.setPen(Qt::NoPen);
    painter.setBrush(rg);
    painter.drawEllipse(QPoint(0,0),5,5);

    painter.restore();
}

时间仓促,可能存在纰漏。如有疑问欢迎与我交流!flist_liu@163.com
源码下载:https://download.csdn.net/download/baidu_33850454/10610033
参考链接:https://blog.csdn.net/osean_li/article/details/55057690

好用控件:https://blog.csdn.net/ren1027538427/article/details/52450294

https://blog.csdn.net/zhangxiaoyu_sy/article/details/78925221

旋转仪表盘是一种常见的显示控件,可以用来展示一些数据,如速度、油量、温度等,下面我将介绍如何使用Qt编写一个旋转仪表盘控件。 首先,我们需要在Qt中创建一个新的自定义控件类。可以通过Qt Creator中的“添加新文件”功能来创建一个QWidget派生类。在这个类中,我们需要实现paintEvent()函数来绘制仪表盘。 在paintEvent()函数中,我们可以使用QPainter来绘制仪表盘的各个部分,包括刻度线、指针、文字等。具体实现可以参考以下代码: ```C++ void RotatingDial::paintEvent(QPaintEvent *event) { // 设置背景色 QPalette pal(palette()); pal.setColor(QPalette::Background, Qt::white); setAutoFillBackground(true); setPalette(pal); // 绘制刻度线 QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); painter.translate(width() / 2, height() / 2); painter.setPen(QPen(Qt::black, 2)); for (int i = 0; i < 60; i++) { painter.drawLine(0, -100, 0, -90); painter.rotate(6); } // 绘制指针 painter.save(); painter.rotate(m_angle); painter.setBrush(Qt::red); painter.setPen(Qt::NoPen); painter.drawConvexPolygon(m_pointer, 3); painter.restore(); // 绘制文字 QFont font("Arial", 12, QFont::Bold); painter.setFont(font); painter.drawText(-30, 50, "Speed"); } ``` 在上面的代码中,我们首先设置了控件的背景色为白色。然后使用QPainter绘制了60条刻度线,并旋转6度。接着,我们绘制了一个红色的指针,并根据m_angle属性来旋转指针的角度。最后,我们使用QPainter绘制了文字“Speed”。 在我们的自定义控件中,我们需要一个属性来控制指针的角度。我们可以使用Q_PROPERTY宏来定义这个属性,例如: ```C++ class RotatingDial : public QWidget { Q_OBJECT Q_PROPERTY(int angle READ angle WRITE setAngle) public: RotatingDial(QWidget *parent = nullptr); int angle() const; void setAngle(int angle); private: int m_angle; QPolygon m_pointer; }; ``` 在上面的代码中,我们使用Q_PROPERTY宏定义了angle属性,并提供了getter和setter函数。我们还定义了一个私有变量m_angle来存储当前的角度,以及一个QPolygon对象m_pointer来存储指针的形状。 在setAngle()函数中,我们设置m_angle属性,并根据新的角度计算指针的位置: ```C++ void RotatingDial::setAngle(int angle) { if (angle != m_angle) { m_angle = angle; m_pointer.setPoint(0, QPoint(0, -90)); m_pointer.setPoint(1, QPoint(5, 0)); m_pointer.setPoint(2, QPoint(-5, 0)); m_pointer.translate(0, 100); update(); } } ``` 在上面的代码中,我们首先判断新的角度是否与当前的角度相同。如果不同,我们就更新m_angle属性,并重新计算指针的位置。最后,我们调用update()函数来触发paintEvent()函数的调用,从而完成控件的重绘。 最后,我们可以在MainWindow类中使用我们的自定义控件,例如: ```C++ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { RotatingDial *dial = new RotatingDial(this); dial->setAngle(30); QHBoxLayout *layout = new QHBoxLayout; layout->addWidget(dial); setCentralWidget(new QWidget); centralWidget()->setLayout(layout); } ``` 在上面的代码中,我们创建了一个RotatingDial对象,并设置了初始角度为30度。然后,将其添加到QHBoxLayout布局中,并设置为主窗口的中央控件。 至此,我们已经完成了一个简单的旋转仪表盘自定义控件。你可以根据需要对其进行扩展和优化,使其更加适合你的应用场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值