Qt基于paintEvent自定义CharView

news2025/1/12 16:14:27

Qt基于paintEvent自定义CharView

鼠标拖动,缩放,区域缩放, 针对x轴,直接上代码
请添加图片描述

charview.h

#ifndef CHARVIEW_H
#define CHARVIEW_H

#include <QWidget>
#include <QPainter>
#include <QPaintEvent>
#include <QResizeEvent>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QPointF>

class ScaleNode
{
public:
    QPointF pointScaleOne;
    QPointF pointScaleTwo;
    QPointF pointScaleText;
    double scaleValue;
    bool bShowScaleText;
    ScaleNode* nextNode;
    ScaleNode(){
        bShowScaleText = false;
        nextNode = nullptr;
    }
};

class CharView: public QWidget
{
public:
    CharView(QWidget *parent = nullptr);
    ~CharView();

    virtual void paintAxisX(QPainter &painter);
    virtual void paintAxisY(QPainter &painter);
    virtual void paintCursor(QPainter &painter);
    virtual void paintData(QPainter &painter);
    virtual void paintMouseRightMove(QPainter &painter);


    void UpdeScaleNode();
    void InitScaleNode();
    void MouseLeftMoveUpdateStartEndValue();//鼠标左键拖动更新
    void MouseRightMoveUpdateStartEndValue();//鼠标右键选择更新
    void MouseWheelUpdateStartEndValue(int flag);//鼠标缩放更新

private:
    void DeleteNode(ScaleNode* node);
protected:
    virtual void paintEvent(QPaintEvent* event) override;
    virtual void resizeEvent(QResizeEvent* event) override;
    virtual void mouseMoveEvent(QMouseEvent* event) override;
    virtual void mousePressEvent(QMouseEvent* event) override;//鼠标左键按住拖动移动, 右键区域放大
    virtual void mouseReleaseEvent(QMouseEvent* event) override;
    virtual void wheelEvent(QWheelEvent* event) override;//滚动鼠标滑轮放大缩小
    virtual void mouseDoubleClickEvent(QMouseEvent* event) override;//双击恢复默认

public:
    int leftBorder;
    int topBorder;
    int rightBorder;
    int bottomBorder;

    double scaleValue;
    int scaleLength;//刻度线高度
    int scaleTextScaleLength;//带text的刻度线高度
    int scaleTextHeight;//刻度text高度
    int scaleTextWidth;//刻度text宽度
    int scaleTextBorder;//刻度text边距
    int scaleCnt;//刻度数量
    double scaleWidth;//刻度宽度
    int scaleCntShowText;//每多少个刻度显示刻度text
    double startScaleValueInit;//默认刻度开始值
    double endScaleValueInit;//默认刻度结束值
    double startScaleValue;//当前刻度开始值
    double endScaleValue;//当前刻度结束值
    double everyWidthValue;//每个宽度的值

    ScaleNode* scaleNodeBegin;//第一个刻度
    QPointF currentPointF;//当前鼠标位置
    bool bShowCursor;//是否实现游标
    bool bPressLeft;//是否鼠标左键按下
    bool bPressRight;//是否鼠标右键按下
    QPointF pressPointF;//鼠标左键按下时坐标
    bool bPressRightMove;//鼠标是否按下移动


};

#endif // CHARVIEW_H

CharView.cpp

#include "charview.h"


#include <QDebug>
CharView::CharView(QWidget *parent):
    QWidget(parent)
{
    setMouseTracking(true);
    setStyleSheet("background-color:rgb(255,255,255);");
    InitScaleNode();
}

CharView::~CharView()
{
    DeleteNode(scaleNodeBegin);
}

void CharView::DeleteNode(ScaleNode *node)
{
    if(node->nextNode)
        DeleteNode(node->nextNode);
    delete node;
    node = nullptr;
}

