QT_XML文件操作

QT_XML文件操作

XML(可扩展标记语言)是标准通用标记语言(SGML)的子集。作为一种允许用户自定义标记语言的源语言,它主要用于标记数据和定义数据类型。XML 具备扩展性良好、内容与形式分离、遵循严格语法要求以及保值性良好等显著优点【有且只有一个根元素】。

文章目录

XML数据结构

cpp 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<factory>
 <worker>
  <WNo>cs001</WNo>
  <WName>吴又可</WName>
  <WSex>男</WSex>
  <WEdu>带专</WEdu>
  <WDep>技术部</WDep>
  <WSalay>2000</WSalay>
 </worker>
</factory>

第一行:XML文档声明;它定义 XML 的1.0版本,以及UTF-8编码;

第一行:XML文档根元素,在文档中唯一;

第三行:XML文档元素;

项目配置

.pro文件里面添加QT += xml

一、DOM 方式核心类速查

作用
QDomDocument XML 文档对象,代表整棵树,解析/构建的入口
QDomElement 元素节点,如 <worker>
QDomNode 所有节点的基类(元素、文本、注释、属性等)
QDomNodeList 子节点集合
QDomText 文本节点,即标签之间的内容
QDomAttr 属性节点,如 name="xxx"
QDomComment 注释节点 <!-- -->
QDomProcessingInstruction 处理指令,如 XML 声明 <?xml ...?>
QDomNamedNodeMap 属性集合

二、XML 各节点类型判断方法

遍历节点时经常踩到「空白文本节点」的坑(XML 标签之间的换行/缩进会被当成 text 节点),导致 toElement() 得到空元素。常用判断:

cpp 复制代码
QDomNode node = root.firstChild();
while (!node.isNull()) {
    if (node.isElement()) {            // 只处理元素节点
        QDomElement e = node.toElement();
        QString tag = e.tagName();
        // ...
    }
    node = node.nextSibling();
}

常用判断方法:

  • node.isElement() --- 是否元素节点
  • node.isText() --- 是否文本节点
  • node.isComment() --- 是否注释节点
  • node.isAttr() --- 是否属性节点
  • node.nodeType() / node.nodeName() / node.nodeValue()

注意:也可用 QDomNode::ElementNodeTextNode 等枚举配合 nodeType() 判断。

三、中文乱码问题(重要)

读取/写入含中文的 XML 常见乱码,原因和解决:

  1. 写入时指定 UTF-8 ,用 toUtf8() 写入,且文件头声明 UTF-8:
cpp 复制代码
QString xml = doc.toString();
file.write(xml.toUtf8());   // 不要直接 write(xml.toLocal8Bit())
  1. 读取解析时,setContent 的字符串应使用 UTF-8 字节
cpp 复制代码
QByteArray data = file.readAll();
QString xmlStr = QString::fromUtf8(data);
doc.setContent(xmlStr);
  1. 如果必须兼容 GBK 中文,用 QTextCodec(Qt5):
cpp 复制代码
QTextCodec *codec = QTextCodec::codecForName("GBK");
QString xmlStr = codec->toUnicode(data);

Qt6 已移除 QTextCodec,建议统一用 UTF-8。

四、常用 API 汇总

cpp 复制代码
// 解析
bool ok = doc.setContent(&file, &errorMsg, &errorLine, &errorColumn); // 带错误定位
bool ok = doc.setContent(QString);       // 从字符串解析

// 获取根元素(等价于 doc.firstChildElement())
QDomElement root = doc.documentElement();

// 查找元素
QDomElement e = root.firstChildElement("worker");      // 第一个匹配子元素
QDomElement next = e.nextSiblingElement("worker");     // 下一个同标签兄弟元素
QDomNodeList list = doc.elementsByTagName("worker");   // 文档级按标签名查找全部

// 创建元素/文本/属性
QDomElement el = doc.createElement("name");
QDomText t = doc.createTextNode("张三");
el.appendChild(t);
QDomAttr attr = doc.createAttribute("id");
attr.setValue("1");
el.setAttributeNode(attr);
// 或简写:el.setAttribute("id", "1");

// 读取/修改元素文本
QString name = e.text();              // 取元素文本(含所有子文本拼接)
e.firstChild().setNodeValue("新值"); // 修改文本节点值

