QT图形视图系统 - 使用一个项目来学习QT的图形视图框架 - 终篇

news2024/11/27 18:50:23

QT图形视图系统 - 终篇

接上一篇,我们需要继续完成以下的效果;

先上个效果图:

在这里插入图片描述

修改背景,使之整体适配

上一篇我们绘制了标尺,并且我们修改了放大缩小和对应的背景,整体看来,我们的滚动条会和背景不搭配,因此我们需要修改我们的背景,这里使用qss修改;并且我们把之前的背景也写到这个里面。

style1.qss

QGraphicsView
{
    background: #000000;
}

QScrollBar:horizontal {
    border: none;
    background: #000000;
    height: 15px;
}
QScrollBar::handle:horizontal {
    background: white;
    min-width: 20px;
}
QScrollBar::add-line:horizontal {
    border: none;
    background: #000000;
    width: 0px;
}

QScrollBar::sub-line:horizontal {
    border: none;
    background: #000000;
    width: 0px;
    subcontrol-position: left;
    subcontrol-origin: margin;
}
/*QScrollBar:left-arrow:horizontal, QScrollBar::right-arrow:horizontal {*/
/*    border: 2px solid grey;*/
/*    width: 3px;*/
/*    height: 3px;*/
/*    background: white;*/
/*}*/

QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal {
    background: none;
}

QScrollBar:vertical {
    border: none;
    background: #000000;
    width: 15px;
    border-bottom: 1px solid red;
}
QScrollBar::handle:vertical {
    background: white;
    min-height: 20px;
}
QScrollBar::add-line:vertical {
    border: none;
    background: #000000;
    height: 0px;
    subcontrol-position: bottom;
    subcontrol-origin: margin;
}

QScrollBar::sub-line:vertical {
    border: none;
    background: #000000;
    height: 0px;
    subcontrol-position: top;
    subcontrol-origin: margin;
}
QScrollBar:up-arrow:vertical, QScrollBar::down-arrow:vertical {
    border: 2px solid grey;
    width: 3px;
    height: 3px;
    background: white;
}

QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
    background: none;
}

然后我们加载这个qss即可, 将之前设置qss的地方修改成读取这个文件

QFile file(":/resources/qss/style1.qss");
file.open(QIODevice::ReadOnly);
// 设置软件背景色
setStyleSheet(QString(file.readAll()));
file.close();

绘制对应刻度的线条

QGraphicsView有两个函数,一个是绘制背景色,一个是绘制前景色。我们的样条实际上绘制的是背景色,因此我们需要重写这两个函数;

void drawForeground(QPainter* painter, const QRectF& rect) override;
void drawBackground(QPainter* painter, const QRectF& rect) override;

去掉之前再scene中添加的文字,我们接下来开始绘制

背景没有什么好说的,直接绘制成黑色的就可以

void GraphicsView::drawBackground(QPainter *painter, const QRectF &rect)
{
    painter->fillRect(rect, Qt::black);
    // QGraphicsView::drawBackground(painter, rect);
}

接下来我们通过前景色来绘制刻度线

constexpr int32_t uScale = 100000;
constexpr double dScale = 1.0 / uScale;
static std::unordered_map<int, int> gridLinesX, gridLinesY;

void GraphicsView::drawForeground(QPainter *painter, const QRectF &rect)
{
    // fixme 这个地方需要修改成按照单位转换的
    double scale =  pow(10.0, ceil(log10(8.0 / h_ruler_->zoom())));
    double lineWidth {0};
    gridLinesX.clear(), gridLinesY.clear();
    const QColor color[4] {
            {255, 0, 0, 127}, // 0处使用红色绘制
            QColor(100, 100, 100, 50),  // Grid1
            QColor(100, 100, 100, 150), // Grid5
            QColor(100, 100, 100, 255), // Grid10
    };

    double y, x;
    draw(scale * 0.1, rect, x, y);
    draw(scale * 0.5, rect, x, y);
    draw(scale * 1.0, rect, x, y);

    gridLinesX[0] = 0;
    gridLinesY[0] = 0;

    static QVector<QLineF> lines[4];
    for (auto&& vec : lines)
        vec.clear();
    double tmp {};
    for (auto [x, colorIndex] : gridLinesX) {
        tmp = x * dScale;
        lines[colorIndex].push_back(QLineF(tmp, rect.top(), tmp, rect.bottom()));
    }
    for (auto [y, colorIndex] : gridLinesY) {
        tmp = y * dScale;
        lines[colorIndex].push_back(QLineF(rect.left(), tmp, rect.right(), tmp));
    }
    painter->save();
    painter->setRenderHint(QPainter::Antialiasing, false);
    int colorIndex {};
    for (auto&& vec : lines) {
        painter->setPen({color[colorIndex++], lineWidth});
        painter->drawLines(vec.data(), vec.size());
    }
    auto width { rect.width() };
    auto height { rect.height() };
    painter->setPen({Qt::yellow, 0.0});
    painter->drawLine(QLineF {point_.x() - width, point_.y(), point_.x() + width, point_.y()});
    painter->drawLine(QLineF {point_.x(), point_.y() - height, point_.x(), point_.y() + height});

    painter->restore();
}


