Qt中对于XML文件的写入有两种方式,一个是使用QXmlStreamWriter,另一个则为使用Dom。stream流的形式相对来说更加灵活,而且适合处理大文件。Dom方式由于是将内容加载到了内存中进行操作,所以对于小内存设备则有一定得局限性。
根据《QtCreator快速入门》和网上的一些例子练习了Qt XML的使用,做一个记录,以下是采用Dom方式实现的
实现界面
编写的XML文件
1 <?xml version="1.0" encoding="UTF-8"?>
2 <information>
3 <pin id="1">
4 <card id="1">
5 <port id="1" flag="0"/>
6 <port id="2" flag="0"/>
7 <port id="3" flag="0"/>
8 <port id="4" flag="0"/>
9 <port id="5" flag="0"/>
10 <port id="6" flag="0"/>
11 <port id="7" flag="0"/>
12 </card>
13 <card id="2">
14 <port id="1" flag="0"/>
15 <port id="2" flag="0"/>
16 <port id="3" flag="0"/>
17 <port id="4" flag="0"/>
18 <port id="5" flag="0"/>
19 <port id="6" flag="0"/>
20 </card>
21 <card id="3">
22 <port id="1" flag="0"/>
23 <port id="2" flag="0"/>
24 <port id="3" flag="0"/>
25 <port id="4" flag="0"/>
26 <port id="5" flag="0"/>
27 </card>
28 </pin>
29 <pin id="2">
30 <card id="1">
31 <port id="1" flag="0"/>
32 <port id="2" flag="0"/>
33 <port id="3" flag="0"/>
34 <port id="4" flag="0"/>
35 <port id="5" flag="0"/>
36 <port id="6" flag="0"/>
37 <port id="7" flag="0"/>
38 </card>
39 <card id="2">
40 <port id="1" flag="0"/>
41 <port id="2" flag="0"/>
42 <port id="3" flag="0"/>
43 <port id="4" flag="0"/>
44 <port id="5" flag="0"/>
45 <port id="6" flag="0"/>
46 </card>
47 </pin>
48 </information>
一共有三层,pin->card->port,最内层的port有id和flag两种属性
首先是编写XML文件
代码如下:
1 void xml::writeXML()
2 {
3 QFile file("../project/ini/write.xml");
4 if(!file.open(QIODevice::WriteOnly|QIODevice::Truncate))
5 {
6 return;
7 }
8 QDomDocument doc;
9 QDomProcessingInstruction instruction;
10
11 instruction = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
12 doc.appendChild(instruction);
13 QDomElement root=doc.createElement(tr("information"));
14 doc.appendChild(root);
15
16 QDomElement Pin;
17 QDomElement Card;
18 QDomElement Port;
19 QDomAttr ID = doc.createAttribute("id");
20 QDomAttr Flag = doc.createAttribute("flag");
21 //QDomText text;
22
23 for (int i = 1;i < 3;i++)
24 {
25 Pin = doc.createElement(tr("pin"));
26
27 ID = doc.createAttribute("id");
28 ID.setValue(tr("%1").arg(i));
29 Pin.setAttributeNode(ID);
30
31 //Pin.appendChild(Card);
32 //Card = doc.createElement(tr("card"));
33 for (int j = 1;j < 5 - i;j++)
34 {
35 Card = doc.createElement(tr("card"));
36
37 ID = doc.createAttribute("id");
38 ID.setValue(tr("%1").arg(j));
39 Card.setAttributeNode(ID);
40
41 for (int k = 1;k < 9 - j;k++)
42 {
43 Port = doc.createElement(tr("port"));
44
45 ID = doc.createAttribute("id");
46 ID.setValue(tr("%1").arg(k));
47 Port.setAttributeNode(ID);
48 Flag = doc.createAttribute("flag");
49 Flag.setValue("0");
50 Port.setAttributeNode(Flag);
51
52 Card.appendChild(Port);
53 }
54 Pin.appendChild(Card);
55 }
56 root.appendChild(Pin);
57 }
58
59 QTextStream out(&file);
60 doc.save(out,4);
61 file.close();
62 }
QDomProcessingInstruction instruction;
instruction =
doc.createProcessingInstruction("xml","version=/"1.0/" encoding=/"UTF-8/"");
用来写入XML文件的声明,这对于一个XML文件来说不可缺少。
writeXML()中采用三层for循环进行XML的存储。
好了,现在有我们需要操作的XML文件了,下一步就是就是进行读取,并在界面上显示
我是采用三个listWidget分别显示pin card port信息的
代码如下:
1 /*
2 *函数名:_CreateListWidget
3 *功能:初始化探针、板卡、端口信息
4 *
5 */
6 void configure_win::_CreateListWidget()
7 {
8 ui->cardlistWidget->clear();
9 ui->portlistWidget->clear();
10 ui->pinlistWidget->clear();
11 int flag_card = 1;
12 int flag_port = 1;//判断标识,确定listWidget初始化显示一次
13 QDomDocument doc;
14 QFile file("../project/ini/write.xml");
15 if (!file.open(QIODevice::ReadOnly))
16 {
17 return;
18 }
19 if (!doc.setContent(&file))
20 {
21 file.close();
22 return;
23 }
24 file.close();
25 QDomElement docElem = doc.documentElement();
26 QDomNode n = docElem.firstChild();
27 while (!n.isNull())
28 {
29 if (n.isElement())
30 {
31 QDomElement e = n.toElement();
32 ui->pinlistWidget->addItem(e.toElement().tagName()+e.toElement().attribute("id"));
33 //ui->pinlistWidget->addItem("探针"+e.toElement().attribute("id"));
34 QDomNodeList listcard = e.childNodes();
35 if (flag_card)
36 {
37 for (int i = 0;i < listcard.count();i++)
38 {
39 QDomNode node = listcard.at(i);
40 if (node.isElement())
41 {
42 ui->cardlistWidget->addItem(node.toElement().tagName()+node.toElement().attribute("id"));
43 //ui->cardlistWidget->addItem("板卡"+node.toElement().attribute("id"));
44 QDomNodeList listport = node.childNodes();
45 if (flag_port)
46 { for (int j = 0;j < listport.count();j++)
47 {
48 QDomNode port = listport.at(j);
49 if (port.isElement())
50 {
51 QListWidgetItem *item = new QListWidgetItem;
52 item->setText(port.toElement().tagName() + port.toElement().attribute("id"));
53 item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable|Qt::ItemIsUserCheckable);
54 item->setCheckState(Qt::Unchecked);
55 ui->portlistWidget->addItem(item);
56 //ui->portlistWidget->addItem(port.toElement().tagName() + port.toElement().attribute("id"));
57 //ui->portlistWidget->addItem("端口" + port.toElement().attribute("id"));
58 }
59 }
60 }
61 flag_port = 0;
62 }
63 node = node.nextSibling();
64 }
65 }
66 flag_card = 0;
67 }
68 n = n.nextSibling();
69 }
70 ui->pinlistWidget->item(0)->setSelected(true);
71 ui->cardlistWidget->item(0)->setSelected(true);
72 g_pin = ui->pinlistWidget->item(0)->text();//初始化存储pin card port
73 g_card = ui->cardlistWidget->item(0)->text();
74 g_port = ui->portlistWidget->item(0)->text();
75 }
因为涉及到获取listWidget的item的信息,而界面上只能有一个焦点,所以我使用了三个全局变量保存当前被激活的item项
并且默认为第一项被选中,这样就完成了开始界面的呈现
现在只是完成了XML数据的静态呈现,还没有动态显示,所以下一步需要对listWidget添加一些信号槽函数
1 connect(ui->pinlistWidget,SIGNAL(itemClicked(QListWidgetItem*)),this,SLOT(xmlChanged(QListWidgetItem*)));//点击探针
2 connect(ui->cardlistWidget,SIGNAL(itemClicked(QListWidgetItem*)),this,SLOT(xmlChanged(QListWidgetItem*)));//点击板卡
代码如下:
1 /*
2 *槽函数名:xmlChanged
3 *功能:根据选择读取xml信息
4 *
5 */
6 void configure_win::xmlChanged(QListWidgetItem *item)
7 {
8 QString str = item->text();
9 QString str2 = str.right(1);//取最后一位1
10 QString str1 = str.left(str.length() - 1);//去掉最后一位 card
11 if (str1 == "pin")//点击pin
12 {
13 g_pin = str;//选中的pin改变
14 g_card = "card1";//默认card1
15 g_port = "port1";
16 _SelectChanged(str,"card1");
17 ui->cardlistWidget->item(0)->setSelected(true);
18 }
19 else if (str1 == "card")//点击card
20 {
21 g_card = str;//选中的card改变
22 g_port = "port1";
23 QString strpin;
24 if (ui->pinlistWidget->currentRow() == -1)//获得选中card对应探针????初始化pin第一项pin为选中,为什么返回-1而不是0
25 {
26 strpin = ui->pinlistWidget->item(0)->text();
27 }
28 else
29 {
30 strpin = ui->pinlistWidget->currentItem()->text();
31 }
32 int i = ui->cardlistWidget->currentRow();//获取选中card项
33 _SelectChanged(strpin,str);//更新listWidget
34 ui->cardlistWidget->item(i)->setSelected(true);//重新设置card为选中
35 }
36 }
1 /*
2 *函数名:_SelectChanged
3 *功能:更新探针、板卡、端口信息
4 *
5 */
6 void configure_win::_SelectChanged(QString str1, QString str2)
7 {
8
9 QDomDocument doc;
10 QFile file("../project/ini/write.xml");
11 if (!file.open(QIODevice::ReadOnly))
12 {
13 return;
14 }
15 if (!doc.setContent(&file))
16 {
17 file.close();
18 return;
19 }
20 file.close();
21
22 //QString str = item->text();
23 //qDebug()<<str1;
24 QString strNumberPin = str1.right(1);
25 QString strTypePin = str1.left(str1.length() - 1);//去掉最后一位
26 QString strNumberCard = str2.right(1);
27 QString strTypeCard = str2.left(str1.length() - 1);//去掉最后一位
28 //qDebug()<<strNumberPin<<strTypePin<<strNumberCard<<"\n"<<strTypeCard;
29 //if (i)//点击板卡
30 {
31 QDomNodeList list = doc.elementsByTagName(strTypePin);//查找探针项
32 for (int i = 0;i < list.count();i++)
33 {
34 QDomElement e = list.at(i).toElement();
35 if (e.attribute("id") == strNumberPin)//找到对应的探针
36 {
37 ui->cardlistWidget->clear();//清空板卡
38 QDomNodeList childCard = e.childNodes();
39 for (int j = 0;j < childCard.count();j++)//遍历板卡
40 {
41 QDomElement card = childCard.at(j).toElement();
42 //QDomNode port = childCard.at(j);
43 //qDebug()<<" "<<qPrintable(card.tagName())<<qPrintable(card.attribute("id"));
44 QListWidgetItem *item = new QListWidgetItem;
45 item->setText(card.tagName() + card.attribute("id"));
46
47 //item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable|Qt::ItemIsUserCheckable);
48 //item->setCheckState(Qt::Unchecked);
49 ui->cardlistWidget->addItem(item);
50 if (card.attribute("id") == strNumberCard)
51 {
52 ui->portlistWidget->clear();//清空端口
53 QDomNodeList childPort = card.childNodes();
54
55 for (int k = 0;k < childPort.count();k++)
56 {
57 QDomNode port = childPort.at(k);
58 //qDebug()<<" "<<qPrintable(port.toElement().tagName())<<qPrintable(port.toElement().attribute("id"));
59 QListWidgetItem *item = new QListWidgetItem;
60 item->setText(port.toElement().tagName() + port.toElement().attribute("id"));
61 item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable|Qt::ItemIsUserCheckable);
62 if (port.toElement().attribute("flag") == "0")
63 {
64 item->setCheckState(Qt::Unchecked);
65 }
66 else
67 {
68 item->setCheckState(Qt::Checked);
69 }
70 ui->portlistWidget->addItem(item);
71 }
72 }
73 }
74 return;//完成部分显示后跳出遍历
75 }
76 }
77 }
78 }
xmlChanged()函数响应信号,获取item信息
_SelectChanged()函数根据pin,card读取XML进行界面的动态呈现,还是默认card、port的第一项为选中
到现在为止,我只进行了XML的读取(全部和选择部分),下面是进行XML的修改,这里我选择更改port的flag属性,默认为0,选中为1
1 <?xml version=‘1.0‘ encoding=‘UTF-8‘?>
2 <information>
3 <pin id="1">
4 <card id="1">
5 <port id="1" flag="0"/>
6 <port id="2" flag="0"/>
7 <port id="3" flag="0"/>
8 <port id="4" flag="0"/>
9 <port id="5" flag="0"/>
10 <port id="6" flag="0"/>
11 <port id="7" flag="0"/>
12 </card>
13 <card id="2">
14 <port id="1" flag="0"/>
15 <port id="2" flag="0"/>
16 <port id="3" flag="0"/>
17 <port id="4" flag="0"/>
18 <port id="5" flag="0"/>
19 <port id="6" flag="0"/>
20 </card>
21 <card id="3">
22 <port id="1" flag="0"/>
23 <port id="2" flag="0"/>
24 <port id="3" flag="0"/>
25 <port id="4" flag="0"/>
26 <port id="5" flag="0"/>
27 </card>
28 </pin>
29 <pin id="2">
30 <card id="1">
31 <port id="1" flag="1"/>
32 <port id="2" flag="0"/>
33 <port id="3" flag="1"/>
34 <port id="4" flag="0"/>
35 <port id="5" flag="1"/>
36 <port id="6" flag="0"/>
37 <port id="7" flag="0"/>
38 </card>
39 <card id="2">
40 <port id="1" flag="0"/>
41 <port id="2" flag="0"/>
42 <port id="3" flag="0"/>
43 <port id="4" flag="0"/>
44 <port id="5" flag="0"/>
45 <port id="6" flag="0"/>
46 </card>
47 </pin>
48 </information>
pin2的card1中的一些端口flag状态已经改变
代码如下:
1 connect(ui->portlistWidget,SIGNAL(itemClicked(QListWidgetItem*)),this,SLOT(portSelected(QListWidgetItem*)));//点击端口
1 void configure_win::portSelected(QListWidgetItem *item)
2 {
3 //qDebug()<<"&&&&&&&&&&&&&&&&&&&";
4 g_port = item->text();
5 if (item->checkState() == Qt::Checked)//添加
6 {
7 _linkUpdate(g_pin,g_card,g_port,1);//链路
8 _xmlUpdate(g_pin,g_card,g_port,1);//XML文件
9 }
10 else//删除
11 {
12 _linkUpdate(g_pin,g_card,g_port,0);;//链路
13 _xmlUpdate(g_pin,g_card,g_port,0);//XML文件
14 }
15 }
1 /*
2 *函数名:_xmlUpdate
3 *功能:更新xml文件信息
4 *
5 */
6 void configure_win::_xmlUpdate(QString pin, QString card, QString port, int number)
7 {
8 //qDebug()<<i;
9 QDomDocument doc;
10 QDomAttr Flag = doc.createAttribute("flag");
11 QFile file("../project/ini/write.xml");
12 if (!file.open(QIODevice::ReadWrite))
13 {
14 return;
15 }
16 if (!doc.setContent(&file))
17 {
18 file.close();
19 return;
20 }
21 file.close();
22
23 QString strNumberPin = pin.right(1);
24 QString strTypePin = pin.left(pin.length() - 1);//去掉最后一位
25 QString strNumberCard = card.right(1);
26 QString strTypeCard = card.left(card.length() - 1);//去掉最后一位
27 QString strNumberPort = port.right(1);
28 QString strTypePort = port.left(port.length() - 1);//去掉最后一位port
29
30 QDomNodeList list = doc.elementsByTagName(strTypePin);//查找探针项
31 for (int i = 0;i < list.count();i++)
32 {
33 QDomElement e = list.at(i).toElement();
34 if (e.attribute("id") == strNumberPin)//找到对应的探针
35 {
36 //ui->cardlistWidget->clear();//清空板卡
37 QDomNodeList childCard = e.childNodes();
38 for (int j = 0;j < childCard.count();j++)//遍历板卡
39 {
40 QDomElement card = childCard.at(j).toElement();
41 //qDebug()<<" "<<qPrintable(card.tagName())<<qPrintable(card.attribute("id"));
42 if (card.attribute("id") == strNumberCard)
43 {
44 QDomNodeList childPort = card.childNodes();
45
46 for (int k = 0;k < childPort.count();k++)
47 {
48 QDomNode port = childPort.at(k);
49
50 if (port.toElement().attribute("id") == strNumberPort)
51 {
52 QString num = QString::number(number);
53 //qDebug()<<num;
54 port.toElement().setAttribute("flag",num); //把属性写入xml文件
55 goto _NEXT;
56 }
57 }
58 }
59 }
60 }
61 }
62 _NEXT:
63 QFile f("../project/ini/write.xml");
64 //if(!f.open(QIODevice::WriteOnly|QIODevice::Truncate))
65 if(!f.open(QIODevice::WriteOnly|QIODevice::Truncate))
66 {
67 return;
68 }
69 QTextStream out(&f);
70 doc.save(out,4);
71 f.close();
72 }
好了,我的XML操作到这里都实现了,最后我根据需要,添加了移除按钮的信息,也对XML中的port属性进行修改
1 connect(ui->linkWidget,SIGNAL(itemClicked(QListWidgetItem*)),this,SLOT(mylinkWidgetSelect(QListWidgetItem*)));//移除,禁用按钮可用
1 /*
2 *槽函数名:on_removeBtn_clicked
3 *功能:单击移除按钮,移除选中端口
4 *
5 */
6 void configure_win::on_removeBtn_clicked()
7 {
8 QMessageBox msgBox;
9 msgBox.setWindowTitle(tr("提示"));
10 msgBox.setText(tr("确定要删除端口?"));
11 msgBox.setIcon(QMessageBox::Information);
12 msgBox.addButton(tr("确定(&Y)"),QMessageBox::YesRole);
13 msgBox.addButton(tr("取消(&N)"),QMessageBox::NoRole);
14 msgBox.setStyleSheet("background-color:grey");
15 int ret = msgBox.exec();
16 if (ret == 0)//删除端口
17 {
18 int row = ui->linkWidget->currentRow();
19 QString strlink = ui->linkWidget->item(row)->text();
20 QStringList listlink = strlink.split("->");
21 QString pin = listlink.at(0);
22 QString card = listlink.at(1);
23 QString port = listlink.at(2);
24 _xmlUpdate(pin,card,port,0);//更新xml文件
25 if (pin == g_pin && card == g_card)
26 {
27 for (int j =0;j < ui->portlistWidget->count();j++)
28 {
29 //qDebug()<<ui->portlistWidget->item(j)->text();
30 if (ui->portlistWidget->item(j)->text() == port)
31 {
32
33 ui->portlistWidget->item(j)->setCheckState(Qt::Unchecked);
34 break;
35 }
36 }
37 }
38 ui->linkWidget->takeItem(row);
39 }
40 }
忘了加一句,需要在.pro文件中添加QT += xml
这样才能使用XML的一些类
花了两天半的时间,终于把项目需要的一些对XML的操作搞定了
Qt XML的使用
时间: 2025-02-01 16:57:06