利用Qt的QGraphicsView框架实现思维导图功能

百度网盘体验地址:
链接:https://pan.baidu.com/s/1VyUupBIraqYbnWCzepcJww 
提取码:skgk


效果图

1、动态演示效果:

功能架构 图 功能架构图模板下载_功能架构 图


功能架构 图 功能架构图模板下载_开发语言_02


功能架构 图 功能架构图模板下载_qt_03


2、静态展示图片:

功能架构 图 功能架构图模板下载_Qt_04


功能架构 图 功能架构图模板下载_思维导图_05


功能架构 图 功能架构图模板下载_思维导图_06


功能架构 图 功能架构图模板下载_qt_07


功能架构 图 功能架构图模板下载_qt_08

节点操作

功能

描述

新建思维导图

将在场景中心创建根节点,默认名称:中心主题

添加节点

若父节点已有孩子节点时,需要调整节点位置。默认名称:新建节点

删除孩子节点

点击节点下方“-”号按钮,删除该节点的所有孩子节点,折叠/展开节点会被隐藏

删除自身及孩子节点

点击节点右上方“x”号按钮,删除该节点及其所有孩子节点

修改节点文本

双击文本节点,修改文本内容

折叠/展开节点

折叠或展开孩子节点

文件操作

功能

描述

加载文件

可以加载指定格式的xml文件,转换为思维导图显示

保存文件

将思维导图转换为指定格式的xml文件

模式与主题

功能

描述

线型选择

提供两种线型:圆角折线、圆滑曲线(三次贝塞尔曲线)

模式选择

提供两种模式:动态编辑、静态展示(可任意拖动节点)

主题选择

提供两种主题:渴望天空的蓝、期待黎明的黑

人性化功能

功能

描述

思维导图居中

初始化加载时,根节点位置根据导图位置设计原则进行居中显示

复位

恢复思维导图居中显示

新增节点位置的可视化设计

调整视图位置,保证新增节点的人性化可视效果

文本节点宽度自适应

修改文本内容时,会实时计算节点宽度是否需要改变

鼠标滚轮移动视图

鼠标滚轮控制视图上下移动,Alt+鼠标滚轮控制视图左右移动

鼠标拖拽视图

鼠标在空白处按下,变成小手状可以拖拽视图移动

鼠标缩放视图

Ctrl+鼠标滚轮,控制视图缩放

方向键控制视图移动

上下左右键控制视图移动

Ctrl+0

思维导图场景显示:显示整个思维导图区域,且居中显示

Ctrl+1

全场景显示:显示整个场景大小

Ctrl+2

原画比例显示,即1:1显示

Ctrl+E

复位功能快捷键

思维导图初始位置设计的原则

序号

描述

1

若导图整体宽度小于视图宽度的一半,则根节点居中显示

2

若导图整体宽度大于视图宽度的一半,且小于视图宽度,根节点适度左移,保证导图能够全部显示

3

若导图整体宽度大于视图宽度,则根节点居左显示,其余节点依次排开,超过视图部分不可见

新增节点位置的可视化设计原则

序号

描述

1

若父节点无孩子节点,则在其右侧新增节点。当新增节点超过视图区域时,移动视图,将新增节点位置移动到之前父节点位置,此操作没有闪烁现象,不需要用户寻找新节点位置

2

若父节点有孩子节点,则在其下侧新增节点,此时会自动调整思维导图的布局。当新增节点超过视图区域时,移动视图,将新增节点位置移动到之前父节点位置,此操作没有闪烁现象,不需要用户寻找新节点位置

附属功能节点代码
1、基类

#pragma once

/*
 * 思维导图-功能节点基类
 */

#include <QGraphicsItem>
#include "DataStruct/ItemColor.h"

class MindFuncItemBase : public QObject, public QGraphicsItem
{
	Q_OBJECT
public:
	MindFuncItemBase(QGraphicsItem *parent = nullptr);
	virtual ~MindFuncItemBase();

	void setItemColor(const ItemColor &color);

public:
	virtual QRectF boundingRect() const override;

protected:
	virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
	virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
	virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
	virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;

	virtual void initItemColor();

signals:
	void clicked();

protected:
	int m_width;			// 宽度
	int m_height;			// 高度
	int m_borderRadius;		// 圆角半径	
	int m_borderWidth;		// 边框宽度
	ItemColor m_itemColor;	// 颜色
	bool m_hover;			// 悬浮
	bool m_selected;		// 选中
};
#include "MindFuncItemBase.h"
#include <QGraphicsSceneMouseEvent>

MindFuncItemBase::MindFuncItemBase(QGraphicsItem *parent /*= nullptr*/)
	: QGraphicsItem(parent)
{
	m_width = 18;		// 宽度
	m_height = 18;		// 高度
	m_borderRadius = 3;	// 圆角半径
	m_borderWidth = 2;	// 边框宽度

	m_hover = false;	// 悬浮
	m_selected = false;	// 选中

	initItemColor();

	setAcceptHoverEvents(true);
	setAcceptedMouseButtons(Qt::LeftButton);
	setFlags(QGraphicsItem::ItemIsSelectable);
}