void CharView::UpdeScaleNode()
{
    scaleValue = ((double)(endScaleValue - startScaleValue))/scaleCnt;
    scaleWidth = ((double)(width() - leftBorder - rightBorder))/scaleCnt;
    everyWidthValue = ((double)(endScaleValue - startScaleValue))/(width() - leftBorder - rightBorder);

    ScaleNode* node = scaleNodeBegin;
    int var=0;
    while(node){

        node->pointScaleOne = QPointF(leftBorder + var*scaleWidth, height() - bottomBorder);
        node->pointScaleTwo = QPointF(leftBorder + var*scaleWidth, height() - bottomBorder - scaleLength);
        node->pointScaleText = QPointF(leftBorder + var*scaleWidth - scaleTextWidth/2,  height() - bottomBorder + scaleTextBorder);
        node->scaleValue = startScaleValue + var*scaleValue;
        if(var%scaleCntShowText == 0)
        {
            node->pointScaleTwo = QPointF((double)(leftBorder + var*scaleWidth), height() - bottomBorder - scaleTextScaleLength);
            node->bShowScaleText = true;
        }

        var++;
        node = node->nextNode;
    }

}

void CharView::InitScaleNode()
{
    bPressRightMove = false;
    bPressLeft = false;
    bPressRight = false;
    bShowCursor = true;

    leftBorder = 50;
    topBorder = 10;
    rightBorder = 50;
    bottomBorder = 20;

    scaleCntShowText = 5;
    startScaleValueInit = 0;
    endScaleValueInit = 3000000000;
    startScaleValue = startScaleValueInit;
    endScaleValue = endScaleValueInit;
    scaleCnt = 30;
    scaleLength = 2;
    scaleTextScaleLength = 4;
    scaleTextBorder = 5;
    scaleTextWidth = 100;
    scaleTextHeight = fontMetrics().height();

    ScaleNode* nodeTmp=nullptr;
    for (int var = 0; var <= scaleCnt; ++var) {
        ScaleNode* node = new ScaleNode;
        if(nodeTmp)
            nodeTmp->nextNode = node;
        nodeTmp = node;
        if(var == 0)
            scaleNodeBegin = node;
    }
}

void CharView::MouseWheelUpdateStartEndValue(int flag)
{
    double zoomValue = (endScaleValue - startScaleValue)/10;
    if(flag > 0)
    {
        endScaleValue -= zoomValue;
    }
    else{
        endScaleValue += zoomValue;
    }
    double everyWidthValueOld = everyWidthValue;
    double centerX = currentPointF.x() - leftBorder;
    everyWidthValue = ((double)(endScaleValue - startScaleValue))/(width() - leftBorder - rightBorder);
    startScaleValue = startScaleValue + centerX*everyWidthValueOld - centerX*everyWidthValue ;
    endScaleValue = endScaleValue + centerX*everyWidthValueOld - centerX*everyWidthValue ;
    if(startScaleValue <=0)
        startScaleValue = 0;
}

void CharView::MouseLeftMoveUpdateStartEndValue()
{
    double offsetX  =  currentPointF.x() - pressPointF.x();
    pressPointF = currentPointF;
    double offsetValue = offsetX*everyWidthValue;

    if(startScaleValue - offsetValue <=0 && offsetX > 0){
        startScaleValue = 0;
        offsetValue = startScaleValue;
    }else{
        startScaleValue = startScaleValue - offsetValue;
    }
    endScaleValue = endScaleValue - offsetValue;

}

void CharView::MouseRightMoveUpdateStartEndValue()
{
    if(currentPointF.x() < leftBorder || currentPointF.x() > width() - rightBorder ||
       pressPointF.x() < leftBorder || pressPointF.x() > width() - rightBorder|| !bPressRight)
        return;
    endScaleValue = startScaleValue + (currentPointF.x() - leftBorder)*everyWidthValue;
    startScaleValue = startScaleValue + (pressPointF.x() - leftBorder)*everyWidthValue;
}

void CharView::paintEvent(QPaintEvent *event)
{
    //界面大小改变,只改变刻度实际宽度, 刻度开始结束值不变
    //鼠标缩放,刻度实际宽度改变, 刻度开始结束值改变
    //鼠标拖动,刻度实际宽度不变, 刻度开始结束值改变

    //绘制前计算更新刻度
    UpdeScaleNode();

    QPainter painter(this);
   // painter.setRenderHint(QPainter::Antialiasing);//加上会加粗

    //绘制游标
    paintAxisX(painter);
    paintAxisY(painter);

    //绘制数据
    paintData(painter);

    paintMouseRightMove(painter);
    //绘制游标
    if(bShowCursor)
        paintCursor(painter);
}

