当前位置: 首页 > news >正文

Qt实现可拖拽的矩形

之前项目上需要用Qt来绘制可拖拽改变形状的矩形。看了Qt Graphics相关的内容,虽然对Qt怎么添加图元的有了些了解,但是具体如何实现拖拽效果,一时也没有什么好的想法。还好网上有人分享的例子,很受启发。后来又回顾了一下这部分的代码,发现了一种新的实现方式。希望这个例子也能帮助到需要的人吧。

这几篇文章对这个例子的顺利实现很有帮助,非常感谢。

通过QGraphicsItem绘制可拖拽,改变大小的矩形_qt 绘制多个可拖动矩形-CSDN博客

QGraphicsSceneBspTree::climbTree崩溃(自记)-CSDN博客

关于QGraphicsItem的scenePos一直为(0,0)的解决方案_qt scenepos-CSDN博客

运行效果:

完整代码如下:

GraphicsViewTest2.pro

QT       += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++11# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0SOURCES += \main.cpp \mainwindow.cpp \mylane.cpp \testrect.cpp \testview.cppHEADERS += \mainwindow.h \mylane.h \testrect.h \testview.hFORMS += \mainwindow.ui# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QGraphicsScene>
#include "mylane.h"
#include "testrect.h"QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();QList<MyLane*> laneList;
private slots:void on_pushButton_clicked();void on_pushButton_2_clicked();private:Ui::MainWindow *ui;QGraphicsScene *scene;
};
#endif // MAINWINDOW_H

mylane.h

#ifndef MYLANE_H
#define MYLANE_H#include <QGraphicsObject>
#include "testrect.h"class MyLane : public QGraphicsObject
{Q_OBJECT
public:explicit MyLane(QGraphicsObject *parent = nullptr);~MyLane();QRectF boundingRect() const override;void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;void addToScene();void removeFromScene();
public:TestRect *item1;TestRect *item2;TestRect *item3;TestRect *item4;public slots:void updateLane();
};#endif // MYLANE_H

testrect.h

#ifndef TESTRECT_H
#define TESTRECT_H#include <QGraphicsRectItem>class TestRect : public QObject, public QGraphicsRectItem
{Q_OBJECT
public:TestRect(qreal x, qreal y, qreal w, qreal h, QGraphicsRectItem *parent = nullptr);~TestRect();void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;void mousePressEvent(QGraphicsSceneMouseEvent *event) override;TestRect &operator=(const TestRect& pt);QPointF point;
public slots:void moveMove(QPointF point);
signals:void sendPos(QPointF point);
};#endif // TESTRECT_H

testview.h

#ifndef TESTVIEW_H
#define TESTVIEW_H#include <QGraphicsView>class TestView : public QGraphicsView
{Q_OBJECT
public:TestView(QWidget *parent = nullptr);void mousePressEvent(QMouseEvent *event) override;void mouseMoveEvent(QMouseEvent *event) override;
signals:void mouseMovePoint(QPoint point);void mouseClicked(QPoint point);
};#endif // TESTVIEW_H

main.cpp

#include "mainwindow.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QGraphicsItem>
#include <QGraphicsRectItem>
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);QRectF rect(-200, -100, 400, 200);scene = new QGraphicsScene(rect);//不加下面这行发现删除矩形的时候程序会概率性的挂在QGraphicsSceneBspTree函数里,什么原因我也不清楚,有清楚的欢迎留言指正scene->setItemIndexMethod(QGraphicsScene::NoIndex);QGraphicsRectItem *item = new QGraphicsRectItem(rect);//item->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsSelectable);QPen pen;pen.setWidth(2);item->setPen(pen);scene->addItem(item);ui->graphicsView->setScene(scene);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::on_pushButton_clicked()
{if(!laneList.isEmpty()){MyLane* lane = laneList.first();lane->removeFromScene();scene->removeItem(lane);laneList.removeOne(lane);delete lane;lane = nullptr;}
}void MainWindow::on_pushButton_2_clicked()
{MyLane* lane = new MyLane;scene->addItem(lane);lane->addToScene();laneList.append(lane);
}

