在使用Qt的GraphicsScene作图时,遇到类似这样的需求:在scene中创建节点类似下图,

现在我要把每个节点的txt保存到xml文件中,结构为

  1. <?xml version='1.0' encoding='UTF-8'?>
  2. <root>
  3. <A>
  4. <B>
  5. </B>
  6. <C>
  7. <E>
  8. ...
  9. </E>
  10. </C>
  11. <D>
  12. <F>
  13. ...
  14. </F>
  15. </D>
  16. </A>
  17. </root>

并且,还要能根据xml文件将这个结构还原出来(由于没有保存坐标信息,当然不能恢复原状)。

我将过程分为:遍历,保存xml;读取xml,还原图形。

我使用Qt的示例项目DiagramScene来改造。

首先,起始节点要与其他节点有所不同,便于我们区分。diagramitem类中,DiagramType { Step, Conditional, StartEnd, Io };,我添加一个virStep类型作为开始节点,其他节点类型为Step。其实virStep和Step的图形一模一样,只是类型不同。

在DiagramItem类中增加一些成员

  1. QList<Arrow *> getArrow(){return arrows;}
  1. void setText(QString text){ mText = text;}
  1. void setItemId(QString pid){ ItemId = pid;}//唯一标识,在创建时设置
  1. QString getItemId(){return ItemId;}
  1. QString getText(){ return mText; }
    重写其paint函数,在其中添加:
  1. painter->drawText(boundingRect() , Qt::AlignCenter ,mText);

保存:

  1. bool OperateItemFile::SaveRelationship(QList<DiagramItem *> &listItem, QList<Arrow *> &listArrow)
  2. {
  3. QFileDialog dlg;
  4. dlg.setAcceptMode(QFileDialog::AcceptSave);
  5. QString strName = dlg.getSaveFileName(getMainWindow() ,QObject::tr("save xml file"), "" ,QObject::tr("XML文件(*.XML)"));
  6. if(strName.isEmpty())
  7. return false;
  8.  
  9. QDomDocument doc;
  10. doc.appendChild( doc.createProcessingInstruction("xml", XML_HEAD_INFO));
  11. QFile file(strName);
  12. if (!file.open(QIODevice::WriteOnly)){
  13. return false;
  14. }
  15. QDomElement root = doc.createElement("Root");
  16. doc.appendChild(root);
  17.  
  18. DiagramItem* startItem = NULL ;
  19. QDomElement startEle;
  20. for (int i = 0; i < listItem.size(); i++) {
  21. if(listItem.at(i)->diagramType() == DiagramItem::virStep){
  22. //开始节点
  23. startEle = doc.createElement(listItem.at(i)->getText());
  24. root.appendChild(startEle);
  25. startItem = listItem.at(i);
  26. //listItem.removeAt(i);
  27. break;
  28. }
  29. }
  30.  
  31. if(!startItem) return false;
  32.  
  33. TravelAllItem(startItem, doc, startEle, listItem);
  34.  
  35. QString xml = doc.toString();
  36. QTextStream txtOutput(&file);
  37. txtOutput.setCodec("UTF-8");
  38. txtOutput<<xml;
  39. file.close();
  40.  
  41. return true;
  42. }
  43.  
  44. void OperateItemFile::GetSubItems(DiagramItem *item, QList<DiagramItem*>& listNodeItem)
  45. {
  46. if(!item) return;
  47.  
  48. listNodeItem.clear();
  49. QList<Arrow*> listArrow = item->getArrow();
  50. for (int i = 0; i < listArrow.size(); i++) {
  51. if(listArrow.at(i)->startItem() == item){
  52. listNodeItem.push_back(listArrow.at(i)->endItem());
  53. }
  54. }
  55. }
  56.  
  57. void OperateItemFile::TravelAllItem(DiagramItem *rootItem, QDomDocument &doc, QDomElement &rootEle, QList<DiagramItem *> &listItem)
  58. {
  59. if(listItem.size() < 1)
  60. return;
  61. QList<DiagramItem*> listNodeItem;
  62. GetSubItems(rootItem, listNodeItem);
  63. for (int i = 0; i < listNodeItem.size(); i++) {
  64. QDomElement ele = doc.createElement(listNodeItem.at(i)->getText());
  65. rootEle.appendChild(ele);
  66. listItem.removeOne(rootItem);
  67. TravelAllItem(listNodeItem.at(i), doc, ele, listItem);
  68.  
  69. }
  70.  
  71. }

使用GraphicsScene的selectItems函数,从中分别获得diagramitem和arrow。代码如果编译不通,可根据情况修改。

