分享
 
 
 

学生考试管理系统ADO版

王朝vc·作者佚名  2006-01-17
窄屏简体版  字體: |||超大  

学生考试管理系统ADO版

作者:Liu_Sir

下载源代码(VC.Net)

下载源代码(VC6)

以前在Delphi下做数据处理,对VC中ADO类的感觉比较麻烦,于是就试着参考别人的ado类封装了两个类,原来的类为 Carlos Antollini

的两个ADO类,版本1.2(VC知识库上有下载),修改了一下,然后继承了一个CADOStorage类,又看过刘永超老师《一个简单的学生成绩管理程序》,想重新用自己的想法设计一下,然后就写了这个小系统:界面结构采用现在数据处理软件常用的MDI形式,如图一:

图一 程序运行画面

我是按照需求分析,数据库设计和一表一类的思想设计了这个系统,下面就从三个主要方面(数据库设计,类设计,编程实现)分析我的设计思路:

一.数据库关系图:

我采用的是ACCESS数据库,对每个表都基本上按照 E-R 关系模式设计,表结构及关系图如图二所示:

图二 数据库关系图

二. 类结构图

采用 Rose 设计了一部分,然后再编程完善后,用 Rose 的逆向工程生成的,基本上包括了现在使用的所有类及其之间的关联关系,如图三:

图三 类之间的关联关系

三. 编程实现部分

主要考虑了以下几个方面:

1.基本表数据的录入

只有输入班级信息,年级信息等一些基础信息后,系统才可以进行其它,如考试信息的管理,那么怎样录入这些基础数据,如果一表建一类的话(这样做最好),如果基础表太多,这样系统编程工作量就会增加,所以想了想,能不能让系统根据数据库的关联关系去选择外键字段然后生成输入界面,再根据用户操作生成sql语句,去更新数据库,如添加记录。如图四所示:

图四 添加记录

图五 添加记录

图四中的年级编号在年级表中索引得到;图五中的班级编号在班级表中索引得到,课程编号在课程表中索引得到,该怎么做?

(1)、数据库结构方面:参考了用友数据库的一些表的设计,然后就想把数据表<表说明>中增加了字段:外键个数,字段0,外键0,外部表0,显示字段0…..字段n:(现在数据库预设计为一个表可以最多有4个外键)。

(2)、程序类方面:设计了一个记录字段信息(CFieldRecord)以及一个基本表类(CBaseTbl):

//记录信息量

struct CFieldRecord

{

char FieldName[20];//字段名(如果为外键字段,则为显示字段)

char Value[255]; //值

bool IsBool; //是否布尔

bool IsStrType; //是否字符串

bool IsVisible; //是否显示

char DisplayName[20]; //对应ID值(用于外键)

char FKtbl[20]; //外键表名或基本表名

CFieldRecord* pFK; //外键信息

};

//基本表的处理

class CBaseTbl : public CObject

{

public:

CBaseTbl();

virtual ~CBaseTbl();

CList<CString,CString& m_TblList;//名称列表

void GetTblnames();

//单表记录数组,默认记录最后一条

bool GetFieldRecord(CPtrArray& FieldArray,CString ctblname,CString constr="");

bool RemoveRecord(int CurRecordPos);

protected:

CADOStorage m_Storage;

//单表记录数组,默认记录最后一条

void AddExtraFieldRecord(CPtrArray& FieldArray,CString ctblname);

private:

CString m_TblName;

public:

//选择联合表

bool SelectUnionTbl(CString StrTblname,CString& Realtbl,bool ByRealTblName=false);

void RefreshList(CListCtrl& List1);

void ReQuery(CString TblName);

void ExecSql(CString SqlStr);

};

(3)、如在基本表视中点击添加数据过程:

①、调用过程:

//选择添加记录

void CStudentScoreView::OnADDRecord()

{

ASSERT(this-m_hWnd);

CBMDialog dialog1;

CStudentScoreDoc* pDoc=this-GetDocument();

pDoc-m_BaseTblList.GetFieldRecord(dialog1.RecordArray,this-m_CurTblName);

dialog1.ISADD=true;

dialog1.m_hParent=this-m_hWnd;

dialog1.m_OprTblName=this-m_CurTblName;

if(dialog1.DoModal()==IDOK)

{

AfxMessageBox("添加记录!");

//ASSERT(dialog1.m_hWnd);

}

}

