LynxMates 软件开发文档
|
.NET软件开发文档 |
|
|
软件名称 |
LynxMates |
|
软件简介 |
LynxMates是一款班级学生信息管理兼通讯簿软件。它基于Access数据库,可存储、编辑、检索、浏览、打印包括姓名、生日、电话、照片等十余项字段在内的个人信息。数据库特别设定了一个加密字段,可用于存储身份证号码等重要信息。程序平时缩小在系统通知区域,可方便地在通知区域图标上通过快捷菜单进行信息检索操作。它是我们日常工作的好助手。 |
|
作者信息 |
林健 北京理工大学01110407班 Website:http://www.linjian.cn/ E-mail:yumenlj@126.com QQ:71424 |
|
版本信息 |
Version 1.06 2005/02/19 于甘肃兰州 |
开发说明
开发这个软件是纯实用目的。我经常给班里同学打印通讯录,在使用电脑时也常常需要查找同学的手机号、QQ之类的信息,在班级网站上也要放同学的这些资料。原先打印通讯录用的是Word,查找同学信息用的是Outlook通讯簿,班级网站上的则是一个静态的HTML网页,每次信息有改动,几处都要改,很不方便。我想让它们共用一个数据库,方便维护管理。开发LynxMates,一是方便数据的维护,二是方便通讯录的打印,三是便于我按照个人习惯快速查找同学的信息。(至于班级网站上使用这个数据库,是另一个ASP.net工程,不属于LynxMates工程)因此,大家可能会觉得这个软件的通用性不是很好(尤其是打印通讯录,按照寝室分类排列完全是我个人的需要)。
程序用VB.net写成。数据库访问主要使用的是ADO.net技术。数据库选用的是最常见的Access。
其他用到的技术以及我自认为的一些“小聪明”,会在后面详细说明。
使用方法
首次运行时,程序会要求用户选择一个数据库文件,请选择示例数据库MyClass.mdb。以后可删除MyClass.mdb中的示例数据,直接添加和修改自己的数据。当然也可将MyClass.mdb复制,重命名,用本软件或Access清空记录(不要清空字段信息)后再使用。
软件启动后,自动缩小到系统通知区域。单击通知区域中的小图标,可以打开主界面;右击小图标,弹出快捷菜单。通过主界面或快捷菜单,皆可访问DataCenter、DataViewer、DataSearch三个功能窗体。
在DataCenter中,可以通过表格总览所有数据。点击“New”、“Edit”、“Delete”按钮可以添加、编辑、删除个人信息。点击“Print”按钮将以特定的格式打印所有数据。打印预览界面如下:
DataViewer提供个人详细信息浏览:
在DataSearch中可以按一定条件检索个人信息,之后启动DataViewer浏览。在快捷菜单的“Go”之后输入关键字,也可以快速检索:
特别说明:
1、Student ID(数据库中的MateStudentID字段)是数据库主键,不可以为空,其他字段皆可为空。
2、本程序文件夹下的photos文件夹是保存照片用的固定的文件夹,程序中所有涉及到照片的记录只填写该文件夹下的文件名而不写路径。
3、数据库的MateCardID字段为加密保存的身份证号码。安全起见,该字段只能在Access中修改。打开本程序文件夹下的EncryptTools文件夹,运行其中的EncryptTools工具,输入一个密钥(8个英文字符,须牢记)和待加密字串。点击加密按钮后,程序自动将加密后字串复制到剪贴板。此时用Access打开数据库,将加密后字串粘贴到相应记录的MateCardID字段即可。
4、查看加密身份证号码字段的方法:在程序的Data Viewer窗体中,用键盘依次输入“allinformation”,此时窗体下方会出现更多的信息。在其中的Key文本框中输入原先加密用的密钥(示例数据库MyClass.mdb中所有记录的密钥皆为iloveyou),点击右边的叹号按钮,解密后的信息会显示在下方文本框。
5、PrintSettings.xml为打印设置文件,可根据有关注释和元素命名自行设置打印参数。
结构设计
这个软件主要由以下几个类构成:
其中FrmMain是启动窗体,在其中可以调用FrmDataCenter、FrmDataViewer和FrmDataSearch。在FrmDataCenter中又可以调用FrmDataEditor和FrmDataPrint。FrmQuickMenu是点击屏幕右下通知区域时显示的快捷菜单(为什么要用Form而不用ContextMenu做菜单?因为我需要在菜单上加一个TextBox,虽然可以在ContextMenu的绘制事件中添加,可我发现那太麻烦,不如用Form自制一个菜单)。
DataPrintManager类实现了用GDI+绘制打印文档,Dorm类是一个寝室的数据结构(打印是以寝室为分类单位的,这是限制本软件通用性的一个因素),InfoEncrypt类实现数据库特定字段信息加密。DataPrintManager类和InfoEncrypt类的编写参考了班主任金旭亮老师的程序中的部分代码,在这里对他表示感谢。
技术说明
这个软件整体上比较简单清楚,我就不对每个过程一一讲解了。以下几处我认为是有必要说明的:
●FrmMain中的BeSureOnlyOne 函数用以确定只能运行一个本程序的实例。对于操作数据库的程序,我认为都有必要考虑这个问题:如果同时打开两个程序实例操作同一个数据(例如A实例去修改B实例已经删除的却在A实例中没有即时更新的数据),程序很可能会出错。
●FrmMain中带有Registry的那几个函数用来从注册表读写设置的。事实上.NET提供了很好的XML支持,我现在写程序也喜欢用XML保存设置了,不给系统带来垃圾,还方便修改调试。
●FrmMain中的DAInit函数用以初始化数据适配器,事实上这仅仅是把.NET自动生成的数据库组件的代码移了一个地方,排列得整齐一些吧!要实现优质高效地访问数据库,还是自己写这些代码好。
●FrmMain中的StartSearch函数有提示,在SQL命令中用“''”替代“'”,同时,SQL中其它一些有特殊含义的字符,如“%”、“_”,我们写程序的时候也要注意,否则用户输入这些字符提交给数据库往往会出现错误的结果。这是程序健壮性的要求。
●FrmMain向FrmDataCenter传递数据(FrmDataCenter向FrmDataEditor等亦然),方法是在FrmDataCenter的构造函数中给它传一个FrmMain实例,让它从FrmMain特定的函数中获得数据。事实上主从窗体间互传数据的方法还有很多,值得我们去探索。
●FrmDataCenter中的DeleteRecord函数中删除一条记录用的是DataRow的Delete方法。至于DataRow的Delete方法与DataTable的Remove方法有什么异同,对数据源各有什么影响,曾经把我搅混了。这个问题留给大家自己思考。
●FrmDataEditor中必须保证作为数据库主键的MateStudentID字段是否为空或有重复,这也是程序健壮性和数据库正确性的要求。但我这里用的把已有的主键以数组的形式提交给FrmDataEditor的方法似乎笨了一些,留给大家改进吧!
●FrmDataPrint中读取数据库时判断一个字段是否是System.DBNull.Value是有必要的。.NET在这方面很严格,System.DBNull.Value与String.Empty是两个不同的对象,不要被它们的视觉效果迷惑了。
●FrmDataViewer是个比较有意思的窗体,里面有一个“秘笈”:用键盘依次输入“allinformation”,窗体下方会出现更多的信息。这个功能的实现参见RecordKeyress函数。要实现类似的功能(比如用键盘上的方向键控制窗体上游戏人物的移动),必须将窗体的KeyPreview属性设置为True,否则得到KeyPress事件的将不是窗体而是窗体上的输入控件。
●FrmDataViewer中通过绑定照片文件名到txtPhoto,再在txtPhoto_TextChanged中实现刷新照片显示,显然是我的一个“小聪明”,用这样一个间接的方法避开了使用当时我并不熟悉的委托等事件机制。
●FrmQuickMenu的制作也算是我的一个“小聪明”,我需要在菜单上加一个TextBox,虽然可以用ContextMenu,在它的绘制事件中添加,可我发现那太麻烦,不如用Form自制一个菜单。模拟菜单的高亮显示事实上可以用一个自定义的可响应鼠标事件的Label控件,我也偷懒没做,找了一个现成的LumiSoft.UI控件(后来我一时兴起,把程序中几乎所有的控件都改成LumiSoft.UI的了)至于菜单的3D效果,我则直接给它加了一个Enabled=False的Button作为背景,Button的这种用途还是头一回见吧!
●FrmQuickMenu初始化时执行Activate是有必要的。细心的朋友可能发现Windows的通知区域里的小喇叭有一个bug:在单击小喇叭出现音量调节窗体时如果恰好有别的窗体自动激活,即使你点击屏幕其他地方,音量调节窗体也不会消失,除非你调节一下音量后点击屏幕其他地方它才消失。究其原因,是音量调节窗体由于外界因素偶然没能被Activate,就无从发生Deactivate事件。我们的QuickMenu也是一样。但只要在窗体初始化时主动Activate它,就可以保证点击屏幕其他地方后Deactivate事件的发生,在Deactivate事件中关闭窗体。
●DataPrintManager类实现了用GDI+绘制打印文档,这玩意儿花了我最多的时间。有以下两点值得注意:① PrintOneObject中的e As System.Drawing.Printing.PrintPageEventArgs是传引用而不是传值。②Printing.PrintDocument的PrintPage方法是在方法内代码全部执行完后再判断e.HasMorePages的,不要认为e.HasMorePages = True是一个立即换页指令。如果要换页,要在e.HasMorePages = True之后立即End Sub。
●Dorm类继承了System.IComparable接口,实现按寝室号排序对Dorm类型的数组排序。我们应当充分利用接口这一面向对象特性。
开发感悟
LynxMates是我学习ADO.net后做的第一个成品软件。开发的时候我对ADO.net的一些特性还不是很了解,于是用了一些不是很好的方法。例如在窗体间传数据,我将DataTable不断Copy,又慢又浪费内存。另外前面也说过,这个软件的通用性不是很好,尤其是打印通讯录,仅仅支持现有的这一种模式,打别的样式就得修改源代码,这有悖于面向对象思想。希望大家从我的程序的缺点中得到启示。