读入xml:

  1. void OperateItemFile::ImportTargetFile(DiagramScene* pScene)
  2. {
  3. QString strName;
  4. strName = QFileDialog::getOpenFileName(nullptr, QObject::tr("open xml file"), p_globalObject->ProjectPath() + "/" + p_globalObject->getProjectName() ,QObject::tr("XML文件(*XML*)"));
  5. if(strName.isEmpty()){
  6. return;
  7. }
  8.  
  9. QDomDocument doc;
  10. QFile file(strName);
  11. if (!file.open(QIODevice::ReadOnly)){
  12. return ;
  13. }
  14. if (!doc.setContent(&file))
  15. {
  16. file.close();
  17. return ;
  18. }
  19.  
  20. QDomNode domNodeStart = doc.documentElement();
  21. QList<DiagramItem*> listItem;
  22. QList<Arrow*> listArrow;
  23. m_bStartNode = true;
  24. SetItemPos(pScene->sceneRect().center());
  25. parsePackage(domNodeStart, listItem, listArrow);
  26.  
  27. pScene->ItemClear();
  28.  
  29. int i=0;
  30. for(i=0 ;i<listItem.size() ;i++){
  31. pScene->addItem(listItem.at(i));
  32. }
  33. pScene->setMode(DiagramScene::Mode::MoveItem);
  34. ////////////////////////////////////////////////////////////////////////////////////
  35. //设置箭头起始节点
  36. int j=0;
  37. for(i=0 ;i<listArrow.size(); i++){
  38. for(j=0 ;j<listItem.size() ;j++){
  39. if(listArrow.at(i)->getStartId() == listItem.at(j)->getItemId()){
  40. listArrow.at(i)->setStartItem(listItem.at(j));
  41. break;
  42. }
  43. }
  44. }
  45. //设置箭头结尾节点
  46. for(i=0 ;i<listArrow.size(); i++){
  47. for(j=0 ;j<listItem.size() ;j++){
  48. if(listArrow.at(i)->getEndId() == listItem.at(j)->getItemId()){
  49. listArrow.at(i)->setEndItem(listItem.at(j));
  50. break;
  51. }
  52. }
  53. }
  54.  
  55. for(i=0 ;i<listArrow.size() ;i++){
  56. if(listArrow.at(i)->startItem()!=NULL)
  57. listArrow.at(i)->startItem()->addArrow(listArrow.at(i));
  58.  
  59. if(listArrow.at(i)->endItem()!=NULL)
  60. listArrow.at(i)->endItem()->addArrow(listArrow.at(i));
  61.  
  62. listArrow.at(i)->setColor(pScene->lineColor());
  63. listArrow.at(i)->setZValue(-1000.0);
  64. pScene->addItem(listArrow.at(i));
  65. if(p_globalObject->getCurStatus() == QGlobalObject::devStatus)
  66. listArrow.at(i)->setArrowFlag(true);
  67. else
  68. listArrow.at(i)->setArrowFlag(true);
  69. listArrow.at(i)->updatePosition();
  70. }
  71.  
  72. file.close();
  73. }
  74.  
  75. bool OperateItemFile::parsePackage(QDomNode pNode, QList<DiagramItem*>& listItem, QList<Arrow*>& listArrow)
  76. {
  77. QDomNode myNode = pNode.firstChild();
  78. while(!myNode.isNull()){
  79. QDomElement domE = myNode.toElement();
  80. QString qstrTagName = domE.tagName();
  81. myDebug(qstrTagName);
  82. if(qstrTagName.compare(PackageRoot) != 0 && !qstrTagName.isEmpty()) {
  83. DiagramItem* pItem = NULL;
  84. if(m_bStartNode){
  85. pItem = new DiagramItem(DiagramItem::virStep ,NULL);
  86. domE.setAttribute("StartItem", "true");
  87. m_bStartNode = false;
  88. }
  89. else {
  90. pItem = new DiagramItem(DiagramItem::Step ,NULL);
  91. }
  92. pItem->setPos(m_itemPos);
  93. m_itemPos = GetNextItemPos(m_itemPos);
  94. //pItem->setZValue(z.toFloat());
  95. pItem->setBkColor(QColor(4294967295));
  96. pItem->setItemId(p_globalObject->getGUID());
  97. pItem->setText(qstrTagName);
  98. pItem->setBrush(QBrush(4294967295, (Qt::BrushStyle)1));
  99. domE.setAttribute("ItemId", pItem->getItemId());
  100. if(!domE.hasAttribute("StartItem")){
  101. Arrow* pArrow = new Arrow(NULL, NULL);
  102. QString startItemId = pNode.toElement().attribute("ItemId");
  103. QString endItemId = pItem->getItemId();
  104. pArrow->setItemId(startItemId, endItemId);
  105. listArrow.push_back(pArrow);
  106. }
  107. listItem.push_back(pItem);
  108. }
  109.  
  110. parsePackage(myNode, listItem, listArrow);
  111.  
  112. myNode = myNode.nextSibling();
  113. }
  114. return true;
  115. }
  116.  
  117. QPointF OperateItemFile::GetNextItemPos(QPointF preItemPos)
  118. {
  119. float rat = 1;
  120. qreal x = preItemPos.x()+80;
  121. qreal y = x*rat;
  122. QPointF pt(x,y);
  123. return pt;
  124. }

先写到这里,下一篇将写一下,如何完全还原图形。

