缘起
大三下学期,在学习《VisualC++面向对象和可视化化程序设计》的第三版的时候,老师让做一个实验,这里是题目:
编写一个程序,能够输入学生的信息,包括:“学号”,“姓名”“性别”“年龄”和所在的“系别”,并能根据学生的“学号”,“姓名”和“系别”来进行检索,当检索的信息超过一个时,能依次显示。
正文
关于这个题目的话,做的简单可以直接在内存一个一个的输入并创建,但是我想试试在MFC中使用XML。所以就上网上找了一下。我写的前一篇文章是一个关于MSXML简单的小程序,在使用MSXML的时候,我发现,MSXML版本dll的版本挺多的:msxml2,msxml3,msxml4,msxml6,调试挺麻烦的。于是转向使用TinyXML解析器,
学习TinyXML的时候参考了百度文库上的如下的文章:
http://wenku.baidu.com/view/01f0732e2af90242a995e507.html(具体如何实现参考它)
个人觉的TinyXML官方的那个实例代码是在是太多了。文库中的那个实例很简单的,花了几个小时实现了一下。
<?xml version="1.0" encoding="utf-8" ?>
<Scene>
<staticbox mesh="crate.mesh">
<position x="-8" y="2" z="4" />
<dimension x="2" y="4" z="2" />
</staticbox>
<staticbox mesh="crate.mesh">
<position x="3" y="2" z="4" />
<dimension x="2" y="4" z="2" />
</staticbox>
</Scene>
运行的结果如下:
我实现的源代码在如下的地址可以下载:http://pan.baidu.com/share/link?shareid=156867&uk=556148328
在这个实现的过程中遇到过这么一些问题:
1.CString类型和string类型以及char *转换的问题:
CString->TCHAR*的转化可以用函数GetBuffer()
函数原型为:LPTSTR GetBuffer( int nMinBufLength );
CString str("CString");
TCHAR* szMsg = new TCHAR[100];
//其参数为CString字符串的长度
//注意GetBuffer()函数和ReleaseBuffer()函数要联合使用不可单独出现
szMsg = str.GetBuffer(str.GetLength());
str.ReleaseBuffer();
delete []szMsg;
szMsg = NULL;
TCHAR*->CString的转化
//方法:使用的是CString类型的格式化的函数
TCHAR szTchar[18] = L"TCHAR";
CString str;
str.Format(_T("%s"),szTchar);
CString和string的互相转换
//这两个类型转化的作用很繁琐,但是又必须使用,TinyXML中使用的是const char *类型
//MFC中使用的是CString类型
CString->std::string 例子:
CString strMfc="test";
std::string strStl;
strStl=strMfc.GetBuffer();
strMfc.ReleaseBuffer();
std::string->CString 例子:
//这里的转换的事例是有效的,c_str()函数
CString strMfc;
std::string strStl="test";
strMfc=strStl.c_str();
更多类型转换参考:http://wenku.baidu.com/view/0280e7a3b0717fd5360cdc84.html
2.Unicode与GB2312的问题,
由于在VS中建立的项目是使用的Unicode编码,我从程序中向XML文档写入中文的字符,程序传给XML文档的是Unicode的编码,我在XML中使用的GB2312编码,这两个编码之间是不同的,所以写入的时候会引起解释成乱码的问题。也许将XML编码改成UTF-8可以解决写的问题,但是如果使用UTF-8的话,下面的XML文档在TinyXML解析的时是会出错的。即TinyXML对中文的支持不太行。
<?xml version="1.0" encoding="gb2312" ?>最后解决 方法是将项目的属性设置为多字节的,这样成功的回避的Unicode与GB2312转化的问题。
<Table>
<student ID="101304" NAME="夏天" SEX="男" AGE="22" DEPART="计算机科学与技术" />
<student ID="101305" NAME="王成宇" SEX="男" AGE="21" DEPART="商学院" />
<student ID="101345" NAME="吴成" SEX="男" AGE="20" DEPART="法政管理学院" />
<student ID="100208" NAME="田野" SEX="女" AGE="22" DEPART="文学院" />
<student ID="100209" NAME="成琳" SEX="女" AGE="23" DEPART="生物科学院" />
</Table>
具体为什么这样做可以,我也不知道,碰巧在:http://blog.csdn.net/dadalan/article/details/3958116
看到叫修改项目属性的,然后修改了一下,在编译了一下,发现可以运行了。不过界面变成这样的发生了如下的变化:
起初的使用Unicode编码的界面:
改变为多字节的后变成:
多字节的编码的界面虽然不好看,但是运行正确。
3.C1010错误
使用TinyXML解析器很容易,将下图的中六个文件添加到项目中,在需要使用的类的是实现的文件中,添加#include "tinyxml.h"就可以使用了。
由于是MFC程序,而不是一个简单的控制台的程序,会有预编译的头文件的存在。添加的到项目中的cpp文件需不需要预编译头,这里问题会引发编译器的C1010号错误-在查找预编译头时遇到意外的文件结尾,解决的方案如下:
在工程中选中TinyXML中的cpp文件,右键属性,在预编译中间使用如下:
两个假设:
1.学号,院系,姓名在XML文件中都是独一无二的,如果看做是二维关系表的话,都可以作为主键使用。这样的假设有这么一些好处,在选择方式的,动态的向选择信息的combobox中添加选择项的时候不需要考虑重复的Item的因素,因而,我的这个程序检索的信息的条数,总是仅有一条。
2.XML文档的大小小于等于2KB。由于我是利用的文件流的读取XML文档的,文件流的缓冲区的大小仅有char buffer [2048]即是只有2KB大小的容量,现在XML文件中的数据量很小,我仅仅是测试功能,没有添加很多的数据。如果发现有GetInfoFormXML()函数中XML解析的错误,先检查一下XML文档是不是超过了2KB,当然可以收手动的扩大缓冲区的大小。
后记
这是很久之前写的一篇技术博客,彼时我还用着Windows系统,学着MFC。现在,我早已告别windows投入Ubuntu一年多了,总体来说,我还是觉得Linux确实是对程序员更加友好的操作系统,也激发了我对命令行的热爱,促进我去思考编程。Linux和开源软件,这是一个*的世界,只要自己想去了解,就能够了解和认识,而不会撞上专有软件这座大墙。而且,系统启动速度变快了,要是再回到Windows,还真不习惯那等待时间。
不过,我挺怀念windows下的那个图形编辑软件(破解版的)的,好用又方便,功能强大。在Linux/Ubuntu下,我一直没有遇到那样好用的图形编辑软件。
关于MFC,看起来好像是很过气的技术,不过,我觉的,其中使用宏来实现的消息处理机制还是很值得学习的,一方面认识到宏的力量,另一方面,对消息处理的理解加深了(这在理解JavaScript的事件驱动时很有帮助)。
参考文献
1.http://wenku.baidu.com/view/01f0732e2af90242a995e507.html