QT自定义控件实现一个车速表

QT 中通过自定义一个QWidget 来绘制一个车速表

车速表的绘制,网络上有很多可以参考的例子,本设计也是参考网上的例子加入一些新的功能实现显示车速,属性显示在页面,通过属性修改控件中相关的值。

首先需要绘制出来仪表盘,分成五个步骤来实现。 

    绘制背景 

                 通过绘制两个圆形,半径分别是radius和radius*0.9,使用不同的背景色。

           

 绘制刻度线

先设置一个起始角度Angle,两边对称,然后将其它的角度按照设定的最高车速均分。

   painter->rotate(Angle);

    double rotate = (double)(360 - (Angle * 2)) / 200;

     绘制出刻度线,两个等分绘制一个刻度,10份绘制一个长一点的线

  for (int i = 0; i <= 200; i++) {
        QColor color = QColor(84, 84, 84);
        if(i>120) color = QColor(250, 0, 0);
        if((i % 10) == 0)
        {
            painter->setPen(QPen(color, 1.3*lineWidth));
            painter->drawLine(0, r, 0, r / 1.2);
        }
        else if((i % 2) == 0)
        {
            painter->setPen(QPen(color, 1*lineWidth));
            painter->drawLine(0, r, 0, r / 1.1);
        }
        painter->rotate(rotate);
    }

       刻度上添加数字

             最高车速分成10份,总共显示10个数字。先要计算每一个数字的旋转角度。

 int gap = (360-Angle*2) / 10;

 再计算出每一个数字的坐标

       int angle = 90+Angle+gap*i;  //角度,10格子画一个刻度值

        float angleArc =( angle % 360) * 3.14 / 180; //转换为弧度
        int x = (r)*cos(angleArc);
        int y = (r)*sin(angleArc);

        QString speed = QString::number(i*20);
        int w = (int)fm.width(speed);
        int h = (int)fm.height();
        x = x - w/2;
        y = y + h/4;

        painter->drawText(QPointF(x, y),speed);

 绘制速度指针

           使用QPolygon 来构造一个多边形,然后根据角度来旋转。

   QPolygon pts;
    int r = radius*0.6;
    pts.setPoints(3, -2, 0, 2, 0, 0, r);

中心部分画出两个圆形出来。

   // 画中心圆圈
    QRadialGradient radial(0, 0, 14);  //渐变
    radial.setColorAt(0.0, QColor(100, 100, 100));
    radial.setColorAt(1.0, QColor(250, 50, 50));
    painter->setPen(Qt::NoPen);  //填满没有边界
    painter->setBrush(radial);
    painter->drawEllipse(-7, -7, 14, 14);

 绘制文字描述车速

    painter->setFont(QFont("Arial", 8));
    painter->setPen(QPen(QColor(255,255,255)));
    QFontMetricsF fm = QFontMetricsF(painter->font());
    QString speed = QString::number(percent) + " km/h";
    int w = (int)fm.width(speed);
 //   int h = (int)fm.height();
    painter->drawText(QPointF(-w/2, (int)(0.5*radius)),speed);

 最后贴出完整的代码:

#ifndef DASHBOARD_H
#define DASHBOARD_H

#include <QWidget>
# include<componentInterface.h>

class  dashboard: public componentInterface
{
    Q_OBJECT

    Q_PROPERTY(double minValue READ getMinValue WRITE setMinValue USER true)
    Q_PROPERTY(double maxValue READ getMaxValue WRITE setMaxValue USER true)
    Q_PROPERTY(double value READ getValue WRITE setValue USER true)

public:
    dashboard(QWidget *parent = nullptr);

    //获取和设置最小值
    double getMinValue() const;
    void setMinValue(double minValue);

    //获取和设置最大值
    double getMaxValue() const;
    void setMaxValue(double maxValue);

    void setValue(double ivalue) override;
    double getValue() const;

    QSize sizeHint() const override;
    QSize minimumSizeHint() const override;


    QString name()override {return "dashboard";};
    void setWindowTitle(const QString & value) override{ QWidget::setWindowTitle(value);};
    void move(int ax, int ay) override {QWidget::move(ax,ay);};
    void show() override{QWidget::show();};
    QMetaObject getQMeat() override {return this->staticMetaObject;};
    void setParent(QWidget * parent) override { QWidget::setParent(parent);};
    void setComponentIndex(int index) override {ID=index;}

private:
   void paintEvent(QPaintEvent *event) override;
   bool eventFilter(QObject *watched, QEvent *event)override;

   void drawBg(QPainter *painter);
   void drawDial(QPainter *painter);
   void drawScaleNum(QPainter *painter);
   void drawIndicator(QPainter *painter);
   void drawText(QPainter *painter);


private:
   const static int radius;
   double maxv;
   double minv;
   double percent {0};
   int m_refSize {200};
   int Angle =45;