// 删除节点
QDomNode old = e.parentNode().removeChild(e);

// 输出
QString xml = doc.toString(4);  // 参数 4 表示缩进空格数,美化输出

五、增删改查常用场景

1. 追加/新增节点

cpp 复制代码
QDomElement root = doc.documentElement();
QDomElement newWorker = doc.createElement("worker");
root.appendChild(newWorker);

2. 修改某一节点文本

cpp 复制代码
QDomNodeList list = doc.elementsByTagName("WName");
if (!list.isEmpty()) {
    QDomElement e = list.at(0).toElement();
    // 方法一:直接改第一个子文本节点
    QDomNode oldText = e.firstChild();
    e.firstChild().setNodeValue("新姓名");
    // 方法二:清空后重建(更安全)
    while (e.hasChildNodes()) e.removeChild(e.firstChild());
    e.appendChild(doc.createTextNode("新姓名"));
}

3. 删除指定节点

cpp 复制代码
QDomNodeList list = doc.elementsByTagName("worker");
for (int i = list.size() - 1; i >= 0; --i) {   // 倒序遍历,避免删除时索引错乱
    QDomNode n = list.at(i);
    if (n.toElement().attribute("id") == "3") {
        n.parentNode().removeChild(n);
    }
}

删除集合节点时必须倒序遍历,否则删一个后面索引全乱了。

4. 属性读写

cpp 复制代码
QString id = e.attribute("id");          // 读
bool has = e.hasAttribute("id");         // 判断是否存在
e.setAttribute("id", "10");              // 写(不存在则自动新建)
e.removeAttribute("id");                 // 删

六、QXmlStreamReader / Writer

DOM 会把整棵树读进内存,大文件(几百 MB)会卡。此时用流式 API:

cpp 复制代码
// 读取
QFile file(path);
file.open(QIODevice::ReadOnly | QIODevice::Text);
QXmlStreamReader reader(&file);
while (!reader.atEnd()) {
    reader.readNext();
    if (reader.isStartElement()) {
        QString name = reader.name().toString();
        if (name == "WNo") {
            QString val = reader.readElementText();
            // 处理 val
        }
    }
}
if (reader.hasError()) {
    qDebug() << reader.errorString() << reader.lineNumber();
}
file.close();
cpp 复制代码
// 写入
QFile out(path);
out.open(QIODevice::WriteOnly | QIODevice::Text);
QXmlStreamWriter writer(&out);
writer.setAutoFormatting(true);      // 自动换行缩进
writer.setAutoFormattingIndent(4);   // 缩进 4 空格
writer.writeStartDocument("1.0", false); // 第二个参数 false 表示不写独立声明,可省 encoding
writer.writeStartElement("factory");
writer.writeStartElement("worker");
writer.writeTextElement("WNo", "cs001"); // 一步写 <WNo>cs001</WNo>
writer.writeEndElement();
writer.writeEndElement();
writer.writeEndDocument();
out.close();

DOM 适合:小文件、需要随机增删改查树结构。Stream 适合:大文件、顺序读写、内存敏感场景。

七、常见坑与注意事项

  1. 空白文本节点firstChild() 可能返回换行文本节点,务必用 isElement()firstChildElement() 过滤。
  2. ReadWrite 打开已有文件不清空 :覆盖写前必须 resize(0)QIODevice::Truncate,否则旧内容残留导致非法 XML。
  3. documentElement() 必须先确保解析成功:setContent 失败时 documentElement 为空,直接访问会崩溃。
  4. 内存泄漏 :Qt DOM 用引用计数自动管理,一般无需手动 delete;ui 对象在析构里 delete 即可。
  5. 编码:XML 头声明编码必须与实际写入字节一致,否则中文乱码。
  6. 关闭文件 :解析/写入完成后记得 close(),否则文件句柄占用,后续操作可能失败。
  7. Qt6 差异QTextCodec 被移除,改用 QStringConvertertoString() 基本用法不变。

八、一个更精简的「读+写」完整示例

cpp 复制代码
#include <QDomDocument>
#include <QFile>