void GraphicsView::draw(double sc, const QRectF& rect, double &x, double &y)
{
    if (sc >= 1.0) {
        int top = floor(rect.top());
        int left = floor(rect.left());
        y = top - top % int(sc);
        x = left - left % int(sc);
    } else {
        const double k = 1.0 / sc;
        int top = floor(rect.top()) * k;
        int left = floor(rect.left()) * k;
        y = (top - top % int(k)) / k;
        x = (left - left % int(k)) / k;
    }

    for (const auto end_ = rect.bottom(); y < end_; y += sc)
        ++gridLinesY[ceil(y * uScale)];

    for (const auto end_ = rect.right(); x < end_; x += sc)
        ++gridLinesX[ceil(x * uScale)];
}

这样我们便有了网格线

下面的函数是对ruler和鼠标移动时候的操作

void GraphicsView::updateRuler()
{
    updateSceneRect(QRectF()); //
    QPoint p = mapFromScene(QPointF());
    v_ruler_->setOrigin(p.y());
    h_ruler_->setOrigin(p.x());
    v_ruler_->setRulerZoom(qAbs(transform().m22() * 0.1));
    h_ruler_->setRulerZoom(qAbs(transform().m11() * 0.1));
    update();
}

void GraphicsView::mouseMoveEvent(QMouseEvent *event)
{
    QGraphicsView::mouseMoveEvent(event);
    v_ruler_->setCursorPos(event->pos());
    h_ruler_->setCursorPos(event->pos());
    point_ = mapToScene(event->pos());
    emit sig_mouseMove(event->pos());
    update();
}

我们之前对鼠标样式进行了修改,这个里面也不要忘记将View中的鼠标修改成十字
展示的是主要代码,并不是全部代码,如果需要全部代码请联系博主获取

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

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

相关文章

《面试1v1》ElasticSearch架构设计

&#x1f345; 作者简介&#xff1a;王哥&#xff0c;CSDN2022博客总榜Top100&#x1f3c6;、博客专家&#x1f4aa; &#x1f345; 技术交流&#xff1a;定期更新Java硬核干货&#xff0c;不定期送书活动 &#x1f345; 王哥多年工作总结&#xff1a;Java学习路线总结&#xf…

设计模式行为型——状态模式

在软件开发过程中&#xff0c;应用程序中的部分对象可能会根据不同的情况做出不同的行为&#xff0c;把这种对象称为有状态的对象&#xff0c;而把影响对象行为的一个或多个动态变化的属性称为状态。当有状态的对象与外部事件产生互动时&#xff0c;其内部状态就会发生改变&…

九、Spring 声明式事务学习总结

文章目录 一、声明式事务1.1 什么是事务1.2 事务的应用场景1.3 事务的特性&#xff08;ACID&#xff09;1.4 未使用事务的代码示例1.5 配置 Spring 声明式事务学习总结 一、声明式事务 1.1 什么是事务 把一组业务当成一个业务来做&#xff1b;要么都成功&#xff0c;要么都失败…

宋浩概率论笔记(四)数字特征

本帖更新数字特征&#xff0c;包含期望、方差、相关系数等&#xff0c;要点在于记忆性质中的各种公式&#xff0c;遇到题目时能迅速利用已知条件计算答案。

Bigemap如何添加谷歌地图?

工具 Bigemap gis office地图软件 BIGEMAP GIS Office-全能版 Bigemap APP_卫星地图APP_高清卫星地图APP 打开软件&#xff0c;要提示需要授权和添加地图&#xff0c;然后去点击选择地图这个按钮&#xff0c;列表中有个添加按钮点进去选择添加地图的方式。 第一种方式&#x…

飞凌OKMX6ULL-C开发板试用

开箱体验 主要配件包括&#xff1a;USB Type-C调试线、电源线、主板。 资源下载 开发环境 飞凌提供了制作好的ubuntu18.04的镜像&#xff0c;直接到网盘下载解压即可&#xff0c;VMWare的安装可以参考网上教程&#xff0c;这里不赘述。安装好VMWare后直接打开解压出来的ubu…

macos搭建python3虚拟环境

我们知道macos自带的python版本是Python2.7, 这个版本比较老而且往往和我们的工程不兼容&#xff0c;所以就得需要我们升级Python版本&#xff0c; 我们不建议直接升级macos自带的本地Python2.7, 因为macos有一些基础软件是依赖于Python2.7的&#xff0c;如果动了遇到问题想再…

neo4j入门实例介绍