mylane.cpp

#include "mylane.h"
#include "testrect.h"
#include <QGraphicsScene>
#include <QGraphicsRectItem>
#include <QPainter>
#include <QDebug>MyLane::MyLane(QGraphicsObject *parent) : QGraphicsObject(parent)
{item1 = new TestRect(0, 0, 10, 10);item1->setFlags(QGraphicsItem::ItemIsFocusable |QGraphicsItem::ItemIsSelectable |QGraphicsItem::ItemIsMovable);item1->setPos(0, 0);item2 = new TestRect(0, 0, 10, 10);item2->setFlags(QGraphicsItem::ItemIsFocusable |QGraphicsItem::ItemIsSelectable |QGraphicsItem::ItemIsMovable);item2->setPos(100, 0);item3 = new TestRect(0, 0, 10, 10);item3->setFlags(QGraphicsItem::ItemIsFocusable |QGraphicsItem::ItemIsSelectable |QGraphicsItem::ItemIsMovable);item3->setPos(100, -100);item4 = new TestRect(0, 0, 10, 10);item4->setFlags(QGraphicsItem::ItemIsFocusable |QGraphicsItem::ItemIsSelectable |QGraphicsItem::ItemIsMovable);item4->setPos(0, -100);connect(item1, &TestRect::sendPos, item2, &TestRect::moveMove);connect(item2, &TestRect::sendPos, item1, &TestRect::moveMove);connect(item3, &TestRect::sendPos, item4, &TestRect::moveMove);connect(item4, &TestRect::sendPos, item3, &TestRect::moveMove);connect(item1, &TestRect::sendPos, this, &MyLane::updateLane);connect(item2, &TestRect::sendPos, this, &MyLane::updateLane);connect(item3, &TestRect::sendPos, this, &MyLane::updateLane);connect(item4, &TestRect::sendPos, this, &MyLane::updateLane);}
MyLane::~MyLane(){qDebug() << "~MyLane";delete item1;delete item2;delete item3;delete item4;item1 = nullptr;item2 = nullptr;item3 = nullptr;item4 = nullptr;
}
QRectF MyLane::boundingRect() const{QVector<float> vecX;QVector<float> vecY;vecX.append(item1->x());vecX.append(item2->x());vecX.append(item3->x());vecX.append(item4->x());vecY.append(item1->y());vecY.append(item2->y());vecY.append(item3->y());vecY.append(item4->y());float minX = *std::min_element(std::begin(vecX), std::end(vecX));float minY = *std::min_element(std::begin(vecY), std::end(vecY));float maxX = *std::max_element(std::begin(vecX), std::end(vecX));float maxY = *std::max_element(std::begin(vecY), std::end(vecY));QPointF startPoint(minX, minY);QPointF endPoint(maxX, maxY);QPointF pointOffset(10, 10);return { startPoint, endPoint + pointOffset};
}void MyLane::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
//    qDebug() << "item1:" << item1->pos();
//    qDebug() << "item2:" << item2->pos();
//    qDebug() << "item3:" << item3->pos();
//    qDebug() << "item4:" << item4->pos();painter->save();painter->setPen(Qt::blue);painter->drawLine(item1->pos(), item2->pos());painter->drawLine(item2->pos(), item3->pos());painter->drawLine(item3->pos(), item4->pos());painter->drawLine(item4->pos(), item1->pos());
//    painter->drawRect(boundingRect());
//    qDebug() << "boundingRect:" << boundingRect().x() << boundingRect().y() << boundingRect().width() << boundingRect().height();painter->restore();
}void MyLane::addToScene(){if(scene()){scene()->addItem(item1);scene()->addItem(item2);scene()->addItem(item3);scene()->addItem(item4);}
}
void MyLane::removeFromScene(){if(scene()){scene()->removeItem(item1);scene()->removeItem(item2);scene()->removeItem(item3);scene()->removeItem(item4);}
}void MyLane::updateLane(){scene()->update();
}