申明为:文档类中 CBaseTbl m_BaseTblList;//表信息实例

对话框类中 CPtrArray RecordArray;//字段数组(用于保存字段的类型及外键信息)

传递参数:表名 this-m_CurTblName,

是否添加信息:dialog1.ISADD=true;

视的句柄的 Dialog1.m_hParent=this-m_hWnd;

以及最关键的一个量 dialog1.RecordArray(this-m_CurTblName 的记录及外键信息)

进行初始化后传递给窗体类CBMDialog;

那么pDoc-m_BaseTblList.GetFieldRecord(dialog1.RecordArray,this-m_CurTblName);如何实现把this-m_CurTblName的字段信息添加到RecordArray列表中去呢?

咱们看一下这个方法的定义:

//单表记录数组

bool CBaseTbl::GetFieldRecord(CPtrArray& FieldArray,CString ctblname,CString constr)

{

ASSERT(ctblname.Trim()!="");

//1.判断及清理工作

…省略

CFieldRecord* fldrec;

CADOFieldInfo fldinfo;

CString fldvalue;

//2.判断记录位置

bool IsZeroRecord;//记录数为0

…省略

int count=this-m_Storage.GetFieldCount();

//3.添加字段记录到指针数组

for(int i=0;i<count;i++)

{

fldrec=new CFieldRecord();

if(IsZeroRecord)

{

fldvalue="";

}

else

{

this-m_Storage.GetFieldValue(i,fldvalue);

}

this-m_Storage.GetFieldInfo(i,&fldinfo);

strcpy(fldrec-FKtbl,ctblname);

strcpy(fldrec-FieldName,fldinfo.m_strName);

strcpy(fldrec-Value,fldvalue);

switch(fldinfo.m_nType)

{

case VT_DATE:

fldrec-IsStrType=true;

fldrec-IsBool =false;

break;

default:

fldrec-IsStrType=false;

fldrec-IsBool =false;

break;

}

fldrec-pFK=NULL;

fldrec-IsVisible=true;

FieldArray.Add(fldrec);

}

//添加外键信息

this-AddExtraFieldRecord(FieldArray,ctblname);

return true;

}

基本过程就是两个:

一是添加fldrec=new CFieldRecord()字段信息;

二是查询是否有外键this-AddExtraFieldRecord(FieldArray,ctblname);并把外键信息添加到fldrec的链表尾部,然后在加入到

FieldArray.Add(fldrec);

②、有了这些工作下面的显示界面如图四、五就简单了,就是逆向的读取 FieldArray 的过程:

在CBMDialog类中:

//动态创建组件

CFieldRecord* pRecord;

int top=0;

for(int i=1;i<=this-RecordArray.GetCount();i++)

{

top=(i-1)*22;

pRecord=(CFieldRecord*)RecordArray.GetAt(i-1);

this-CreateStatic(pRecord,top,70+i);

//布尔或有关联外键

if((pRecord-IsBool)||(pRecord-pFK!=NULL))

this-CreateCombo(pRecord,top,10+i);

else

this-CreateEdit(pRecord,top,10+i);

}

注:有关联外件就读取关联表显示字段的索引信息,然后添加到 ComboBox 中,

显示出界面:

如何修改和添加记录呢?

//发送修改或添加消息

void CBMDialog::SendChangeMsg(void)

{

CWnd* pWnd;

CString value,Msg;

CFieldRecord* pRecord;

for(int i=1;i<=this-RecordArray.GetCount();i++)

{

pWnd=this-GetDlgItem(10+i);

if(pWnd)

{

pRecord=(CFieldRecord*)RecordArray.GetAt(i-1);

if ((!pRecord-IsBool)&&pWnd-IsKindOf(RUNTIME_CLASS(CComboBox)))

{ //非布尔类型,且有关联字段时

CComboBox* pCombo=(CComboBox*) pWnd;

CFldValue* p;

int index=pCombo-GetCurSel();

p=(CFldValue*)pCombo-GetItemDataPtr(index);

value=p-FieldValue;

}

else

pWnd-GetWindowText(value);

if(value.Trim()=="")

{

Msg=(CString)pRecord-FieldName+"不能为空!";

AfxMessageBox(Msg);

pWnd-SetFocus();

return;

}

else

{

if((i==1)&&(!this-ISADD))//如果是修改的话,则不对第一字段操作

{}

else

strcpy(pRecord-Value,value);

}

}

}

//发送字符串

CString cSend;

if(this-ISADD)

{

cSend=this-GenerateInsertSql();

}

else

{

cSend=this-GenerateUpdateSql();

}

LPARAM lparam=(LPARAM)&cSend;

::SendMessage((HWND)this-m_hParent,WM_USER+51,0,lparam);

}