void CharView::paintMouseRightMove(QPainter &painter)
{
    if(currentPointF.x() < leftBorder || currentPointF.x() > width() - rightBorder ||
       pressPointF.x() < leftBorder || pressPointF.x() > width() - rightBorder|| !bPressRight)
        return;
    QPen pen;
    pen.setStyle(Qt::DashLine);
    pen.setColor(QColor(236,132,251));
    pen.setWidth(1);
    painter.setPen(pen);

    double w = currentPointF.x() - pressPointF.x();
    double y = currentPointF.y() - pressPointF.y();

    painter.drawRect(pressPointF.x(),pressPointF.y(), w, y);
}

void CharView::paintAxisX(QPainter &painter)
{
    QPen pen;
    pen.setStyle(Qt::SolidLine);
    pen.setColor(Qt::black);
    pen.setWidth(1);
    painter.setPen(pen);

    int y = height() - bottomBorder;
    painter.drawLine(QPointF(leftBorder, y),
                     QPointF(width() - rightBorder, y));
    ScaleNode* node = scaleNodeBegin;
    while(node){

        painter.drawLine(node->pointScaleOne,node->pointScaleTwo);

        if(node->bShowScaleText)
            painter.drawText(node->pointScaleText.x(), node->pointScaleText.y(), scaleTextWidth, scaleTextHeight,
                         Qt::AlignCenter, QString::number(node->scaleValue, 'f', 0));

        node = node->nextNode;
    }
}

void CharView::paintAxisY(QPainter &painter)
{

}

void CharView::paintCursor(QPainter &painter)
{
    if(currentPointF.x() < leftBorder || currentPointF.x() > width() - rightBorder)
        return;
    QPen pen;
    pen.setStyle(Qt::DashLine);
    pen.setColor(QColor(236,132,251));
    pen.setWidth(1);
    painter.setPen(pen);


    painter.drawLine(QPointF(currentPointF.x(), 0), QPointF(currentPointF.x(), height() - bottomBorder));


    double number = (currentPointF.x() - leftBorder)*everyWidthValue + startScaleValue;
    painter.drawText(currentPointF.x(), height() - bottomBorder - scaleTextHeight, scaleTextWidth, scaleTextHeight,
                     Qt::AlignLeft, QString::number(number, 'f', 0));
}

void CharView::paintData(QPainter &painter)
{
    //test
    double value1 = 1240000000;
    double value2 = 1590000000;
    double x1 = leftBorder + (value1 - startScaleValue)/everyWidthValue;
    double x2 = leftBorder + (value2 - startScaleValue)/everyWidthValue;

    QPointF point1(x1, 100);
    QPointF point2(x2, 200);

    QPen pen;
    pen.setStyle(Qt::SolidLine);
    pen.setColor(Qt::black);
    pen.setWidth(1);
    painter.setPen(pen);

    painter.drawLine(point1,point2);
}

void CharView::resizeEvent(QResizeEvent *event)
{
    UpdeScaleNode();
    return QWidget::resizeEvent(event);
}

void CharView::mouseMoveEvent(QMouseEvent *event)
{
    currentPointF = event->localPos();
    if(bPressLeft){
       if(currentPointF != pressPointF)
            MouseLeftMoveUpdateStartEndValue();
    }
    else if(bPressRight){
        bPressRightMove = true;
    }
    update();
    return QWidget::mouseMoveEvent(event);
}

void CharView::mousePressEvent(QMouseEvent *event)
{
    if(!bPressLeft && event->button() == Qt::LeftButton){
        bPressLeft = true;
        pressPointF = event->localPos();
    }
    else if(!bPressRight && event->button() == Qt::RightButton){
        bPressRight = true;
        pressPointF = event->localPos();
    }
    return QWidget::mousePressEvent(event);
}

