当前位置: 首页 > 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…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...