testrect.cpp

#include "testrect.h"
#include <QGraphicsSceneMouseEvent>
#include <QDebug>TestRect::TestRect(qreal x, qreal y, qreal w, qreal h, QGraphicsRectItem *parent): QGraphicsRectItem(x, y, w, h, parent)
{}
void TestRect::mouseMoveEvent(QGraphicsSceneMouseEvent *event){emit sendPos(event->pos() - point);QGraphicsRectItem::mouseMoveEvent(event);
}
void TestRect::mousePressEvent(QGraphicsSceneMouseEvent *event){point = event->pos();QGraphicsRectItem::mousePressEvent(event);
}void TestRect::moveMove(QPointF point){moveBy(point.x(), point.y());
}
TestRect &TestRect::operator=(const TestRect& pt){setPos(pt.pos());return *this;
}
TestRect::~TestRect(){qDebug() << "~TestRect";
}

testview.cpp

#include "testview.h"#include <QMouseEvent>
#include <QDebug>TestView::TestView(QWidget *parent)
{}void TestView::mousePressEvent(QMouseEvent *event){if(event->button() == Qt::LeftButton){QPoint point = event->pos();qDebug() << "view:" << point;qDebug() << "scene:" << mapToScene(point);}QGraphicsView::mousePressEvent(event);
}void TestView::mouseMoveEvent(QMouseEvent *event){QGraphicsView::mouseMoveEvent(event);
}

mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>MainWindow</class><widget class="QMainWindow" name="MainWindow"><property name="geometry"><rect><x>0</x><y>0</y><width>800</width><height>600</height></rect></property><property name="windowTitle"><string>MainWindow</string></property><widget class="QWidget" name="centralwidget"><layout class="QGridLayout" name="gridLayout"><item row="0" column="0"><widget class="QGraphicsView" name="graphicsView"/></item><item row="1" column="0"><layout class="QHBoxLayout" name="horizontalLayout"><item><spacer name="horizontalSpacer"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="sizeHint" stdset="0"><size><width>40</width><height>20</height></size></property></spacer></item><item><widget class="QPushButton" name="pushButton_2"><property name="text"><string>Add</string></property></widget></item><item><widget class="QPushButton" name="pushButton"><property name="text"><string>Remove</string></property></widget></item></layout></item></layout></widget><widget class="QMenuBar" name="menubar"><property name="geometry"><rect><x>0</x><y>0</y><width>800</width><height>26</height></rect></property></widget><widget class="QStatusBar" name="statusbar"/></widget><resources/><connections/>
</ui>

相关文章:

Qt实现可拖拽的矩形

之前项目上需要用Qt来绘制可拖拽改变形状的矩形。看了Qt Graphics相关的内容&#xff0c;虽然对Qt怎么添加图元的有了些了解&#xff0c;但是具体如何实现拖拽效果&#xff0c;一时也没有什么好的想法。还好网上有人分享的例子&#xff0c;很受启发。后来又回顾了一下这部分的代…...

CentOS:A服务器主动给B服务器推送(上传),B服务器下载A服务器文件(下载)

Linux:常识(bash: ip command not found )_bash: ip: command not found-CSDN博客 rsync 中断后先判断程序是否自动重连:ps aux | grep rsync 查看目录/文件是否被使用(查询线程占用):lsof /usr/local/bin/mongodump/.B_database1.6uRCTp 场景:MongoDB中集合非常大需要…...

Oracle 执行计划查看方法汇总及优劣对比

在 Oracle 数据库中&#xff0c;查看执行计划是优化 SQL 语句性能的重要工具。以下是几种常用的查看执行计划的方法及其优劣比较&#xff1a; 1. 使用 EXPLAIN PLAN FOR 和 DBMS_XPLAN.DISPLAY 方法 执行 EXPLAIN PLAN FOR 语句&#xff1a; EXPLAIN PLAN FOR SELECT * FROM …...

TCL大数据面试题及参考答案