// 写:把一张 map 写入 config.xml
void writeConfig(const QMap<QString, QString> &cfg, const QString &path) {
    QDomDocument doc;
    QDomProcessingInstruction pi = doc.createProcessingInstruction(
        "xml", "version=\"1.0\" encoding=\"UTF-8\"");
    doc.appendChild(pi);

    QDomElement root = doc.createElement("config");
    doc.appendChild(root);

    for (auto it = cfg.begin(); it != cfg.end(); ++it) {
        QDomElement item = doc.createElement("item");
        item.setAttribute("key", it.key());
        item.setAttribute("value", it.value());
        root.appendChild(item);
    }

    QFile file(path);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
        return;
    file.write(doc.toString(4).toUtf8()); // 4 空格缩进美化
    file.close();
}

// 读:把 config.xml 读回 map
QMap<QString, QString> readConfig(const QString &path) {
    QMap<QString, QString> cfg;
    QFile file(path);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return cfg;

    QDomDocument doc;
    QString err; int line = -1, col = -1;
    if (!doc.setContent(&file, &err, &line, &col)) {
        qDebug() << "XML parse error:" << err << "line" << line << "col" << col;
        file.close();
        return cfg;
    }
    file.close();

    QDomElement root = doc.documentElement();
    for (QDomElement e = root.firstChildElement("item");
         !e.isNull(); e = e.nextSiblingElement("item")) {
        cfg.insert(e.attribute("key"), e.attribute("value"));
    }
    return cfg;
}

九、Qt读取写入配置文件案例

widget.ui

cpp 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>444</width>
    <height>244</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>读取xml文件测试</string>
  </property>
  <widget class="QPushButton" name="writeBtn">
   <property name="geometry">
    <rect>
     <x>70</x>
     <y>190</y>
     <width>101</width>
     <height>31</height>
    </rect>
   </property>
   <property name="text">
    <string>写入XML文件</string>
   </property>
  </widget>
  <widget class="QPushButton" name="readBtn">
   <property name="geometry">
    <rect>
     <x>270</x>
     <y>190</y>
     <width>101</width>
     <height>31</height>
    </rect>
   </property>
   <property name="text">
    <string>读取XML文件</string>
   </property>
  </widget>
  <widget class="QWidget" name="layoutWidget">
   <property name="geometry">
    <rect>
     <x>10</x>
     <y>10</y>
     <width>426</width>
     <height>166</height>
    </rect>
   </property>
   <layout class="QHBoxLayout" name="horizontalLayout_13">
    <item>
     <layout class="QFormLayout" name="formLayout">
      <item row="0" column="0">
       <layout class="QHBoxLayout" name="horizontalLayout">
        <item>
         <widget class="QLabel" name="label">
          <property name="text">
           <string>职工编号:</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QLineEdit" name="no"/>
        </item>
       </layout>
      </item>
      <item row="1" column="0">
       <layout class="QHBoxLayout" name="horizontalLayout_2">
        <item>
         <widget class="QLabel" name="label_2">
          <property name="text">
           <string>职工姓名:</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QLineEdit" name="name"/>
        </item>
       </layout>
      </item>
      <item row="2" column="0">
       <layout class="QHBoxLayout" name="horizontalLayout_4">
        <item>
         <widget class="QLabel" name="label_4">
          <property name="text">
           <string>职工性别:</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QLineEdit" name="sex"/>
        </item>
       </layout>
      </item>
      <item row="3" column="0">
       <layout class="QHBoxLayout" name="horizontalLayout_3">
        <item>
         <widget class="QLabel" name="label_3">
          <property name="text">
           <string>职工学历:</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QLineEdit" name="edu"/>
        </item>
       </layout>
      </item>
      <item row="4" column="0">
       <layout class="QHBoxLayout" name="horizontalLayout_5">
        <item>
         <widget class="QLabel" name="label_5">
          <property name="text">
           <string>职工部门:</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QLineEdit" name="dep"/>
        </item>
       </layout>
      </item>
      <item row="5" column="0">
       <layout class="QHBoxLayout" name="horizontalLayout_6">
        <item>
         <widget class="QLabel" name="label_6">
          <property name="text">
           <string>职工薪资:</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QLineEdit" name="salay"/>
        </item>
       </layout>
      </item>
     </layout>
    </item>
    <item>
     <layout class="QFormLayout" name="formLayout_2">
      <item row="0" column="0">
       <layout class="QHBoxLayout" name="horizontalLayout_7">
        <item>
         <widget class="QLabel" name="label_7">
          <property name="text">
           <string>职工编号:</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QLineEdit" name="no_2"/>
        </item>
       </layout>
      </item>
      <item row="1" column="0">
       <layout class="QHBoxLayout" name="horizontalLayout_8">
        <item>
         <widget class="QLabel" name="label_8">
          <property name="text">
           <string>职工姓名:</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QLineEdit" name="name_2"/>
        </item>
       </layout>
      </item>
      <item row="2" column="0">
       <layout class="QHBoxLayout" name="horizontalLayout_9">
        <item>
         <widget class="QLabel" name="label_9">
          <property name="text">
           <string>职工性别:</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QLineEdit" name="sex_2"/>
        </item>
       </layout>
      </item>
      <item row="3" column="0">
       <layout class="QHBoxLayout" name="horizontalLayout_10">
        <item>
         <widget class="QLabel" name="label_10">
          <property name="text">
           <string>职工学历:</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QLineEdit" name="edu_2"/>
        </item>
       </layout>
      </item>
      <item row="5" column="0">
       <layout class="QHBoxLayout" name="horizontalLayout_12">
        <item>
         <widget class="QLabel" name="label_12">
          <property name="text">
           <string>职工薪资:</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QLineEdit" name="salay_2"/>
        </item>
       </layout>
      </item>
      <item row="4" column="0">
       <layout class="QHBoxLayout" name="horizontalLayout_11">
        <item>
         <widget class="QLabel" name="label_11">
          <property name="text">
           <string>职工部门:</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QLineEdit" name="dep_2"/>
        </item>
       </layout>
      </item>
     </layout>
    </item>
   </layout>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