Qt 遍历不规则树的节点的更多相关文章

  1. SAX解析xml (遍历DOM树各节点)

    本文参考 http://yangjunfeng.iteye.com/blog/401377 1. books.xml <?xml version="1.0" encoding ...

  2. Qt实现表格树控件-自绘树节点虚线

    目录 一.开心一刻 二.自绘树节点? 三.效果展示 四.实现思路 1.可扩展接口 2.函数重写 3.同步左侧表头 五.相关文章 原文链接:Qt实现表格树控件-自绘树节点虚线 一.开心一刻 一程序员第一 ...

  3. POJ 3321 Apple Tree(后根遍历将树转化成序列,用树状数组维护)

    题意:一棵树,有很多分叉,每个分叉上最多有1个苹果. 给出n,接下来n-1行,每行u,v,表示分叉u,v之间有树枝相连.这里数据中u相当于树中的父节点,v相当于子节点. 给出两个操作: 1.C x  ...

  4. 根据 中序遍历 和 后序遍历构造树(Presentation)(C++)

    好不容易又到周五了,周末终于可以休息休息了.写这一篇随笔只是心血来潮,下午问了一位朋友PAT考的如何,顺便看一下他考的试题,里面有最后一道题,是关于给出中序遍历和后序遍历然后求一个层次遍历.等等,我找 ...

  5. 函数遍历DOM树

    //获取页面中的根节点--根标签   var root=document.documentElement;//html   //函数遍历DOM树   //根据根节点,调用fn的函数,显示的是根节点的名 ...

  6. 探索未知种族之osg类生物---状态树与渲染树以及节点树之间的关系

    节点树 首先我们来看一个场景构建的实例,并通过它来了解一下“状态节点”StateGraph 和“渲染叶”RenderLeaf 所构成的状态树,“渲染台”RenderStage 和“渲染元”Render ...

  7. 先序遍历DOM树的5种方法

    DOM树由文档中的所有节点(元素节点.文本节点.注释节点等)所构成的一个树结构,DOM树的解析和构建是浏览器要实现的关键功能.既然DOM树是一个树结构,那么我们就可以使用遍历树结构的相关方法来对DOM ...

  8. 利用层序遍历(含空节点)和中序遍历重建二叉树 python

    给定一颗二叉树的层序遍历(不含None的形式)和中序遍历序列,利用两个序列完成对二叉树的重建. 还是通过一个例子来说明整个过程,下图所示的二叉树,层序遍历结果为[a,b,c,d,e],中序遍历结果为[ ...

  9. 九度OJ 1359:大魏树遍历 (树)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:299 解决:29 题目描述: 大魏是JOBDU技术组里最喜欢折腾的一个了,单反.骑车.改九度页面,当然还有YY prado.我们姑且先把这些 ...

随机推荐

  1. 两种常用的数据交换格式:XML和JSON

    不同编程语言之间的数据传输,需要一种通用的数据交换格式,它需要简洁.易于数据储存.快速读取,且独立于各种编程语言.我们往往传输的是文本文件,比如我们都知道的csv(comma seperated va ...

  2. vs中free内存失败

    关于vs中free内存失败: 主要有以下两个原因: 1. 函数参数调用写错.特别是传指针进去的时候,若形参与实参不对应,会出错. 2. 内存分配不够,这个原因主要是因为程序中访问到了内存外的地址,即使 ...

  3. mysql NULL函数 语法

    mysql NULL函数 语法 作用:如果表中的某个列是可选的,那么我们可以在不向该列添加值的情况下插入新记录或更新已有的记录.这意味着该字段将以 NULL 值保存. 说明:NULL 值的处理方式与其 ...

  4. 2018百度之星初赛A轮 度度熊学队列

    注意:刚开始用数组存deque<int> qa[MAX]会爆内存 需要改用map<int, deque<int> > qa优化 不明觉厉 #include<b ...

  5. Quartz监听器

    1.概念Quartz的监听器用于当任务调度中你所关注事件发生时,能够及时获取这一事件的通知.类似于任务执行过程中的邮件.短信类的提醒.Quartz监听器主要有JobListener.TriggerLi ...

  6. sh_11_九九乘法表

    sh_11_九九乘法表 # 1. 打印 9 行小星星 row = 1 while row <= 9: col = 1 while col <= row: # print("*&q ...

  7. Django简单操作

    一.静态文件配置 静态文件配置 STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR,'static') ] # 暴露给 ...

  8. linux-解决添加的网卡无法识别的问题(转载)

    添加网卡之后,网卡无法被正确的识别和使用排错方法查看/etc/udev/rules.d/70-persistent-net.rules的内容,该文件中可以查看到新添加的网卡的MAC地址修改/etc/s ...

  9. Mongodb副本集集群搭建

    一.环境准备 1.1.主机信息(机器配置要求见硬件及开发标准规范文档V1.0) 序号 主机名 IP 1 DB_01 10.202.105.52 2 DB_02 10.202.105.53 3 DB_0 ...

  10. 【Python】学习笔记七:函数

    函数的目的:重复使用相同的一段程序 函数的定义 下面是我自定义的一个求a,b,c三个参数平方和的函数 #a,b,c三个参数的平方和 def pow_sum(a,b,c): x = pow(a,2)+p ...