MindFuncItemBase::~MindFuncItemBase()
{

}

void MindFuncItemBase::setItemColor(const ItemColor &color)
{
	m_itemColor = color;
	update();
}

QRectF MindFuncItemBase::boundingRect() const
{
	qreal penWidth = m_borderWidth;
	QRectF rect = QRectF(-m_width / 2 - penWidth / 2, -m_height / 2 - penWidth / 2, m_width + penWidth, m_height + penWidth);
	return rect;
}

void MindFuncItemBase::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
	m_hover = true;
	update();
}

void MindFuncItemBase::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
	m_hover = false;
	update();
}

void MindFuncItemBase::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
	m_selected = true;
	update();
}

void MindFuncItemBase::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
	m_selected = false;
	m_hover = false;

	if (boundingRect().contains(event->pos()))
		emit clicked();

	update();
}

void MindFuncItemBase::initItemColor()
{
	m_itemColor.m_color = Qt::white;
	m_itemColor.m_hoverColor = Qt::white;
	m_itemColor.m_selectedColor = Qt::white;

	m_itemColor.m_bgColor = QColor(118, 118, 118);
	m_itemColor.m_bgHoverColor = QColor(168, 168, 168);
	m_itemColor.m_bgSelectedColor = QColor(68, 68, 68);

	m_itemColor.m_borderColor = Qt::transparent;
	m_itemColor.m_borderHoverColor = Qt::transparent;
	m_itemColor.m_borderSelectedColor = Qt::transparent;
}

派生类举例:折叠/展开节点

#pragma once

/*
 * 思维导图-折叠/展开节点
 */

#include "MindFuncItemBase.h"

class MindCollapseItem : public MindFuncItemBase
{
	Q_OBJECT
public:
	enum State { COLLAPSE, EXPAND };

	MindCollapseItem(QGraphicsItem *parent = nullptr);
	~MindCollapseItem();

	void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
	QRectF boundingRect() const override;

public:
	State state();
	void setState(State state);

protected:
	virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;

private:
	void initItemColor();

signals:
	void collpased();
	void expanded();

private:
	State m_state;	// 折叠状态
	int m_radius;	// 半径	
};
#include "MindCollapseItem.h"
#include <QGraphicsSceneMouseEvent>
#include <QPainter>

MindCollapseItem::MindCollapseItem(QGraphicsItem *parent /*= nullptr*/)
	: MindFuncItemBase(parent)
{
	m_state = EXPAND;

	m_radius = 12;		// 半径
	initItemColor();
}

MindCollapseItem::~MindCollapseItem()
{

}

void MindCollapseItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
	// 绘制背景
	QRectF rect = QRectF(-m_radius, -m_radius, m_radius * 2, m_radius * 2);
	QFont font = painter->font();
	font.setBold(true);
	font.setPixelSize(20);
	painter->setFont(font);
	painter->setPen(QPen(m_selected ? m_itemColor.m_borderSelectedColor : (m_hover ? m_itemColor.m_borderHoverColor : m_itemColor.m_borderColor) , m_borderWidth));
	painter->setBrush(m_selected ? m_itemColor.m_bgSelectedColor : (m_hover ? m_itemColor.m_bgHoverColor : m_itemColor.m_bgColor));
	painter->drawEllipse(rect);
	
	// 绘制文本
	QString text = (m_state == EXPAND) ? "-" : "+";
	painter->setPen(QPen(m_selected ? m_itemColor.m_selectedColor : (m_hover ? m_itemColor.m_hoverColor : m_itemColor.m_color), 4));
	painter->drawText(rect, Qt::AlignCenter, text);
}

QRectF MindCollapseItem::boundingRect() const
{
	qreal penWidth = m_borderWidth;
	QRectF rect = QRectF(-m_radius - penWidth / 2, -m_radius - penWidth / 2, m_radius * 2 + penWidth, m_radius * 2 + penWidth);
	return rect;
}

MindCollapseItem::State MindCollapseItem::state()
{
	return m_state;
}

void MindCollapseItem::setState(State state)
{
	m_state = state;
	update();
}

void MindCollapseItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
	m_selected = false;

	if (boundingRect().contains(event->pos()))
	{
		if (m_state == EXPAND)
		{
			m_state = COLLAPSE;
			emit collpased();
		}
		else// m_state == COLLAPSE
		{
			m_state = EXPAND;
			emit expanded();
		}
	}

	update();
}

void MindCollapseItem::initItemColor()
{
	m_itemColor.m_color = Qt::black;
	m_itemColor.m_hoverColor = Qt::black;
	m_itemColor.m_selectedColor = Qt::white;

	m_itemColor.m_bgColor = Qt::white;
	m_itemColor.m_bgHoverColor = QColor(128, 128, 128);
	m_itemColor.m_bgSelectedColor = Qt::black;

	m_itemColor.m_borderColor = Qt::black;
	m_itemColor.m_borderHoverColor = Qt::white;
	m_itemColor.m_borderSelectedColor = Qt::white;
}