widget.h

cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

#include <QDomComment> // Qt所封装的类,专门用来操作XML文件,专门用来操作XML文件,用来存储一些配置数据信息
#include <QDomNodeList> // 子节点集合类
#include <QDir>
#include <QFile>
#include <QDebug>
#include <QMessageBox>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;

    QFile m_qfiles;
    QString strcurrentfilepath; // 表示当前文件的路径
    QString strcurrentfilename; //表示当前文件名

public:
    bool openxmlfile(QString filesnamepath); //打开指定的文件
    void readxmlfile(); //读取XML文件
    void writexmlfiles(); // 写入xml文件
    void readrootxml(QDomNodeList sonnodelist); // 读取子节点数据


private slots:
    void on_writeBtn_clicked();
    void on_readBtn_clicked();
};
#endif // WIDGET_H

widget.cpp

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

// ========================== 构造函数 ==========================
// 初始化界面,并设置 XML 文件的默认保存路径与文件名
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
  ui->setupUi(this); // 加载 designer 中设计的 UI 界面

  QDir dirs;                          // 可用来检查/创建目录,此处未实际使用
  strcurrentfilepath = "D:/xmlfiles"; // XML 文件所在目录
  strcurrentfilename = "/factoryworkersxml.xml"; // 文件名
}

// ========================== 析构函数 ==========================
// 释放 ui 对象,避免内存泄漏
Widget::~Widget() { delete ui; }


// ========================== 打开 XML 文件 ==========================
// 功能:按指定文件名打开(不存在则自动创建)XML 文件
// 参数:filesnamepath ------ 相对文件名(如 "/factoryworkersxml.xml")
// 返回:true 表示打开成功,false 表示失败
bool Widget::openxmlfile(QString filesnamepath) {
  m_qfiles.setFileName(strcurrentfilepath + filesnamepath); // 拼接完整路径
  // ReadWrite:可读可写;QFile::Text:以文本模式打开
  return m_qfiles.open(QIODevice::ReadWrite | QFile::Text);
}

