基于Qt和XML的小型笔记管理系统

XML课程的结课大作业,结果比起XML来说,更像是Qt的入门级试手玩具项目。。。

 

源代码及发行版本见GitHub:https://github.com/pinpeng/SampleNoteWithXML.git

 

程序大致实现了对书籍笔记的增删改,对章节笔记的增删改,最终的运行效果如下:

除去右上方查找书籍功能外,其他可见功能均已实现,双击列表中的元素可以更改元素的名称。

 

在编写中出现的值得一提的情况如下:

1、当书籍名称、书籍作者等内容被编辑后就会立刻保存在对应的数据结构中,因而需要使用Qt中的信号:

QLineEdit::editingFinished()

  Qt讲究一个命名容易理解,所以这个信号很容易理解,意思是结束对这个组件的编辑的时候会发送这个信号。

1、由于需要实现双击列表中元素进行元素重命名的功能,所以需要自己绑定特定的信号和槽函数。

  在网络上搜集资料的时候,发现他人博客上调用的槽有如下两个:

//对QListWidget进行双击操作时会发送该信号
QListWidget::doubleClicked()
//当当前选中行改变时发送该信号
QListWidget::currentRowChanged()

  大致的使用方法如下:

  ①使用doubleClicked( )完成双击时让组件元素进入可编辑的状态的行为

  ②使用currentRowChanged( )完成修改名称后的保存

  但这样会存在一个问题:currentRowChanged( )只有当选中行改变时才会发送信号,但编辑结束后如果不改变选中行为其他行,那么修改后的名称便不会保存。

  通过查(bian)阅(li)资料后发现可以使用这个信号:

QListWidget::itemChanged()

  当列表中某个元素被修改并且该元素失去输入焦点时,会发送这个信号。

  使用itemChanged( )代替currentRowChanged( )后,即使不进行换行操作,也可以保存数据到数据结构中。

 

2、QListWidget::currentRow( )的返回值问题

  当没有选中列表元素的时候,currentRow( )会返回-1值,而currentItem( )会返回nullptr。

  所以如果在程序中使用vector等数据结构存储数据时,要注意边界问题,以及指针越界问题。

  本人在程序中的大部分按钮检测中,都增加了这样的检测:

Function(){
  //检测列表是否有元素被选中
  if(list->currentRow()<0)
    return;

  //
TODO... }

 

3、持久化问题

  在刚开始时,每一个按钮都会修改本地XML文件中的内容,但后面意识到这样会导致大量文件读写的产生,进而导致软件效率的大幅度下降。

  所以在最终版本里,只在初始化窗口时从XML文件中读取,之后在进程结束时删除原有的XML文件,并使用内存中的数据重新写一份XML文件保存在磁盘中。

  这样会导致某一下大量IO的产生。或许需要添加一个保存按钮,来让用户决定在恰当的时候保存文件?

  或者添加线程,每隔一段时间就自动保存?

  这也许会是后面的拓展点。

 

4、XML中Dom节点的添加和读取问题

  写到这里才发现基本没有与XML相关的内容。。。

  本程序使用了Dom来进行有关XML的操作。

  由于只需要从XML中读取和写入数据结构,所以直接使用了node层层索引的方法(firstChild( ),childNotes( )等函数)

  而未使用寻找元素的方法(getElementsByTagName( )等函数)

  为了详细说明,举一个实例:

  假设现在有如下内容:

<bookList>
  <book>
    <name>操作系统</name>
    <version>1.0</version>
  </book>
</bookList>

  使用Qt的QDomDocument添加新的书籍(计算机网络,1.4)时,使用的代码如下:

//为了结构清晰,样例去除了所有检错代码
Fuction(QFile file){
  //打开文件
  file.open(QIODevice::ReadOnly);
  //初始化QDomDocument对象
  QDomDocument doc;
  doc.setContent(&file)
  QDomElement elemBookList = doc.documentElement();

  //初始化要写入的book的信息
  QDomElement elemNewBook = doc.createElement("book");
  //初始化name信息
  QDomElement elemNewBookName = doc.createElement("name");
  QDomText nameText = doc.createTextNode("计算机网络");
  elemNewBookName.appendChild(nameText);
  //初始化version信息
  QDomElement elemNewBookVersion = doc.createElement("version");
  QDomText versionText = doc.createTextNode("1.4");
  elemNewBookName.appendChild(versionText);

  //将name、version信息放入book节点
  elemNewBook.appendChild(elemNewBookName);
  elemNewBook.appendChild(elemNewBookVersion);

  //将book放入bookList节点
  elemBookList.appendChild(elemNewBook);
}

  其中要注意的地方在于,要想编写类似<node>something</node>的内容,那么需要先初始化一个子孩子节点,之后将子孩子节点加入到node中。

  添加进入后的XML文件内容如下:

<bookList>
  <book>
    <name>操作系统</name>
    <version>1.0</version>
  </book>
    <book>
    <name>计算机网络</name>
    <version>1.4</version>
    </book>
</bookList>

 

  但是,在从XML文件中使用Dom读取节点内容时,却不需要那么麻烦

QString bookName = elemNewBook.childNodes().at(0).toElement().text();
QString bookVersion = elemNewBook.childNodes().at(1).toElement().text();

  不需要再到节点的子孩子下面去寻找内容,而是直接读取节点的text。

  个人感到很神秘,不知道为什么这样,如果有知道原因的大佬希望可以指点一下。

posted @ 2021-05-15 16:47  海纳川  阅读(218)  评论(0)    收藏  举报