   bool isPressed;         //鼠标是否按下
   QPoint lastPoint;       //鼠标按下最后坐标

   int ID {-1};

signals:
   void valueChanged(double value);
   void clicked(bool,QObject *);
   void doubleClicked();
   void customContextMenuRequested(const QPoint &pos);

};

#endif // DASHBOARD_H
#include "dashboard.h"
#include<QPainter>
#include <QCoreApplication>
#include <QtMath>
#include<QDebug>
#include<QMouseEvent>


const int dashboard::radius = 100;


dashboard::dashboard(QWidget *parent)
{

    maxv=200;
    minv=0;
    this->installEventFilter(this);
     QWidget::setParent(parent);
}

void dashboard::setValue(double ivalue)
{
    percent = ivalue;
    update();
    emit valueChanged(ivalue);
}

double dashboard::getValue() const
{
    return percent;
}

QSize dashboard::sizeHint() const
{
    return QSize(m_refSize, m_refSize);
}

QSize dashboard::minimumSizeHint() const
{
    return QSize(30, 10);
}

void dashboard::paintEvent(QPaintEvent *event)
{

    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

    float scale = qMin(width(),height());
    painter.scale(scale/m_refSize,scale/m_refSize);
    painter.translate(m_refSize/2,m_refSize/2); //设置坐标原点

    drawBg(&painter);
    drawDial(&painter);
    drawScaleNum(&painter);
    drawIndicator(&painter);
    drawText(&painter);

     QWidget::paintEvent(event);

}
void dashboard::drawBg(QPainter *painter)
{
     int r = radius;
     painter->save();
     painter->setPen(Qt::NoPen);
     painter->setBrush(QColor(172, 172, 172));
     painter->drawEllipse(-r, -r, r * 2, r * 2);

     r =  radius * 0.9;
     painter->setBrush(QColor(40, 40, 40));
     painter->setPen(Qt::NoPen);
     painter->drawEllipse(-r, -r, r * 2, r * 2);
     painter->restore();

}

void dashboard::drawDial(QPainter *painter)
{
    int r = radius*0.85;
    double lineWidth = 1;
    painter->save();

    painter->rotate(Angle);

    double rotate = (double)(360 - (Angle * 2)) / 200;

    for (int i = 0; i <= 200; i++) {
        QColor color = QColor(84, 84, 84);
        if(i>120) color = QColor(250, 0, 0);
        if((i % 10) == 0)
        {
            painter->setPen(QPen(color, 1.3*lineWidth));
            painter->drawLine(0, r, 0, r / 1.2);
        }
        else if((i % 2) == 0)
        {
            painter->setPen(QPen(color, 1*lineWidth));
            painter->drawLine(0, r, 0, r / 1.1);
        }
        painter->rotate(rotate);
    }

    painter->restore();
}

void dashboard::drawScaleNum(QPainter *painter)
{
    painter->save();

    int r = (int)(radius*0.6);

    painter->setFont(QFont("Arial", 9));
    painter->setPen(QPen(QColor(255,255,255)));
    QFontMetricsF fm = QFontMetricsF(painter->font());

    int gap = (360-Angle*2) / 10;
    for(int i=0; i<=10; i+=1)
    {
        int angle = 90+Angle+gap*i;  //角度,10格子画一个刻度值

        float angleArc =( angle % 360) * 3.14 / 180; //转换为弧度
        int x = (r)*cos(angleArc);
        int y = (r)*sin(angleArc);

        QString speed = QString::number(i*20);
        int w = (int)fm.width(speed);
        int h = (int)fm.height();
        x = x - w/2;
        y = y + h/4;

        painter->drawText(QPointF(x, y),speed);
    }
    painter->restore();
}

void dashboard::drawIndicator(QPainter *painter)
{
    painter->save();
    QPolygon pts;
    int r = radius*0.6;
    pts.setPoints(3, -2, 0, 2, 0, 0, r);
    double degRotate =Angle +  (360.0 - Angle - Angle) / 200 * percent;

    //画指针
    painter->rotate(degRotate);
    QRadialGradient haloGradient(0, 0, 60, 0, 0);  //辐射渐变,内部填充颜色
    haloGradient.setColorAt(0, QColor(100, 100, 100));
    haloGradient.setColorAt(1, QColor(250, 50, 50)); //red
    painter->setPen(QColor(250, 150, 150)); // 边框颜色
    painter->setBrush(haloGradient);
    painter->drawConvexPolygon(pts);
 //   painter->restore();
   // painter->save();

    // 画中心圆圈
    QRadialGradient radial(0, 0, 14);  //渐变
    radial.setColorAt(0.0, QColor(100, 100, 100));
    radial.setColorAt(1.0, QColor(250, 50, 50));
    painter->setPen(Qt::NoPen);  //填满没有边界
    painter->setBrush(radial);
    painter->drawEllipse(-7, -7, 14, 14);

    painter->restore();
}