// ========================== 写入 XML 文件 ==========================
// 功能:将界面输入框中的内容写入 XML 文件
void Widget::writexmlfiles() {
  // 1. 打开(或创建)XML 文件,失败则终止
  if (!openxmlfile(strcurrentfilename)) {
    qDebug() << "打开XML文件失败,请重新检查";
    return;
  }
  qDebug() << "写入:打开XML文件成功,请认真操作XML";

  // 截断文件,清空旧内容。因为 ReadWrite 模式打开已有文件不会清空,若不截断,末尾会残留旧字节,导致新内容 + 旧残留拼成非法 XML,读取时 setContent 解析失败。
  m_qfiles.resize(0);

  // 2. 创建 QDomDocument 对象,用于构建 XML 文档
  QDomDocument domdoct;
  // 创建 XML 头部处理指令(声明版本号与编码方式)
  QDomProcessingInstruction qversion;
  qversion = domdoct.createProcessingInstruction(
      "xml", "version=\"1.0\" encoding=\"UTF-8\"");
  domdoct.appendChild(qversion); // 将头部声明追加到文档中

  // 3. 创建顶层节点 <factory>
  QDomElement domrootelement = domdoct.createElement("factory");
  domdoct.appendChild(domrootelement);

  // 4. 创建父节点 <worker>,并在其下挂接各个子节点
  QDomElement itemrootelement = domdoct.createElement("worker");
  {
    // ---- 节点1:工号 <WNo> ----
    QDomElement node1 = domdoct.createElement("WNo");  // 创建元素节点
    QDomText domtext1 = domdoct.createTextNode("WNO"); // 创建文本节点
    domtext1.setData(ui->no->text());                  // 写入界面输入框的工号
    node1.appendChild(domtext1);        // 将文本节点绑定到元素节点
    itemrootelement.appendChild(node1); // 将元素节点绑定到父节点 <worker>

    // ---- 节点2:姓名 <WName> ----
    QDomElement node2 = domdoct.createElement("WName");
    QDomText domtext2 = domdoct.createTextNode("WName");
    domtext2.setData(ui->name->text()); // 写入界面输入框的姓名
    node2.appendChild(domtext2);
    itemrootelement.appendChild(node2);

    // ---- 节点3:性别 <WSex> ----
    QDomElement node3 = domdoct.createElement("WSex");
    QDomText domtext3 = domdoct.createTextNode("WSex");
    domtext3.setData(ui->sex->text()); // 写入界面输入框的性别
    node3.appendChild(domtext3);
    itemrootelement.appendChild(node3);

    // ---- 节点4:学历 <WEdu> ----
    QDomElement node4 = domdoct.createElement("WEdu");
    QDomText domtext4 = domdoct.createTextNode("WEdu");
    domtext4.setData(ui->edu->text()); // 写入界面输入框的学历
    node4.appendChild(domtext4);
    itemrootelement.appendChild(node4);

    // ---- 节点5:部门 <WDep> ----
    QDomElement node5 = domdoct.createElement("WDep");
    QDomText domtext5 = domdoct.createTextNode("WDep");
    domtext5.setData(ui->dep->text()); // 写入界面输入框的部门
    node5.appendChild(domtext5);
    itemrootelement.appendChild(node5);

    // ---- 节点6:工资 <WSalay> ----
    QDomElement node6 = domdoct.createElement("WSalay");
    QDomText domtext6 = domdoct.createTextNode("WSalay");
    domtext6.setData(ui->salay->text()); // 写入界面输入框的工资
    node6.appendChild(domtext6);
    itemrootelement.appendChild(node6);
  }

  // 5. 将 <worker> 节点挂接到顶层节点 <factory> 下
  domrootelement.appendChild(itemrootelement);

  // 6. 将整棵文档树转成字符串,以 UTF-8 编码写入文件,并关闭文件
  m_qfiles.write(domdoct.toString().toUtf8());
  m_qfiles.close();

  // 7. 提示用户写入成功
  QMessageBox::information(this, "提示", "恭喜你XML写入成功,请查看目录文件",
                           QMessageBox::Yes);
}


