Qt (高仿Visio)流程图组件开发(四) 流程图 图元对齐 磁吸线功能

时间:2025-03-25 08:13:37

文章目录

  • 本系列目录
  • 前言
  • 一、磁吸线原理及实现
  • 二、完整代码
  • 总结


本系列目录

Qt (高仿Visio)流程图组件开发(一) 效果展示及基本开发框架构思
Qt (高仿Visio)流程图组件开发(二) 基本图元绘制 图元间连线绘制
Qt (高仿Visio)流程图组件开发(三) 图元基类如何定义,流程图多种图元类型实现
Qt (高仿Visio)流程图组件开发(四) 流程图 图元对齐 磁吸线功能
Qt (高仿Visio)流程图组件开发(五) 流程图 双击编辑图元内容实现
Qt (高仿Visio)流程图组件开发(六) 流程图 线图元 如何绘制曲线 连接线移除视口后无法显示
Qt (高仿Visio)流程图组件开发(七) 流程图 简单操作界面搭建
Qt (高仿Visio)流程图组件开发(八) 流程图 鼠标拖动图元到场景(QGraphicsScene)创建
Qt (高仿Visio)流程图组件开发(九) 流程图 代码展示


前言

  本文主要介绍流程图中常见的一个功能——磁吸线,图元在移动到另一图元水平线附加时,将显示辅助线并自动对齐。该功能为流程图优化功能,如果不需要可逃过此文。只是经验分享,描述内容并不绝对,如有误差欢迎指正。


一、磁吸线原理及实现

  以水平磁吸线为例,当移动一个图元时,以图元中点为基准,创建一个长为视口(QGraphicsView)长度,高为1像素的矩形,判断哪些图元在这个矩形范围。

	// 磁吸线判断区域 判断区域越小越好,最好所有在区域内的图元都在同一水平线上,这样相近的两个图元不会互相干扰
	QRectF magarea(QPointF(this->sceneRect().left(), mouse_move_point_.y() - 1), QSizeF(this->width(), 1));
	auto area_items = items(magarea);

  删除其他图元干扰项

	// 去除掉自己
	if (area_items.contains(item_temp_)) {
		area_items.removeOne(item_temp_);
	}
	// 去除垂直磁吸线
	if (area_items.contains(item_vline_)) {
		area_items.removeOne(item_vline_);
	}
	// 去掉连线
	for (auto area_item : area_items)
	{
		if (QGraphToFlow(area_item)->GetItemType() == ItemType::Link) {
			area_items.removeOne(area_item);
		}

	}

  使用鼠标当前y坐标和另一个图元判断,判断y的上下限范围可以根据情况设置,该范围就是磁吸线生效范围。

// 判断区域内有无图元
	if (!area_items.isEmpty())
	{
		for (auto i : area_items)
		{
			// 根据鼠标y坐标和另一个图元判断,水平对齐
			float y = mouse_move_point_.y();
			float ny = i->sceneBoundingRect().center().y();
			if (y > ny - 25 && y < ny + 25)
			{
				
			}
		}
	}

  绘制磁吸线,移动图元到磁吸线上。

	if (item_hline_) { removeItem(item_hline_); delete item_hline_; item_hline_ = nullptr; }
	QPointF temp_point = QPointF(item_temp_->sceneBoundingRect().center().x(), ny) - item_temp_->boundingRect().center();
	item_temp_->setPos(temp_point);
	//画线
	item_hline_ = new QGraphicsLineItem(QLineF(item_temp_->sceneBoundingRect().center(), i->sceneBoundingRect().center()));
	item_hline_->setPen(QPen(Qt::DashLine));
	addItem(item_hline_);

二、完整代码

void FlowchartScene::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
{
		// ! [5] 绘制磁吸线
		// 判断选中多个不走磁吸线逻辑
		if (selectedItems().size() > 1) {
			return;
		}
		if (item_temp_ == nullptr) {
			return;
		}
		// 移动图元时,保证鼠标位于图元中心点
		item_temp_->setPos(mouse_move_point_ - item_temp_->boundingRect().center());
		// 水平磁吸线
		MagneticHLine();
		// 垂直磁吸线
		MagneticVLine();

	}
}

