当前位置:网站首页>qt绘制网络拓补图(连接数据库,递归函数,无限绘制,可拖动节点)
qt绘制网络拓补图(连接数据库,递归函数,无限绘制,可拖动节点)
2022-07-04 22:37:00 【GreenHandBruce】
硬件:ThinkPadT590
系统:Win10
数据库:sqlserver2014
Qt:5.14.1
QtCreator:4.11.1
源码连接:
qt实现的绘制网络拓补图,先连接sqlserver数据库获取所有节点数据,然后通过递归函数解析出每个节点之间的关系,并计算每个节点要在图上绘制的位置,然后通过重写的
QGraphicsPixmapItem类来绘制节点图,通过重写的
QGraphicsItem类来绘制节点之间的连线。
只要各节点之间的关系数据正确,可以无限绘制。
界面显示如下:
拖动效果如下:
sqlserver数据库表内数据如下:
关键代码如下:
#include <QtWidgets>
#include "nodeframe.h"
#include <iostream>
using namespace std;
NodeFrame::NodeFrame(QWidget *parent) :
QGraphicsView(parent)
{
setGeometry(0,0,1920,2000);
m_scene = new QGraphicsScene(0, 0, this->width(), this->height());
this->setScene(m_scene);
QScrollBar *horBar = this->horizontalScrollBar();
QScrollBar *verBar = this->verticalScrollBar();
horBar->setValue(horBar->maximum());
verBar->setValue(verBar->maximum());
// connectSqlServer();//连接数据库并读取数据,这里先禁用,如果你配好了数据库,则可以开起来
manulInitNoteList();//如果不连接数据库则可以手动初始化节点队列,连接数据库的情况下,这行要禁用!
initNodeList();
}
void NodeFrame::manulInitNoteList()
{
NodeInSql node;
node.nNodeID =1; node.nParentID =1; node.strNodeName ="根节点"; m_lstNodeInSql.append(node);
node.nNodeID =2; node.nParentID =1; node.strNodeName ="子节点2"; m_lstNodeInSql.append(node);
node.nNodeID =3; node.nParentID =1; node.strNodeName ="子节点3"; m_lstNodeInSql.append(node);
node.nNodeID =4; node.nParentID =1; node.strNodeName ="子节点4"; m_lstNodeInSql.append(node);
node.nNodeID =5; node.nParentID =1; node.strNodeName ="子节点5"; m_lstNodeInSql.append(node);
node.nNodeID =6; node.nParentID =2; node.strNodeName ="子节点6"; m_lstNodeInSql.append(node);
node.nNodeID =7; node.nParentID =2; node.strNodeName ="子节点7"; m_lstNodeInSql.append(node);
node.nNodeID =8; node.nParentID =3; node.strNodeName ="子节点8"; m_lstNodeInSql.append(node);
node.nNodeID =9; node.nParentID =3; node.strNodeName ="子节点9"; m_lstNodeInSql.append(node);
node.nNodeID =10; node.nParentID =4; node.strNodeName ="子节点10"; m_lstNodeInSql.append(node);
node.nNodeID =11; node.nParentID =10; node.strNodeName ="子节点11"; m_lstNodeInSql.append(node);
node.nNodeID =12; node.nParentID =11; node.strNodeName ="子节点12"; m_lstNodeInSql.append(node);
node.nNodeID =13; node.nParentID =12; node.strNodeName ="子节点13"; m_lstNodeInSql.append(node);
node.nNodeID =14; node.nParentID =13; node.strNodeName ="子节点14"; m_lstNodeInSql.append(node);
node.nNodeID =15; node.nParentID =13; node.strNodeName ="子节点15"; m_lstNodeInSql.append(node);
node.nNodeID =16; node.nParentID =13; node.strNodeName ="子节点16"; m_lstNodeInSql.append(node);
node.nNodeID =17; node.nParentID =13; node.strNodeName ="子节点17"; m_lstNodeInSql.append(node);
node.nNodeID =18; node.nParentID =13; node.strNodeName ="子节点18"; m_lstNodeInSql.append(node);
}
NodeFrame::~NodeFrame()
{
delete m_scene;
}
void NodeFrame::refresh()
{
this->destroyed(m_scene);
m_scene = new QGraphicsScene(0, 0, this->width(), this->height());
this->setScene(m_scene);
initNodeList();
}
void NodeFrame::connectSqlServer()
{
QSqlDatabase db= QSqlDatabase::addDatabase("QODBC", "dbTemp");
db.setDatabaseName(QString("DRIVER={SQL SERVER};"
"SERVER=%1;" //服务器名称
"DATABASE=%2;"//数据库名
"UID=%3;" //登录名
"PWD=%4;" //密码
).arg("127.0.0.1,49674")//我电脑上的端口号是49674
.arg("myTestSql")
.arg("Bruce")
.arg("Qwerty*963.-+")
);
//数据库连接
bool ok = db.open();
if(ok)
{
qDebug()<<"database open success";
}
else
{
qDebug()<<db.lastError();
return;
}
//数据库查询
QSqlQuery query(db);
query.exec("SELECT * FROM Node;");
while(query.next())
{
NodeInSql node;
if(query.value(1).isValid())
node.nNodeID = query.value(1).toInt();
if(query.value(2).isValid())
node.nParentID = query.value(2).toInt();
if(query.value(3).isValid())
node.strNodeName = query.value(3).toString();
m_lstNodeInSql.append(node);
}
db.close();
}
void NodeFrame::initNodeList()
{
//找到根节点
NodeInSql nRootID;
foreach(NodeInSql node,m_lstNodeInSql)
{
if(node.nNodeID==node.nParentID)
{
nRootID = node;
}
}
NodeInfoToShow rootNodeInfoToShow;
rootNodeInfoToShow.nLevel = 0;
rootNodeInfoToShow.nNodeID = nRootID.nNodeID;
rootNodeInfoToShow.nParentID = nRootID.nParentID;
rootNodeInfoToShow.ptPos = QPoint(0,100);
rootNodeInfoToShow.strNodeName = nRootID.strNodeName;
m_lstNodeInfoToShow.append(rootNodeInfoToShow);
NetNode *rootNetNode = new NetNode(rootNodeInfoToShow,m_scene);
parseNodesInSql(rootNodeInfoToShow,rootNetNode);//解析所有节点关系及位置
}
void NodeFrame::parseNodesInSql(NodeInfoToShow node,NetNode *netNode)
{
int nChildNum = 0;//当前node节点有几个子节点
int nWidth = node.nLevel%2==0?250:150;//节点之间的横向间隔
int nHeight = 200;//节点之间的纵向间隔
QList<NodeInfoToShow> lstNodeInCrtLevel;//当前node下的所有节点
for(int i = 0;i<m_lstNodeInSql.count();i++)
{
if(m_lstNodeInSql[i].nParentID==node.nNodeID && m_lstNodeInSql[i].nParentID!=m_lstNodeInSql[i].nNodeID)
{
nChildNum++;
NodeInfoToShow rootNodeInfoToShow;
rootNodeInfoToShow.nLevel = node.nLevel+1;
rootNodeInfoToShow.nNodeID = m_lstNodeInSql[i].nNodeID;
rootNodeInfoToShow.nParentID = node.nNodeID;
rootNodeInfoToShow.ptPos = QPoint(0,0);//这里先给0,0点作为初始值,下面再给每个子节点确定位置
rootNodeInfoToShow.strNodeName = m_lstNodeInSql[i].strNodeName;
lstNodeInCrtLevel.append(rootNodeInfoToShow);
}
}
//确定每个子节点的位置
for(int i = 0;i<lstNodeInCrtLevel.count();i++)
{
if(nChildNum%2==1)//有奇数个子节点
{
int nHalf = (nChildNum-1)/2;
int nX =node.ptPos.x()+(i-nHalf)*nWidth;//以上一个节点的x坐标为基础加上偏移量
int nY = node.ptPos.y()+nHeight;//以上一个节点的y坐标为基础加上偏移量
lstNodeInCrtLevel[i].ptPos = QPoint(nX,nY);
}
else//有偶数个子节点
{
int nHalf = nChildNum/2;
int nX =node.ptPos.x()+(i-nHalf)*nWidth+nWidth/2;//以上一个节点的x坐标为基础加上偏移量
int nY = node.ptPos.y()+nHeight;//以上一个节点的y坐标为基础加上偏移量
lstNodeInCrtLevel[i].ptPos = QPoint(nX,nY);
}
m_lstNodeInfoToShow.append(lstNodeInCrtLevel[i]);
NetNode *subNetNode = new NetNode(lstNodeInCrtLevel[i],m_scene);
NodeLink *link = new NodeLink(netNode, subNetNode);
if (link) {
m_scene->addItem(link);
}
parseNodesInSql(lstNodeInCrtLevel[i],subNetNode);
}
}
源码下载连接:
边栏推荐
- Redis入门完整教程:有序集合详解
- Explanation of bitwise operators
- Attack and defense world misc advanced area Hong
- Hit the core in the advanced area of misc in the attack and defense world
- Taobao commodity review API interface (item_review get Taobao commodity review API interface), tmall commodity review API interface
- A complete tutorial for getting started with redis: understanding and using APIs
- [try to hack] wide byte injection
- 攻防世界 MISC 进阶区 Ditf
- P2181 对角线和P1030 [NOIP2001 普及组] 求先序排列
- Erik baleog and Olaf, advanced area of misc in the attack and defense world
猜你喜欢
Co create a collaborative ecosystem of software and hardware: the "Joint submission" of graphcore IPU and Baidu PaddlePaddle appeared in mlperf
【图论】拓扑排序
[roommate learned to use Bi report data processing in the time of King glory in one game]
[OpenGL] note 29 anti aliasing (MSAA)
How to send a reliable request before closing the page
Mongodb aggregation operation summary
Redis入门完整教程:Redis Shell
Redis introduction complete tutorial: slow query analysis
攻防世界 MISC 进阶 glance-50
为什么信息图会帮助你的SEO
随机推荐
Redis getting started complete tutorial: publish and subscribe
Talk about Middleware
OSEK标准ISO_17356汇总介绍
图片懒加载的原理
[graph theory] topological sorting
[machine learning] handwritten digit recognition
S32 Design Studio for ARM 2.2 快速入门
微信小程序显示样式知识点总结
攻防世界 misc 进阶区 2017_Dating_in_Singapore
Attack and defense world misc master advanced zone 001 normal_ png
MYSQL架构——用户权限与管理
Analysis of the self increasing and self decreasing of C language function parameters
Redis getting started complete tutorial: Key Management
Redis入门完整教程:初识Redis
The new version judges the code of PC and mobile terminal, the mobile terminal jumps to the mobile terminal, and the PC jumps to the latest valid code of PC terminal
Photoshop批量给不同的图片添加不同的编号
Three stage operations in the attack and defense drill of the blue team
企业如何跨越数字化鸿沟?尽在云原生2.0
Redis introduction complete tutorial: client communication protocol
Redis入门完整教程:API的理解和使用