Mysql 索引失效的场景 对索引列进行运算或使用函数:当在索引列上进行数学运算、函数操作等,索引可能失效。例如,在存储年龄的列上建立了索引,若查询语句是 “SELECT * FROM table WHERE age + 1 = 20”,这里对索引列 age 进行了加法运算,数据库会放弃使用索引而进行全表扫…...

九、FOC原理详解

1、FOC简介 FOC&#xff08;field-oriented control&#xff09;为磁场定向控制&#xff0c;又称为矢量控制&#xff08;vectorcontrol&#xff09;&#xff0c;是目前无刷直流电机&#xff08;BLDC&#xff09;和永磁同步电机&#xff08;PMSM&#xff09;高效控制的最佳选择…...

vue页面成绩案例(for渲染表格/删除/添加/统计总分/平均分/不及格显红色/输入内容去首尾空格trim/输入内容转数字number)

1.使用v-if 和v-else 完成<tbody>标签的条件渲染 2.v-for完成列表渲染 3.:class完成分数标红的条件控制 删哪个就传哪个的id&#xff0c;基于这个id去过滤掉相同id的项&#xff0c;把剩下的项返回 a标签的默认点击事件会跳转 这里要禁止默认事件 即使用click.provent 就…...

STM32编程小工具FlyMcu和STLINK Utility 《通俗易懂》破解

FlyMcu FlyMcu 模拟仿真软件是一款用于 STM32 芯片 ISP 串口烧录程序的专用工具&#xff0c;免费&#xff0c;且较为非常容易下手&#xff0c;好用便捷。 注意&#xff1a;STM32 芯片的 ISP 下载&#xff0c;只能使用串口1&#xff08;USART1&#xff09;&#xff0c;对应的串口…...

Centos使用docker搭建Graylog日志平台

日志管理系统有很多&#xff0c;比如ELK,Graylog&#xff0c;LokiGrafanaPromtail 适用场景&#xff1a; 1.如果需求复杂&#xff0c;服务器资源不受限制&#xff0c;推荐使用ELK&#xff08;Logstash Elasticsearch Kibana&#xff09;方案&#xff1b; 2.如果需求仅是将…...

自定义 Kafka 脚本 kf-use.sh 的解析与功能与应用示例

Kafka&#xff1a;分布式消息系统的核心原理与安装部署-CSDN博客 自定义 Kafka 脚本 kf-use.sh 的解析与功能与应用示例-CSDN博客 Kafka 生产者全面解析&#xff1a;从基础原理到高级实践-CSDN博客 Kafka 生产者优化与数据处理经验-CSDN博客 Kafka 工作流程解析&#xff1a…...

【SQL】【数据库】语句翻译例题

SQL自然语言到SQL翻译知识点 以下是将自然语言转化为SQL语句的所有相关知识点&#xff0c;分门别类详细列出&#xff0c;并结合技巧说明。 1. 数据库操作 创建数据库 自然语言&#xff1a;创建一个名为“TestDB”的数据库。 CREATE DATABASE TestDB;技巧&#xff1a;识别**“创…...

linux基本命令2

7. 文件查找和搜索 (继续) find — 查找文件 find /path/to/search -name "file_name" # 根据名称查找文件 find /path/to/search -type f # 查找所有普通文件 find /path/to/search -type d # 查找所有目录 find /path/to/search -name "*.txt" # 查找…...

Spring Boot项目集成Redisson 原始依赖与 Spring Boot Starter 的流程

Redisson 是一个高性能的 Java Redis 客户端&#xff0c;提供了丰富的分布式工具集&#xff0c;如分布式锁、Map、Queue 等&#xff0c;帮助开发者简化 Redis 的操作。在集成 Redisson 到项目时&#xff0c;开发者通常有两种选择&#xff1a; 使用 Redisson 原始依赖。使用 Re…...

Git命令使用与原理详解

