基于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。
个人感到很神秘,不知道为什么这样,如果有知道原因的大佬希望可以指点一下。
浙公网安备 33010602011771号