这是基本的信息,根据显示内容生成sql语句,发送消息给基本表视,完成数据库更新操作。

③、视的更新过程:

LRESULT CStudentScoreView::OnExecSql(WPARAM wParam,LPARAM lParam)

{

CString c;

c=*((CString*)lParam);

CStudentScoreDoc* pDoc=this-GetDocument();

pDoc-m_BaseTblList.ExecSql(c);

this-RefreshShow();

//AfxMessageBox(c);

return 0;

}

2.关于考试过程的编码

主要是依靠几个类来实现:

* CExam 考试类 用于考试的信息登记

* CExamClass 考试班级类

* CExamStudent 考试学生类

* CExamSubject 考试科目类

他们都聚合了一个数据集TADOStorage,然后通过数据集完成考试信息的记录,计算:

class CExam : public CObject

{

public:

CExam();

virtual ~CExam();

CString m_No; //考试编号

COleDateTime m_Date; //考试日期

CString m_TermNo; //学期编号

CStringList& GetTerms();

CStringList* GetNos();

protected:

CADOStorage m_Storage;//数据库连接

CString m_TblName; //表名称

private:

CStringList m_TermList;//学期列表

CStringList m_NoList; //编号列表

public:

void ClearTermList(void);

void ClearNoList(void);

void GetExamByNo(CString No);//获取考试信息

bool IsNoExisted(CString No);//编号是否存在

void AddExam();

void DeleteExamByNo(CString No);

};

(1)、在文档类中申明CExam m_Exam.添加记录

void CExamView::OnBnClickedButton2()

{

CEdit* pEdit=(CEdit*) this-GetDlgItem(IDC_EDIT1);

CString ExamNo;

pEdit-GetWindowText(ExamNo);

CExamDoc* pDoc=this-GetDocument();

if(pDoc-m_Exam.IsNoExisted(ExamNo))

{

AfxMessageBox("不能添加重复记录!");

return;

}

else

{

//添加记录

pDoc-m_Exam.m_No=ExamNo;

CDateTimeCtrl* pPicker=

(CDateTimeCtrl*)this-GetDlgItem(IDC_DATETIMEPICKER1);

pPicker-GetTime(pDoc-m_Exam.m_Date);

CComboBox* pComb=(CComboBox*)this-GetDlgItem(IDC_COMBO1);

pComb-GetLBText(pComb-GetCurSel(),pDoc-m_Exam.m_TermNo);

pDoc-m_Exam.AddExam();

}

}

(2)、然后看: pDoc-m_Exam.AddExam();

void CExam::AddExam()

{

CString FldList,ValueList;

FldList="考试编号,考试日期,学期编号";

ValueList="''''"+this-m_No+"'''',''''"+this-m_Date.Format()+"'''',''''"+this-m_TermNo+"''''";

this-m_Storage.ExecInsertSql(this-m_TblName,FldList,ValueList);

}

这是一个与数据库交互的过程。

其它类的处理过程类似,就是对数据库表的操作用类来封装,去执行。当然怎么做可能有一些不妥之处,如一个类包含一个数据集,可能占有存储空间比较大,对象如果进行拷贝复制的话

,有可能占有系统的存储空间;所以有的人建议把对数据库的操作让一个代理类去实现,当然各有优缺点,这也是对OR

Map争论比较多的一个问题,感觉java

Bean实体在这方面做的更好一些。我编程的时间也不算太长,考虑上的深度不够和自己的水平有限,当然还有很多不足之处,甚至BUGS,当然,希望大家多提出批评意见。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有