void dashboard::drawText(QPainter *painter)
{
    painter->save();

    painter->setFont(QFont("Arial", 8));
    painter->setPen(QPen(QColor(255,255,255)));
    QFontMetricsF fm = QFontMetricsF(painter->font());
    QString speed = QString::number(percent) + " km/h";
    int w = (int)fm.width(speed);
 //   int h = (int)fm.height();
    painter->drawText(QPointF(-w/2, (int)(0.5*radius)),speed);
    painter->restore();
}

bool dashboard::eventFilter(QObject *watched, QEvent *event)
{
    QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
    if (event->type() == QEvent::MouseButtonPress) {
        //限定鼠标左键
        if (mouseEvent->button() == Qt::LeftButton) {
            lastPoint = mouseEvent->pos();
            isPressed = true;
            emit clicked(isPressed,this);
            return true;
        }
        else if (mouseEvent->button() == Qt::RightButton)
        {
            isPressed = true;
            emit clicked(isPressed,this);

            emit customContextMenuRequested ( mouseEvent->pos());
        }
    } else if (event->type() == QEvent::MouseMove) {
        //允许拖动并且鼠标按下准备拖动
        if (isPressed) {

            int offsetX = mouseEvent->pos().x() - lastPoint.x();
            int offsetY = mouseEvent->pos().y() - lastPoint.y();
            int x = this->x() + offsetX;
            int y = this->y() + offsetY;
            if (true) {
                //可以自行调整限定在容器中的范围,这里默认保留20个像素在里面
                int offset = 20;
                bool xyOut = (x + this->width() < offset || y + this->height() < offset);
                bool whOut = false;
                QWidget *w = (QWidget *)this->parent();
                if (w) {
                    whOut = (w->width() - x < offset || w->height() - y < offset);
                }
                if (xyOut || whOut) {
                    return false;
                }
            }

            this->move(x, y);
            return true;
        }
    } else if (event->type() == QEvent::MouseButtonRelease) {
        isPressed = false;
    }

   return QWidget::eventFilter(watched, event);
}

double dashboard::getMinValue() const
{
    return minv;
}

void dashboard::setMinValue(double minValue)
{
   minv=minValue;
}

double dashboard::getMaxValue() const
{
    return maxv;
}

void dashboard::setMaxValue(double maxValue)
{
   maxv=maxValue;

}
#ifndef COMPONENTINTERFACE_H
#define COMPONENTINTERFACE_H
#include<QString>
#include <QWidget>
#include<QtCore>

class componentInterface : public QWidget
{
public:
   virtual ~componentInterface(){};
   virtual  QString name()=0;
   virtual void setValue(double ivalue)=0;
   virtual  void setWindowTitle(const QString &)=0;
   virtual void move(int ax, int ay)=0;
   virtual  void show()=0;
   virtual QMetaObject getQMeat()=0;
   virtual void setParent(QWidget * parent)=0;

   virtual void setComponentIndex(int index)=0;
    virtual int getComponentIndex()=0;
 //  virtual void clicked(bool,QWidget*)=0;


};

#endif // COMPONENTINTERFACE_H

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QT是一种跨平台的图形用户界面开发框架,允许开发者创建各种自定义控件。其中的一个自定义控件就是盘,可以用来展示时间、进度或其他指示器。 QT自定义控件盘的实现可以通过继承QAbstractSlider类来实现。首先,我们需要定义一个继承自QWidget的类,这个类将成为我们自定义盘控件的主窗口。在这个类中,我们可以添加各种用于展示盘的元素,比如指针、刻度、数字等。 接下来,在主窗口类的构造函数中,我们可以设置一些控件的基本属性,比如大小、位置、样式等。然后,可以创建QPainter对象并使用它来绘制各种盘元素。绘制过程中,我们可以使用QPainter的API来画出指针、刻度线、数字等等。 为了实现盘的交互功能,我们可以重写主窗口类的一些事件处理函数,比如鼠标按下、移动、释放事件等。通过这些事件处理函数,我们可以改变盘的显示状态,比如旋转指针、更新数值等等。 除了绘制和交互功能,我们还可以通过添加信号和槽来实现盘和外部代码的交互。比如,我们可以在盘被点击时发送一个信号,让外部的槽函数来处理相应的逻辑。 总之,通过QT自定义控件功能,我们可以方便地创建各种定制化的盘控件。通过继承QAbstractSlider类,定义绘制元素、处理事件和信号、槽函数等,我们可以实现一个完整的、交互性强的盘控件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值