void CharView::mouseReleaseEvent(QMouseEvent *event)
{
    if(bPressRight)
    {
        if(bPressRightMove && currentPointF != pressPointF)
            MouseRightMoveUpdateStartEndValue();
        bPressRight = false;
        bPressRightMove = false;
        update();
    }
    bPressLeft = false;
    return QWidget::mouseReleaseEvent(event);
}

void CharView::wheelEvent(QWheelEvent *event)
{
    MouseWheelUpdateStartEndValue(event->delta());
    update();
    return QWidget::wheelEvent(event);
}

void CharView::mouseDoubleClickEvent(QMouseEvent *event)
{
    startScaleValue = startScaleValueInit;
    endScaleValue = endScaleValueInit;
    return QWidget::mouseDoubleClickEvent(event);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1016995.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kotlin使用infix关键字构建高可读性代码

自从Google推出Kotlin作为官方开发语言后&#xff0c;一堆像我这样的习惯Java开发的程序员从不习惯到爱上这门语言只用了很短的时间&#xff0c;相比于Java语言&#xff0c;kotlin集各家所长&#xff0c;可以使用更少的代码&#xff0c;实现更多更复杂的需求&#xff0c;而且可…

腾讯mini项目-【指标监控服务重构】2023-08-18

今日已办 watermill 将 key 设置到 message 中 修改 watermill-kafka 源码 将 key 设置到 message.metadata中 接入 otel-sdk 添加 middleware resolveUpstreamCtx 解析上游上下文&#xff0c;开启根Span添加 middleware middleware.InstantAck - 马上ACK&#xff0c;使得多…

怒刷LeetCode的第4天(Java版)

#【中秋征文】程序人生&#xff0c;中秋共享# 目录 第一题 题目来源 题目内容 解决方法 方法一&#xff1a;遍历字符串 方法二&#xff1a;有限状态机&#xff08;Finite State Machine&#xff09; 方法三&#xff1a;正则表达式 第二题 题目来源 题目内容 解决方…

机器学习——决策树/随机森林

0、前言&#xff1a; 决策树可以做分类也可以做回归&#xff0c;决策树容易过拟合决策树算法的基本原理是依据信息学熵的概念设计的&#xff08;Logistic回归和贝叶斯是基于概率论&#xff09;&#xff0c;熵最早起源于物理学&#xff0c;在信息学当中表示不确定性的度量&…

带你了解前后端分离的秘密-Vue【vue入门】

&#x1f3c5;我是默&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Vue》。&#x1f3af;&#x1f3af; &#x1f680;无论你是编程小白&#xff0c;还是有一定基础的程序员&#xff0c;这个专栏…

js中事件委托和事件绑定之间的区别

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 事件绑定&#xff08;Event Binding&#xff09;⭐事件委托&#xff08;Event Delegation&#xff09;⭐ 选择事件绑定或事件委托⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本…

NVM安装及如何使用NVM

NVM是什么&#xff1f; nvm 全名 Node Version Manager&#xff0c;Node的版本管理工具 NVM能做什么&#xff1f; 安装 nvm 后&#xff0c;可以使用nvm的相关命令来管理和切换不同的 node 版本&#xff0c;方便开发 如何安装NVM 链接: NVM GitHub地址 如何使用 NVM 命令 …

R语言绘制PCA双标图

代码&#xff1a; setwd("D:/Desktop/0000/R") #更改路径#导入数据 df <- read.table("Input data.csv", header T, sep ",")# ----------------------------------- #所需的包: packages <- c("ggplot2", "tidyr"…

1.简单工厂模式

UML类图 代码 main.cpp #include <iostream> #include "OperationFactory.h" using namespace std;int main(void) {float num1;float num2;char operate;cin >> num1 >> num2 >> operate;Operation* oper OperationFactory::createOpera…

算法综合篇专题四:前缀和

"回忆里的我&#xff0c;比国王富有。奢侈的快乐~" 1、前缀和【模板】 (1) 题目解析 (2) 算法原理 #include <iostream> using namespace std;const int N 100010; // 可能出现溢出 long long arr[N],dp[N]; int n,q;int main() {cin >> n …

长胜证券:突破五日线什么意思?

随着股市的快速开展&#xff0c;越来越多的人开端了解和参与股票投资&#xff0c;但或许会遇到一些术语和概念&#xff0c;例如“打破五日线”&#xff0c;这是新手们需求了解的。本文将介绍“打破五日线”的概念及其意义&#xff0c;同时从不同视点剖析其意义和影响因素。 什…

记录wisemodel上传失败

参考&#xff1a;https://wisemodel.cn/docs/%E6%A8%A1%E5%9E%8B%E4%B8%8A%E4%BC%A0 第一种方法&#xff1a; git lfs install git clone https://oauth2:your_git_tokenwww.wisemodel.cn/username/my_test_model.git也就是用oauth2&#xff0c;然后再按照一般的方法传文件&a…

(三十三)大数据实战——Canal安装部署及其应用案例实战

前言 Canal 是一个开源的MySQL数据库binlog监听和解析框架&#xff0c;用于实时捕获 MySQL数据库的binlog 变更事件&#xff0c;并将其解析成易于消费的数据格式。Canal 可以实时监听 MySQL 数据库的 binlog&#xff0c;并即时捕获数据库的数据变更事件。Canal可以将捕获到的b…

C++ function<>和bind()

一、可调用对象 介绍两个概念&#xff1a;调用运算符和可调用对象 调用运算符 调用运算符&#xff0c;即&#xff1a;() 。跟随在函数名之后的一对括号 “()”&#xff0c;起到调用函数的效果&#xff0c;传递给函数的参数放置在括号内。 可调用对象 对于一个对象或者一个表…

位图+布隆过滤器+海量数据问题(它们都是哈希的应用)

一)位图: 首先计算一下存储一下10亿个整形数据&#xff0c;需要多大内存呢&#xff0c;多少个G呢&#xff1f; 2^3010亿&#xff0c;10亿个字节 byte kb mb gb 100000000个字节/1024/1024/10241G 所以10亿个字节就是1G&#xff0c;所以40亿个字节就是4G&#xff0c;也就是10个整…

