Download presentation
Presentation is loading. Please wait.
1
过程性保存文本格式的实现 计算概论小课题 王元康
2
Lay Out 课题的最终目的 基础类和算法 用visual studio2010创建MFC工程 实现程序预期功能 成品展示及分析 课题总结
参考资料
3
课题的最终目的
4
课题的最终目的 课题的最终成品 一个基于核心算法的简单文本编辑器软件(用 visual studio2010和MFC框架完成)
与之配套的一个新的文件类型(prt:process recorded text) 该编辑器具有文本读写功能(只支持.prt文件)和 查看并恢复一切之前保存过的状态的功能。
5
基础类和算法
6
基础类 1,基础类 现在拥有一个文本编辑器,用户在三种条件下依保存: Abcdefghijklmnopqrstuvwxyz 保存
Abcdefghijklmnopqrstuvwxyzabc 保存 defghijklmnopqrstuvwxyzabc 保存 算法将记录三个过程对象: (0,add,” Abcdefghijklmnopqrstuvwxyz”) (26,add,”abc”) (0,del,3) 现在将这样的过程对象抽象为一个类:Changer(改变 子)类。
7
Changer类成员变量 Class Changer{ public: int begin_index; int type;
CString a; int number; ……………… }; 有四个成员变量,begin_index标记改变的发生位置, type标记类型(添加或删除),a标记添加的内容, number标记删除的位数。
8
Changer类成员函数 class Changer{ ……………… public:
Changer(int begin_index,CString a); Changer(int begin_index,char b); Changer(int begin_index,int number); Changer(int tpye); Changer(); Changer(Changer & c); bool isadder(); void Change(CString &d); }; 有这些成员函数:六个构造函数,isadder()判断是不 是添加,Change()对一个CString进行Changer所对应 的操作。
9
以上就是类的基本结构,当然,为了配合串行化对 象和MFC架构以后还要进行很多修改。
10
算法 将Changer修改为从CObject类继承(这也为串行 化提供支持)。
class Changer : public CObject{………………}; 将一组Changer放在MFC提供的容器CObArray之 中。
11
recover CString recover(CObArray *pmemory,int end_index,CString a){
if(-1==end_index||end_index>=pmemory->GetSize()){ end_index=pmemory->GetSize(); } //第二、三个参数使用默认值调用的时候,从空状态恢复所所有的。 CString b=a; for(int i=0;i<end_index;i++){ reinterpret_cast<Changer *>(pmemory->GetAt(i))- >Change(b);//这个转换应该没大问题,因为memory里的指针是 Changer转过去的。 return b; 我们可以实现对CString对象的连续操作。 通过recover这个函数来实现,他需要提供一个CObArray指针 pmemory(包含一列Changer),实际进行的操作数end_index(默认 是全部执行),和初始值(默认为空CString)。
12
seek_change //先实现这个函数
int get_char_index(CString a,char x,int begin_index){ int length=a.GetLength(); for(int i=begin_index;i<length;i++){ if(a[i]==x) return i; } return length; }//在字符串a中寻找x,从指标begin_index开始。 未达返回length
13
CObArray * seek_change(CString b,CString a){
int length=min(a.GetLength(),b.GetLength()); CString temp_string; CObArray *pmemory=new CObArray; for(int i=0;i<length;i++){ if(a[i]!=b[i]){//获取上下文搜索到的指标,a 是上文,b是下文。 int status1=get_char_index(a,b[i],i);// 在上文中搜索 int status2=get_char_index(b,a[i],i); //在下文中搜索
14
if(status1==a.GetLength()&&status2==b.GetLength()) {
Changer* pc=new Changer(i,b[i]); pmemory->Add(pc); pc->Change(a); } else if(status1<=status2){//如果上文搜索得到 的指标更小,就将上文搜索过的元素去除。 Changer *pc=new Changer(i,status1-i); else{//如果下文搜索得到的指标更小,就将下文搜 索过的元素添加。 Changer* pc=new Changer(i,b.Mid(i,status2-i)); }}}
15
if(a.GetLength()>b.GetLength()){//以下两个判断处 理多余的长度
Changer* pc=new Changer(length,int(a.GetLength()-length)); pmemory->Add(pc); pc->Change(a); } else if(a.GetLength()<b.GetLength()){ Changer* pc=new Changer(length,b.Right(b.GetLength()-length)); simplify(pmemory);//这里产生完之后要化简,化 简函数在下方会给出。 return pmemory;
16
simplify void simplify(CObArray *pmemory){
for(int i=pmemory->GetSize()-1;i>0;i--){ //第一类化简,共点删除。 while(1){ if(i==pmemory->GetSize()){ break; } Changer* ci=reinterpret_cast<Changer*>(pmemory- >GetAt(i)); Changer* ci_1=reinterpret_cast<Changer*>(pmemory- >GetAt(i-1));
17
if((ci->begin_index==ci_1- >begin_index)&&((ci->type)&&(ci_1->type))){
Changer* pc=new Changer(*ci_1); pc->number=ci- >number+ci_1->number; //释放堆内存 delete ci; delete ci_1; pmemory->RemoveAt(i- 1,2); pmemory->InsertAt(i-1,pc); } else{ break;
18
//第二类化简,连续加合并。PS:不可能和上一个 同时触发
while(1){ if(i==pmemory->GetSize()){ break; } Changer* ci=reinterpret_cast<Changer*>(pmemory- >GetAt(i)); Changer* ci_1=reinterpret_cast<Changer*>(pmemory- >GetAt(i-1));
19
if(!(ci->type||ci_1->type)&&(ci- >begin_index-ci_1->begin_index==ci_1- >a.GetLength())){ Changer* pc=new Changer(*ci_1); pc->a=ci_1->a+ci->a; pmemory->RemoveAt(i- 1,2); pmemory->InsertAt(i-1,pc); } else{ break;
20
以上三个算法便是主体算法了,构建完基础类和主 体算法就可以用visual studio2010建立MFC框架 应用程序了。
21
用visual studio2010创建MFC工程
22
visual studio2010 是一个支持多文档、多窗口的应用程序,功能很强 大,拥有强大debug能力和图形化编程支持。
23
MFC MFC是微软提供的应用程序开发框架,它分为单文 档支持和多文档支持,采用文档、框架、视类三部 分(每部分对应一个类)来构建一个文件处理的应 用程序(当然图形处理、网页处理也是文件处理)。 类与类之间用类方法链接。主要的基类有: CDocument、CMainFrm、CWinApp、CView。 然后用户从这些类上派生的类便拥有基本的文件处 理手段。
24
实现程序预期功能
25
应用程序架构
26
首先,test.h中定义了CtsetApp类,继承 自CWinAppEx类。
testDoc.h中定义了CtestDoc类,继承自 CDocument。 testView.h中定义了CtestView类,继承自 CEditView,CEditView继承自CView并附 带了简单的文本处理功能。 Changer.h中定义了Changer类和与 Changer类相关的非成员函数 。 RecoverDlg.h中定义了CRecoverDlg类, 继承自CDialogEx类,它是程序中的第二 个窗口,可通过按钮调出并实现恢复文件 的功能。
27
Changer类的串行化支持以及数据的的存取
//Changer.h class Changer : public CObject { public: ……………… DECLARE_SERIAL(Changer); void Serialize(CArchive& ar); }; //Changer.cpp IMPLEMENT_SERIAL(Changer,CObject,1); void Changer::Serialize(CArchive& ar){ if(ar.IsStoring()){ ar<<begin_index<<type<<a<<number; } else{ ar>>begin_index>>type>>a>>number;
28
这样我们就能用CArchive对向来读取和保存文件中 的Changer数据。由于CObArray本身支持串行化, 故可以建立一个CObArray *变量来保存两次修改 之间的所有的Changer,并在CtestDoc类建立一 个CObArray *类型的成员变量m_pallmemory来 保存所有的CObArray *。 然后在Serialize函数中实现保存和读取。
29
void CtestDoc::Serialize(CArchive& ar)
{ if(ar.IsStoring()){//如果是存储过程 CString temp; //这里要先get以下view POSITION pos=GetFirstViewPosition(); GetNextView(pos)->GetWindowTextA(temp); CObArray * new_pmemory;//new_pmemory用以储存 两次保存之间的Changer。 new_pmemory=seek_change(temp,m_content); if(0!=new_pmemory->GetSize()){ m_pallmemory->Add(new_pmemory); //将new_pmemory压入m_pallmemory } //刷新m_isnew m_isnew=false; m_content=temp;//将这个内容刷新为下一次保存做准 备 m_pallmemory->Serialize(ar);//调用CObArray的 Serialize函数保存数据。
30
else{ //如果是读取内容 m_pallmemory->Serialize(ar);//调用 CObArray的Serialize函数读取数据。 int nSave=m_pallmemory->GetSize(); for(int i=0;i<nSave;i++){ m_content=recover(reinterpret_cast<CObArra y *>(m_pallmemory->GetAt(i)),-1,m_content); } //这里也要get一次view。 POSITION pos=GetFirstViewPosition(); GetNextView(pos)- >SetWindowTextA(m_content); //刷新m_isnew m_isnew=false;
31
创建Dialog并响应消息 一个Dialog(对话框), 包含三种控件,左边的 是List Box,对应的控 制类是CListBox,我在 CRecoverDlg类创建了 一个CListBox类型的成 员变量m_listctrl来控制 它。右边是一个Edit Control,我没有使用 他的control对象而是创 建了一个CString类对象 来绑定它的文本。最下 面是三个按钮
32
List Box的处理 首先在CRecoverDlg::OnPaint中获取CtestDoc中的数据并绘制 列表。
void CRecoverDlg::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: 在此处添加消息处理程序代码 // 不为绘图消息调用 CDialogEx::OnPaint() if(!m_painted){ //这些主要是获取Doc类的指针(Doc类就是指CtestDoc类, 下同)。 CMainFrame* pFrame=(CMainFrame*)AfxGetMainWnd(); CtestView* pView = (CtestView*)pFrame- >GetActiveView(); CtestDoc *doc=pView->GetDocument();
33
int nSave=doc->m_pallmemory->GetSize();
for(int i=0;i<nSave-1;i++){ char a[10]; m_listctrl.InsertString(0,_itoa(i- nSave+1,a,10));//InsertString在指定位置添加字符串。 } m_listctrl.InsertString(0,"当前状态"); m_context=m_nowtext;// View类在调用Dialog之前 将现在屏幕数据保存在n_nowtext中,此时作为文本提示的 默认值,也是当前状态的值。 UpdateData(false);//将m_context的改变load一下。 m_painted=true;
34
之后,添加对ListBox项点击的消息处理函数
void CRecoverDlg::OnLbnSelchangeList1() { // TODO: 在此添加控件通知处理程序代码 int n=m_listctrl.GetCount()- m_listctrl.GetCurSel();//FetCurSel获取选中索引号。 if(1!=m_listctrl.GetCount()){ if(0!=m_listctrl.GetCurSel()){ CMainFrame* pFrame=(CMainFrame*)AfxGetMainWnd(); CtestView* pView = (CtestView*)pFrame->GetActiveView(); CtestDoc *doc=pView- >GetDocument(); CString temp; for(int i=0;i<n;i++){ temp=recover(reinterpret_cast<CObArray *>(doc->m_pallmemory->GetAt(i)),-1,temp); }//计算第n次保存之后的文档内容
35
GetDlgItem(IDC_TEXT)- >SetWindowTextA(temp);//将文档内容显示
//这里也可以m_context=doc- >m_content;UpdateData(false);load数据 } else{ GetDlgItem(IDC_TEXT)- >SetWindowTextA(m_nowtext);//第一个单独画吧 CMainFrame* pFrame=(CMainFrame*)AfxGetMainWnd(); CtestView* pView = (CtestView*)pFrame- >GetActiveView(); CtestDoc *doc=pView->GetDocument(); GetDlgItem(IDC_TEXT)- >SetWindowTextA(m_nowtext); //m_context=doc->m_content; //UpdateData(false);
36
对于三个CButton的逻辑设计 第一个,舍弃之后代表我要恢复到在List Box中选 中的这个状态,并且将自己已经进行的在该状态之 后的改变全部抛弃。 第二个,保留之后代表我要恢复到在List Box中选 中的这个状态,是以添加一个从现状算到选中状态 的过程来实现的。 第三个,取消就是什么都不做(不响应)。
41
在使用Dialog前要求用户保存文件 最后我们在调用Dialog前用n_isnew标签来判断是 否为新建的文档,如果是要求用户保存(否则恢复 功能将没有意义)
42
成品展示及分析
43
成品展示 现场展示 不贴图了
44
分析 通过改变子的迭代实现了过程性保存的功能,可能 存在bug,但是日常使用压力不大。
文件的大小的方面,上面的文件最后有4kb,直接 用记事本保存需要1kb。
45
课题总结 基本实现了课题的预期。 通过本课题,我的收获了使用 visual studio2010和MFC编程的 技巧,同时实现了原创算法。
46
参考资料: [1] MSDN中文网页版 appId=Dev10IDEF1&l=ZH- CN&k=k(MSDNSTART)&rd=true [2] MFC视频教程全集 作者:孙鑫
47
谢谢
Similar presentations