使用Cypher查询语言创建了一个图数据库&#xff0c;其中包含了电影《The Matrix》和演员Keanu Reeves、Carrie-Anne Moss、Laurence Fishburne、Hugo Weaving以及导演Lilly Wachowski和Lana Wachowski之间的关系。 CREATE (TheMatrix:Movie {title:The Matrix, released:1999,…

力扣:54. 螺旋矩阵(Python3)

题目&#xff1a; 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;力扣 示例&#xff1a; 示例 1&#xff1a; 输入&#xff1a;matrix [[1,…

[NOIP2007 普及组] 纪念品分组

[NOIP2007 普及组] 纪念品分组 题目描述 元旦快到了&#xff0c;校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获得 的纪念品价值相对均衡&#xff0c;他要把购来的纪念品根据价格进行分组&#xff0c;但每组最多只能包括两件纪念品&#xff0c; 并且…

IO学习-线程

1&#xff0c;使用信号量的方式实现&#xff0c;将倒置以及打印的那道题目&#xff0c; 要求打印&#xff0c;倒置线程&#xff0c;顺序执行。出现的现象为先打印1234567&#xff0c;后打印7654321 不使用flag 运行结果&#xff1a; 2&#xff0c;创建两个线程&#xff0c;其中…

3. C++类和对象

一、面向对象程序设计的基本特点 1.1 抽象 指对具体问题&#xff08;对象&#xff09;进行概括&#xff0c;抽出一类对象的公共性质并加以描述的过程 数据抽象 描述某类对象的属性或状态&#xff0c;即此类对象与其他类对象的区别 行为抽象 描述某类对象的共同行为或功能特征…

IP核之fifo

一.FIFO简介 FIFO (First In First Out&#xff0c;即先入先出&#xff09;&#xff0c;是一种数据缓冲器&#xff0c;用来实现数据先入先出的读写方式。 二&#xff0c;FIFO实现原理 FIFO是采用一种先入先出的实现原理 就如图按照D1到D10的顺序输入那么读取的时候也是按照D…

web浏览器打开本地exe应用

一、如何使web浏览器打开本地exe应用&#xff1f; 浏览器打开本地exe程序我们可以使用ActiveXObject方法&#xff0c;但是只支持IE&#xff0c;谷歌、火狐等浏览器并不支持此操作。 那问题来了&#xff0c;我们又该如何操作&#xff1f; 经过本博主的不断学习探索终于找到了一…

多语言一键铺货跨境电商平台快速开发(java开源)

要搭建一个多语言一键铺货跨境电商平台&#xff0c;可以参考以下步骤&#xff1a; 1. 确定需求&#xff1a;首先&#xff0c;明确平台的功能需求&#xff0c;包括多语言支持、一键铺货功能、跨境支付等。 2. 选择适合的开源项目&#xff1a;选择一个适合的Java开源电商平台项…

Unity 编辑器资源导入处理函数 OnPreprocessAudio :深入解析与实用案例

Unity 编辑器资源导入处理函数 OnPreprocessAudio 用法 点击封面跳转下载页面 简介 在 Unity 中&#xff0c;资源导入是一个非常重要的环节&#xff0c;它决定了资源在项目中的使用方式和效果。Unity 提供了一系列的资源导入处理函数&#xff0c;其中之一就是 OnPreprocessAud…

Crond计划任务的简单使用

目录 前言 一、一次性任务at 二、crond周期性任务 总结 前言 crond是Linux系统中的一个守护进程&#xff0c;负责定期执行预设的任务&#xff0c;也称为计划任务。它可以根据用户的需求&#xff0c;在指定的时间、日期或周期性地执行特定的命令或本crond的用是自动化和定时执行…

JavaWeb_LeadNews_Day5-文章定时发布

JavaWeb_LeadNews_Day5-文章定时发布 延时服务概述DelayQueueRabbitMQ(常用)Redis(常用) redis延迟服务实现思路总思路添加任务取消任务拉取任务未来数据定时刷新redis解决集群抢占 具体实现乐观锁docker运行redis项目集成redis添加任务取消任务拉取任务未来数据定时刷新redis解…

Jmeter入门之digest函数 jmeter字符串连接与登录串加密应用

登录请求中加密串是由多个子串连接&#xff0c;再加密之后传输。 参数连接&#xff1a;${var1}${var2}${var3} 加密函数&#xff1a;__digest &#xff08;函数助手里如果没有该函数&#xff0c;请下载最新版本的jmeter5.0&#xff09; 函数助手&#xff1a;Options > …

【Hystrix技术指南】(1)基本使用和配置说明

这世间许多事物皆因相信而存在&#xff0c;所以人们亲手捏出了泥菩萨&#xff0c;却选择坚定的去信仰它。 分布式系统的规模和复杂度不断增加&#xff0c;随着而来的是对分布式系统可用性的要求越来越高。在各种高可用设计模式中&#xff0c;【熔断、隔离、降级、限流】是经常被…