Qt 自绘控件--如何在指定位置显示控件

本文档介绍了一个名为WaterProgressBar的自定义控件,该控件继承自QWidget,用于显示带有水波纹效果的进度条。通过使用setGeometry()设置控件的位置和大小,并利用鼠标事件实现拖动调整进度。代码中详细实现了波浪形进度条的绘制,包括波浪的动画效果、数值显示和背景绘制。此外,还提供了鼠标按下、释放和移动事件的处理,使得用户可以通过拖动来改变进度值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用法:

QWidget的话:setGeometry()
Item的话:setPos()

一般大家用的都是 QWidget,所以这里只对 setGeometry() 解释一下
官方文档对 setGeometry() 的解释是:

在这里插入图片描述

用法其实很简单:

  • x、y 是控件的横纵坐标
  • w、h 是控件的宽和高
#ifndef WATERPROGRESSBAR_H
#define WATERPROGRESSBAR_H

#include <QWidget>

class WaterProgressBar : public QWidget//继承QWidget
{
    Q_OBJECT
public:
    explicit WaterProgressBar(QWidget *parent = nullptr);

    void setVaule(int value);

public slots:
    void updaterWater();//定时更新,让波浪动起来

protected:
    void paintEvent(QPaintEvent *event) override;//自绘控件
    //实现左右拖动改变value
    void mousePressEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;

private:
    int m_value;
    qreal m_offset;

    bool m_isPressed;
    QPoint m_startPoint;

    void drawWater(QPainter* painter);//画水波浪
    void drawText(QPainter* painter);//画中间数值
    void drawBg(QPainter* painter);//画背景
};

#endif // WATERPROGRESSBAR_H
#include "WaterProgressBar.h"
#include <QPainter>
#include <QtMath>
#include <QTimer>
#include <QMouseEvent>

WaterProgressBar::WaterProgressBar(QWidget *parent) : QWidget(parent)
{
    m_value = 0;
    m_offset = 0;

    m_isPressed = false;

    QTimer *timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &WaterProgressBar::updaterWater);
    timer->start(30);//定时30毫秒
}

void WaterProgressBar::setVaule(int value)
{
    m_value = value;
    update();
}

void WaterProgressBar::updaterWater()
{
    m_offset=m_offset+0.15;//波浪偏移
    if (m_offset >= 360)
        m_offset = 0;
    update();
}

void WaterProgressBar::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event)
    int width = this->width();
    int height = this->height();
    int side = qMin(width, height);

    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);//设置抗锯齿
    painter.translate(width / 2, height / 2);//设置坐标中心为控件中心
    painter.scale(side / 200.0, side / 200.0);//设置坐标系拉伸为200*200

    drawBg(&painter);//画背景
    drawWater(&painter);//画水波浪
    drawText(&painter);//画中间数值
}

void WaterProgressBar::drawWater(QPainter* painter)
{
    int radius = 100;//坐标系高度,上为-,下为+

    if (m_value == 0){//没波浪,不用画
        return;
    }
    else if (m_value == 100) {//波浪满,直接画圆
        painter->save();
        painter->setPen(Qt::NoPen);
        painter->setBrush(QBrush(QColor(100, 180, 250, 230)));
        painter->drawEllipse(QRect(-radius, -radius, radius*2, radius*2));
        painter->restore();
    }
    else//画波浪
    {
        int height = 2*(-m_value+50);//波浪在坐标系中的高度位置
        painter->save();
        QPainterPath wavePath; //波浪区域
        QPainterPath wavePath2; //波浪区域
        wavePath.moveTo(-radius, radius);//第一点坐标为(0,height);
        for(int x = -radius; x < radius; x++)  //x从0~w的值而改变,从而得到正弦曲线
        {
            double waveY = 4*qSin(1.8*(x*M_PI/180 + m_offset)) + height;// waveY随着x的值改变而改变,从而得到正弦曲线
            wavePath.lineTo(x, waveY);   //从上一个绘制点画一条线到(x,waveY);
        }
        wavePath.lineTo(radius, radius); //右下角,坐标(width, height),移动到右下角结束点,整体形成一个闭合路径

        wavePath2.moveTo(-radius, radius);//第一点坐标为(0,height);
        for(int x = -radius; x < radius; x++)  //x从0~w的值而改变,从而得到正弦曲线
        {
            double waveY = 4*qSin(1.8*(x*M_PI/180 + m_offset + 2)) + height;// waveY随着x的值改变而改变,从而得到正弦曲线
            wavePath2.lineTo(x, waveY);   //从上一个绘制点画一条线到(x,waveY);
        }
        wavePath2.lineTo(radius, radius); //右下角,坐标(width, height),移动到右下角结束点,整体形成一个闭合路径

        QPainterPath bigPath;
        bigPath.addEllipse(QRect(-radius, -radius, radius*2, radius*2));
        wavePath = bigPath.intersected(wavePath);
        wavePath2 = bigPath.intersected(wavePath2);

        painter->setPen(Qt::NoPen);
        painter->setBrush(QBrush(QColor(100, 184, 255, 80)));
        painter->drawPath(wavePath);      //绘制路径
        painter->setBrush(QBrush(QColor(100, 180, 250, 230)));
        painter->drawPath(wavePath2);      //绘制路径
        painter->restore();
    }
}

void WaterProgressBar::drawText(QPainter* painter){
    int radius = 40;
    painter->save();
    QString text = QString("%1%").arg(m_value);
    QFont font = painter->font();
    font.setPixelSize(40);
    painter->setFont(font);
    QPen pen = painter->pen();
    pen.setColor(Qt::white);
    pen.setWidth(4);
    painter->setPen(pen);
    QRect rect(-radius,-radius,radius*2,radius*2);
    painter->drawText(rect,Qt::AlignCenter,text);
    painter->restore();
}

void WaterProgressBar::drawBg(QPainter* painter){
    int outRadius = 100;
    painter->save();
    painter->setPen(Qt::NoPen);
    painter->setBrush(QColor(40,40,40));
    QRect rect(-outRadius,-outRadius,outRadius*2,outRadius*2);
    painter->drawEllipse(rect);
    painter->restore();
}

void WaterProgressBar::mousePressEvent(QMouseEvent *event)
{
    m_isPressed = true;
    m_startPoint = event->pos();
}

void WaterProgressBar::mouseReleaseEvent(QMouseEvent *event)
{
    Q_UNUSED(event)
    m_isPressed = false;
}

void WaterProgressBar::mouseMoveEvent(QMouseEvent *event)
{
    if (m_isPressed)
    {
        if (m_startPoint.x()<=0 || m_startPoint.x()>=width())
        {
            m_startPoint = event->pos();
            return;
        }
        if (event->pos().x() > m_startPoint.x())
        {
            int addVaule = qCeil((100-m_value)*1.0/(width()-m_startPoint.x()));
            if (m_value < 100)
                setVaule(m_value+addVaule);
        }
        else if (event->pos().x() < m_startPoint.x()){
            int addVaule = qCeil(m_value*1.0/m_startPoint.x());
            if (m_value > 0)
                setVaule(m_value-addVaule);
        }
        m_startPoint = event->pos();
    }
}
#include "widget.h"
#include "ui_widget.h"
#include "waterprogressbar.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    WaterProgressBar *w = new WaterProgressBar();  //创建 WaterProgressBar 对象
    w->setGeometry(rect().x()+200, rect().y()+10, 
                   100, 300); //设置大小
    w->setParent(this); //设置父窗口

   
}

Widget::~Widget()
{
    delete ui;
}
#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值