// 绘制磁吸线 水平
void FlowchartScene::MagneticHLine()
{
	// 删除上次磁吸线 水平
	if (item_hline_) { removeItem(item_hline_); delete item_hline_; item_hline_ = nullptr; }

	// 水平磁吸线
	// 磁吸线判断区域 判断区域越小越好,最好所有在区域内的图元都在同一水平线上,这样相近的两个图元不会互相干扰
	QRectF magarea(QPointF(this->sceneRect().left(), mouse_move_point_.y() - 1), QSizeF(this->width(), 1));
	auto area_items = items(magarea);
	// 去除掉自己
	if (area_items.contains(item_temp_)) {
		area_items.removeOne(item_temp_);
	}
	// 去除垂直磁吸线
	if (area_items.contains(item_vline_)) {
		area_items.removeOne(item_vline_);
	}
	// 去掉连线
	for (auto area_item : area_items)
	{
		if (QGraphToFlow(area_item)->GetItemType() == ItemType::Link) {
			area_items.removeOne(area_item);
		}

	}
	// 判断区域内有无图元
	if (!area_items.isEmpty())
	{
		for (auto i : area_items)
		{
			// 根据鼠标y坐标和另一个图元判断,水平对齐
			float y = mouse_move_point_.y();
			float ny = i->sceneBoundingRect().center().y();
			if (y > ny - 25 && y < ny + 25)
			{
				if (item_hline_) { removeItem(item_hline_); delete item_hline_; item_hline_ = nullptr; }
				QPointF temp_point = QPointF(item_temp_->sceneBoundingRect().center().x(), ny) - item_temp_->boundingRect().center();
				item_temp_->setPos(temp_point);
				//画线
				item_hline_ = new QGraphicsLineItem(QLineF(item_temp_->sceneBoundingRect().center(), i->sceneBoundingRect().center()));
				item_hline_->setPen(QPen(Qt::DashLine));
				addItem(item_hline_);
			}
		}
	}
}

// 绘制磁吸线 垂直
void FlowchartScene::MagneticVLine()
{
	// 删除上次磁吸线 垂直
	if (item_vline_) { removeItem(item_vline_); delete item_vline_; item_vline_ = nullptr; }

	// 水平磁吸线
	// 磁吸线判断区域 判断区域越小越好,最好所有在区域内的图元都在同一水平线上,这样相近的两个图元不会互相干扰
	QRectF magarea(QPointF(mouse_move_point_.x() - 1, this->sceneRect().top()), QSizeF(1, this->height()));
	auto area_items = items(magarea);
	// 去除掉自己
	if (area_items.contains(item_temp_)) {
		area_items.removeOne(item_temp_);
	}
	// 去除水平磁吸线
	if (area_items.contains(item_hline_)) {
		area_items.removeOne(item_hline_);
	}
	// 去掉连线
	for (auto area_item : area_items)
	{
		if (QGraphToFlow(area_item)->GetItemType() == ItemType::Link) {
			area_items.removeOne(area_item);
		}

	}
	// 判断区域内有无图元
	if (!area_items.isEmpty())
	{
		for (auto i : area_items)
		{
			// 根据鼠标y坐标和另一个图元判断,水平对齐
			float x = mouse_move_point_.x();
			float nx = i->sceneBoundingRect().center().x();
			if (x > nx - 25 && x < nx + 25)
			{
				if (item_vline_) { removeItem(item_vline_); delete item_vline_; item_vline_ = nullptr; }
				QPointF temp_point = QPointF(nx, item_temp_->sceneBoundingRect().center().y()) - item_temp_->boundingRect().center();
				item_temp_->setPos(temp_point);
				//画线
				item_vline_ = new QGraphicsLineItem(QLineF(item_temp_->sceneBoundingRect().center(), i->sceneBoundingRect().center()));
				item_vline_->setPen(QPen(Qt::DashLine));
				addItem(item_vline_);
			}
		}
	}
}

总结

本文主要介绍磁吸线的功能实现,属于功能优化,玩家按需取用。
本文只是经验分享,描述内容并不绝对,如有误差欢迎指正。

如果此文帮助到你( •̀ ω •́ )✧,动动小手点个赞可好O(∩_∩)O。

原创文章,转载请标明本文出处。