1.仓库 # 在当前目录新建一个Git代码库 $ git init ​ # 新建一个目录&#xff0c;将其初始化为Git代码库 $ git init [project-name] ​ # 下载一个项目和它的整个代码历史 $ git clone [url]2.配置 # 显示当前的Git配置 $ git config --list ​ # 编辑Git配置文件 $ git co…...

Linux:自定义Shell

本文旨在通过自己完成一个简单的Shell来帮助理解命令行Shell这个程序。 目录 一、输出“提示” 二、获取输入 三、切割字符串 四、执行指令 1.子进程替换 2.内建指令 一、输出“提示” 这个项目基于虚拟机Ubuntu22.04.5实现。 打开终端界面如图所示。 其中。 之前&#x…...

vue项目中中怎么获取环境变量

在 Vue 项目中&#xff0c;有几种获取环境变量的方法。最常用的是通过 import.meta.env 来访问。 1.首先在项目根目录创建环境变量文件&#xff1a; .env # 所有环境都会加载 .env.development # 开发环境 .env.production # 生产环境2.在环境变量文件…...

C#里怎么样使用正则表达式?

C#里怎么样使用正则表达式? 正则表达式是由普通字符(如英文字母)以及特殊字符(也称为元字符)组成的一种文字模式 这种文字模式可用于检查字符串的值是否满足一定的规则,例如: 验证输入的邮箱是否合法 输入的身份证号码是否合法 输入的用户名是否满足条件等 也可以…...

《生成式 AI》课程 第5講:訓練不了人工智慧?你可以訓練你自己 (下)

资料来自李宏毅老师《生成式 AI》课程&#xff0c;如有侵权请通知下线 Introduction to Generative AI 2024 Springhttps://speech.ee.ntu.edu.tw/~hylee/genai/2024-spring.php 摘要 这一系列的作业是为 2024 年春季的《生成式 AI》课程设计的&#xff0c;共包含十个作业。…...

Vue 动态给 data 添加新属性深度解析:问题、原理与解决方案

在 Vue 中,动态地向 data 中添加新的属性是一个常见的需求,但它也可能引发一些问题,尤其是关于 响应式更新 和 数据绑定 的问题。Vue 的响应式系统通过 getter 和 setter 来追踪和更新数据,但 动态添加新属性 时,Vue 并不会自动为这些新属性创建响应式链接。 1. 直接向 V…...

【Pytest+Yaml+Allure】实现接口自动化测试框架

一、框架思想 requestsyamlpytestallure实现接口自动化框架。结合数据驱动和分层思想&#xff0c;将代码与数据分离&#xff0c;易维护&#xff0c;易上手。使用yaml编写编写测试用例&#xff0c;利用requests库发送请求&#xff0c;使用pytest管理用例&#xff0c;allure生成…...

el-input绑定点击回车事件意外触发页面刷新

小伙伴们在项目中应该还是比较常用键盘指定按键事件的&#xff0c;尤其是一些筛选条件的通过点击键盘回车按键去触发搜索 例如&#xff1a; <el-form><el-form-item label条件title><el-input v-modelformData.searchKey keydown.entersearch></el-input…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

招商蛇口 | 执笔CID,启幕低密生活新境

作为中国城市生长的力量&#xff0c;招商蛇口以“美好生活承载者”为使命&#xff0c;深耕全球111座城市&#xff0c;以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子&#xff0c;招商蛇口始终与城市发展同频共振&#xff0c;以建筑诠释对土地与生活的…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

Web中间件--tomcat学习

Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机&#xff0c;它可以执行Java字节码。Java虚拟机是Java平台的一部分&#xff0c;Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...

基于PHP的连锁酒店管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...

OPENCV图形计算面积、弧长API讲解(1)

一.OPENCV图形面积、弧长计算的API介绍 之前我们已经把图形轮廓的检测、画框等功能讲解了一遍。那今天我们主要结合轮廓检测的API去计算图形的面积&#xff0c;这些面积可以是矩形、圆形等等。图形面积计算和弧长计算常用于车辆识别、桥梁识别等重要功能&#xff0c;常用的API…...