// ========================== 读取 XML 文件 ==========================
// 功能:解析并读取 XML 文件内容
void Widget::readxmlfile() {

  if (!openxmlfile(strcurrentfilename)) {
    qDebug() << "读取:打开xml文件失败,请重新检查";
    return;
  }
  qDebug() << "读取:打开XML文件成功";

  QDomDocument docs;
  // 使用带错误信息参数的重载,解析失败时可以输出具体错误行/列,便于排查
  QString errorMsg;
  int errorLine = -1, errorColumn = -1;
  if (!docs.setContent(&m_qfiles, &errorMsg, &errorLine, &errorColumn)) {
    qDebug() << "读取:操作setContent失败,请重新检查";
    qDebug() << "错误信息:" << errorMsg << ",行:" << errorLine
             << ",列:" << errorColumn;
    m_qfiles.close();
    return;
  }
  qDebug() << "读取:操作setContent成功";
  m_qfiles.close(); // 解析完成后关闭文件,避免文件句柄被占用

  // 读取根节点
  QDomElement root = docs.documentElement();

  // 读取第一个父亲节点
  QDomNode node = root.firstChild();

  while (!node.isNull()) {
    QDomNodeList sonlist = node.childNodes();      // 读取子节点集合信息
    QString rootname = node.toElement().tagName(); // 读取父亲节点名称
    if (rootname.compare("worker") == 0) {
      readrootxml(sonlist); // 将子节点集合信息传递到读取子节点数据
    }
    node = node.nextSibling(); // 读取下一个父节点
  }
}


// ========================== 读取子节点数据 ==========================
// 功能:遍历 <worker> 的子节点集合,将各节点文本显示到右侧编辑框
// 参数:sonnodelist ------ <worker> 节点的全部子节点集合
void Widget::readrootxml(QDomNodeList sonnodelist) {
  // 循环遍历子节点集合,逐个取出节点
  for (int sonnode = 0; sonnode < sonnodelist.size(); sonnode++) {
    // 获取当前子节点并转为元素节点
    QDomElement sonelement = sonnodelist.at(sonnode).toElement();

    // 根据节点标签名,将文本内容填入对应的右侧显示框
    if (sonelement.tagName().compare("WNo") == 0) {
      ui->no_2->setText(sonelement.text()); // 职工编号
    } else if (sonelement.tagName().compare("WName") == 0) {
      ui->name_2->setText(sonelement.text()); // 职工姓名
    } else if (sonelement.tagName().compare("WSex") == 0) {
      ui->sex_2->setText(sonelement.text()); // 职工性别
    } else if (sonelement.tagName().compare("WEdu") == 0) {
      ui->edu_2->setText(sonelement.text()); // 职工学历
    } else if (sonelement.tagName().compare("WDep") == 0) {
      ui->dep_2->setText(sonelement.text()); // 职工部门
    } else if (sonelement.tagName().compare("WSalay") == 0) {
      ui->salay_2->setText(sonelement.text()); // 职工薪资
    }
  }
}


// ========================== 槽函数 ==========================
// 点击"写入"按钮时调用,将界面数据写入 XML 文件
void Widget::on_writeBtn_clicked() { writexmlfiles(); }

void Widget::on_readBtn_clicked() {
  readxmlfile(); // 点击"读取XML文件"按钮,解析文件并回显到右侧编辑框
}

效果


相关推荐
qq762118223 小时前
Ubuntu22.04 Qt 调用shell 脚本启动程序,GLFW 初始化失败
qt
zzzll11113 小时前
用 DeepSeek Harness 手搓一个自己的 Agent
数据库
名字还没想好☜3 小时前
Spring @EventListener 事件驱动解耦实战:同步转异步、事务绑定与顺序控制
java·数据库·后端·python·spring
del3 小时前
第十周技术博客
数据库
1314lay_10074 小时前
C#调用Sql Server存储过程,并且使用传入表结构
数据库·经验分享·笔记·sqlserver·c#
anxiao_m4 小时前
2026大文件传输软件推荐,从速度安全多维度客观测评
数据库·文件传输·传输
IT大白鼠4 小时前
MySQL 分布式集群系列 · 第七篇——生产调优实战:NDB 性能、内存、高可用全方位优化
数据库·分布式·mysql
IvorySQL4 小时前
打造下一代 AI Agent 的统一多模智能数据底座——PostgreSQL 与 AI 的融合演进
数据库·人工智能·postgresql
ShineWinsu4 小时前
对于MySQL:内置函数的解析
linux·数据库·c++·mysql·面试·函数·查询
isNotNullX4 小时前
智能问数为什么答不准?数据、语义、模型、SQL四层拆解
数据库