Swing基本组件的用法(一)

语雀笔记&#xff1a;https://www.yuque.com/huangzhanqi/rhwoir/paaoghdyv0tgksk1https://www.yuque.com/huangzhanqi/rhwoir/paaoghdyv0tgksk1Java图形化界面: Java图形化界面学习demo与资料 (gitee.com)https://gitee.com/zhanqi214/java-graphical-interface Swing组件层次…

机器学习笔记 - 视频分析和人类活动识别技术路线简述

一、理解人类活动识别 首先了解什么是人类活动识别,简而言之,是对某人正在执行的活动/动作进行分类或预测的任务称为活动识别。 我们可能会有一个问题:这与普通的分类任务有什么不同?这里的问题是,在人类活动识别中,您实际上需要一系列数据点来预测正确执行的动作。 看看…

Python 多进程异常

这里写目录标题 1、捕获异常2、退出程序3、进程共享变量4、multiprocessing的Pool所起的进程中再起进程 1、捕获异常 https://zhuanlan.zhihu.com/p/321408784 try:<语句> except Exception as e:print(异常说明,e)1 捕获所有异常 包括键盘中断和程序退出请求&#xff0…

一个Binder的前生今世 (一):Service的创建

一个Binder的前生今世 (一):Service的创建 一个Binder的前生今世Binder的历史 (字面意义的前生今世)Binder的生命周期(抽象意义的前生今世)Binder 应用及系统层关系图Binder应用层的架构设计Binder应用层实现Binder的创建服务端Binder的创建服务端Binder的传递Binder在客…

Trino HTTPS 与密码认证介绍与实战操作

文章目录 一、概述二、安装 Trino三、配置 HTTPS1&#xff09;生成证书2&#xff09;配置 Trino3&#xff09;修改 Trino docker-compose yaml 文件4&#xff09;开始部署 Trino5&#xff09;测试验证 四、密码认证1&#xff09;开启密码认证2&#xff09;创建密码认证配置文件…