C语言课程实践:自制文本编辑器_第1页
C语言课程实践:自制文本编辑器_第2页
C语言课程实践:自制文本编辑器_第3页
C语言课程实践:自制文本编辑器_第4页
C语言课程实践:自制文本编辑器_第5页
已阅读5页,还剩62页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

文本编辑器

文本编辑器是最常用日勺文档创立和编辑工具。伴随计算机科学与技术的发展,用来处

理文本的编辑器随地可见,并且形式多样。例如,Windows下口勺记事本,写字板,

EditPlus,UltraEdit等都是十分优秀日勺文本编辑器和处理工具。在本章中,我们将向读者讲解

怎样运用C语言来发展开发一种简易口勺文本编辑器。

1设计目的

运用C语言口勺单链表数据构造及有关函数,本章编程实现了一种与DOS操作系统下的I

Edit相似的J文本编辑器。再次文本编辑器中,顾客可以逍过快捷和选择菜单项,完毕基本日勺

文本编辑器和文献处理T作。

通过文章曰勺简介,读者可以理解文本编辑器口勺开发过程,掌握菜单口勺开发技巧,加深而

文献操作的理解。更重要的是,但愿此程序能抛砖引玉,引领读者掌握编程日勺措施和技巧,

开发出更优秀日勺程序。

2功能描述

如图.1所示,文本编辑器重要由五大功能模块构成,它们分别是文献操作模块,文本编

辑模块,剪切操作模块,菜单控制模块和协助及其他模块。下面分别简要简介功能模块口勺功

能。

(1)文献操作模块。在文献操作模块中,重要完毕文献的创立,打开,保留和另存操

作。顾客可以选择File菜单上的New子菜单来完毕新建文本文献操作;选择File菜单上的

Save子菜单来完毕保留文献操作选择File菜单上的Open子菜单来完毕打开文献操作;选择

Flie菜单上的Saveas子菜单来完毕文献日勺另存为操作。在文献的J打开,保留和另存为操作

中,系统会提醒顾客输入文献途径及文献名。值得•提时是,当顾客打开•种文献时,指定

的文献必须存在,否则系统会报错。

(2)文本编辑器模块。在文本编辑器模块中,重要完毕在编辑窗口中以添加或插入的

方式输入字符,删除光标所在目前位置日勺单个字符或前一种位置H勺单个字符,朝上下左右4

个方向口勺光标移动操作。当光标所在位置及背面口勺位置没有字符时,系统会以添加口勺方式输

入字符;当光标所在位置及背面的位置有字符时,系统会已插入的方式输入字符。顾客可以

使用Backspace键删除光标前一种字符,也可以使用Del键删除目前位置的字符或删除Ctrl+

左移(右移)键i选定了的多种字符。顾客可以使用左移健(一),右移键(一),上移键(t)

和下移键(I)来移动光标位置。

(3)剪贴板操作模块。在剪贴板操作模块中,重要完毕对已选定文本的剪切,复制,

粘贴工作。假如顾客要剪切文本以便可以将它移动到其他位置,可通过CtH+X左移键(右

移键)先选定文本,然后选择Edit菜单上的Cut子菜单或按Ctrl+X快捷键来完毕剪切任务。

假如顾客要复制文本以便可以将它黏贴到其他位置,必须先选定文本,然后选择Edit菜单

上的Copy紫菜单或按Ctrl+C快捷键来完毕豆制任务。假如顾客要粘贴剪切或复制的I文本,

必须将光标置于要粘贴文本的位置,然后选择Edit菜单上的Paste子菜单或按Ctrl+V快捷

键来完毕粘贴任务。

(4)菜单控制模块。在菜单控制模块中,重要完毕菜单时显示。光带条在子菜单之间

的上下移动或菜单之间的左右移动和子菜单项I)勺选用。本文本编辑器共有Flie,Edit和Help3

个子菜单项,顾客可以分别按F1,F2和F3功能键来完毕这3个菜单项的调用,即显示某项

菜单。顾客可按光标上移或下移键在某菜单项的子菜单之间循环移动,也可使用光标区左移

或右移键在3个菜单项之间循环移动。当光带移动到某个字菜单项上时,顾客此时可使川

Enter键来选用有关菜单项选择项。

(5)协助及其他模块。在协助及其他模块中,重要完毕系统功能及按键的I简要简介。

其他模块包括文本的迅速预览和窗II的显示。顾客可按F10功能键来打开迅速预览窗口,

在迅速预览窗口中没有功能菜单条。主窗II要有菜单栏,文本编辑区和状态栏三大部分构成,

菜单栏用来显示菜单项,文本编辑区重要用来文本字符的输入,删除等操作,状态栏重要用

来显示目前光标在文本窗口中口勺坐标值。

注意:TurboC2.默认定义的文本窗口为整个屏幕,共有80列(或40列),25行的文本单元,每

个单元包括一种字符和一种属性,字符即ASCH码字符,属性规定该字符的颜色和强度。同步,他还规定

整个屏幕的左上角坐标为(1,1),右下角坐标为(80,25)。并规定沿水平方向为X轴,方向朝右:眼垂

直方向为Y轴,方向朝卜。

3总体设计

3.1功能模块设计

在.2节中,简朴描述了各功能模块的作用,下面分别简介各功能模块的详细设计。在简

介各功能模块的详细设计之前,有必要先描述一下主程序的执行流程。

1.程序执行主流程

文本编辑器程序执行主流程如图.2所示,它是在main()函数中实现的。他首先初始

化某此全局变量及构造数组,接着调用drawmain()函数来显示主窗口,然后调用while。)进

入主循环,等待顾客按键,最终程序根据顾客的按键值,进行对应的处理,完毕文本编辑U勺

有关工作。下面对图.2中的按键判断和有关处理作补充阐明。

(1)若按键为常规字符,即其ASCII码不小于32不不小于127,则继续判断在文本编

辑区的H前光标位置有无字符,若有字符,则调用insert。函数,将此字符插入在目前位置,

否则在判断没有满行后,将此字符添加在单链表的数据域中,若此行已满,则执行添加新行

保留数据的数据构造。在此程序中,共有两种类型的单链表,我们称其为行单链表和列单链

表,一种列单链表用来保留一行的字符,有多少行即有多少个这样的单链表。行单链表只有

一种,它的每个节点口勺数裾域用来保留不一样列单链表的首节点的地址。例如,第4行第4

列欧J字符保留在行单链表的第4个节点的数据域所指H勺列单链表的第4个节点的数据域中。

有关详细数据构造的定义,在背面口勺小节中会有详细简介。

1)打开文献

文献H勺打开流程如图.3所示,它首先提醒顾客输入要打开文献日勺文献名,若该文献不存在

或由于其他原因打开失败,则会结束文献打开操作。若文献成功打开并且文献指针没有到文

献尾,则从文献中一次读取一种字符,并将该字符添加到一列单链表节点中,直至碰到换行

符(ASCII码10)或持续渎取字符个数不小于76(在此文献编辑器中,每行最多为76个字

符)。当列单链表形成后,它的首地址将被保留至行单链表的对应节点日勺数据域中,如此动

作,直至文献指针指向文献尾部而结束。

注意:由于本程序中每行以回车符(ASCH码为13)结束,而当用Windows的记事本创

立•利文本文献,打开此文献并用fgetc()函数读取时,程序写入列单链表节点中时值是ASCII

码为13的回车符。

2)保留文献

保留文献操作重要完毕将单链表中的数据写入文献中的任务,它口勺详细实现流程如下。

(1)顾客输入一种保留此单链表数据的文献名。

(2)以只写方式打开此文献,若成功打开此文献,见执行环节(3);否则退出。

(3)读取行单链表中的节点数据域的值,若值不为空,则执行环节(4);否则执行环节

(6)o

(4)依次读取行单链表节点中保留的首地址日勺对应列单链表节点的数据域H勺值,若其值

为回车符,则用换行符替代后将其写入文献中:否则直接将其值写入文献中,直至

该列单链表中指针域为NULL时最终一种元素结束。

(5)读取行单链表中的下一种节点,并跳至环节(3〕。

(6)关闭文献,退出。

3.文献编辑模块

在文献编辑模块中,重要完毕以添加或插入的方式输入字符、删除光标所在的目前位置或前

一种位置的单个字符、朝上下左右4个方向的光标U勺移动操作。下面简介这4个功能的详细

设计与实现。

1)添加字符

当光标处在文本编辑时最终一行的位置且光标背面没有字符时,若此时输入字符,程序会判

断一行中字符的个数,若字符个数不等于76,则在目前的列单链表的最终一种节点中保留

输入的字符,然后添加一种新的节点来保留下一种输入的字符:若等于76,则在H前的列

单链表的最终一种节点中保留输入的字符,然后在行单链表中添加种新节点用来保留下一

行的列单链表IJ勺首地址,添加一种新的列单链表节点来保留下一种顾客输入的字符。

2)插入字符

若光标所在处已经存在字符,当顾客在H前位置输入字符时,程序会调用insert。函数将输

入的字符在光标所在的位置处在列单链表中插入,插入完毕后,会调用lest。函数来检查各

行与否满足只有76个字符的条件,若不满足此条件,则在此函数中会对多出的字符进行处

理。下面分别对列单链表中字符的插入过程和单链表的检查过程进行简介。

若在第m行,第n列的位置插入一种字符,其insert。过程描述如下:

(I)定位至行单链表中日勺第m个节点,得到这个节点日勺数据域的J值,其值为对应列单链

表中第一种节点的地址。

(2)定位至列单链表中日勺第n-1个节点。

(3)创立一种新的列单链表节点,用其数据域保留输入的字符。

(4)若字符插入在第m行第1歹人则直接将行单链表中第m个节点的数据域的值变化为

新口勺列单链表节点的地址,新的列单链表节点的指针域指向列单链表中本来的第1

个节点。若字符不是插入在第m行第1列,则执行简朴的单链表中插入节点的操作。

(5)插入此字符后,调用test。函数,从第m行开始检查各行与否满足每行只容许有76

个字符的条件,若不满足此条件,则必须进行处埋。

其test()检查处理过程描述如下:

(1)用指针tail指向已经插入了新节点的列单链表中的最终一种节点。

(2)若此单链表中节点数超过76个,则指针pl会指向此列单链表中的第76个节点,指

针p2指向第77个节点,并将pl所指节点的指针域设置为NULLo

(3)若tail所指节点的数据域为Enter键(ASCII为13)且在行单链表中只有m个节点,

则在此行单链表中添加一种新的节点,新节点U勺数据域为p2的值,指针域为空,并

将m节点的指针域指向它;若tail所指节点反而数据域为Enter键(ASCH为13〕且在

行单链表中有多于m个节点,与上面不一样的是,它执行的是在行单链表插入一种

新口勺节点的操作。

(4)若tail所指节点的数据域不是回车符,pl的数据域为回车符并且行单链表中只有m

个节点,则在行单链表中添加一种新的节点,新节点的数据域为p2的值,指针域为

空,并将第m节点口勺指针域指向它;若tail所指节点的数据域不为回车符并且行单

链表中有多于m节点,则将tailH勺指针域指向行单链表中第m+1个节点所指的列单

链表的首节点,并将行单链表中第m+1个节点的数据域修改成指针p2的值,并对

行单链表中第m+1个节点所指的列单链表进行tcst()检杳,相似的处理过程至行单

链表中的最终一种节点结束。

3)删除字符

当顾客按下Del键时,系统会调用del()函数在单链表中删除目前光标所在处的字符:当顾

客按下Backspace键时,系统也会调用这个函数在单链表中删除目前光标所在处前一种位置

的J字符。

若在第m行、第n列的位.置删除一种字符,其在列单链表中删除一种十点的操作域插入_L

作十分相似,因此这里重点简介删除该字符后,单链表中数据的前移工作过程。

(1)在对应的列单链表中删除第n个节点。

(2)判断第m行与否存在并且判断在此行中与否有字符,若第m行不存在,或此行中没

有字符,则结束字符删除过程,否则执行环节(3)。

(3)用tail保留第m行对应列单链表中最终•种节点的地址,并将最终一种节点的指针

域保留为第m+1行中对应列单链表的第一种元素的地址。

(4)计算出第m行中没有字符I向位置的个数num,然后在第m+1行的对应列单链表中

截取num个节点,并将行单链表中U勺第m+1节点的数据域改为对应列单链表中的第

num个节点后H勺节点的地址。

(5)调用m++语句,是变量m增1,跳至环节(3),开始对下一行进行处理。

4)移动光标

移动光标的操作重要运用goloxyO函数来实现,过程非常简朴,只需对目前的光标位置和移

动方向进行判断后,即可执行gotoxy()过程。例如,假如目前光标在第m行第1列,且按F

了光标左移键,只需将光标移至第m-1行,第76列。

4.剪贴板操作模块

在剪切板操作模块中,重要完毕对已选定文本日勺剪切、复制和粘贴工作,因此剪贴板操作与

文本选定工作亲密有关。下面分别简介文本的选定和对选定文本的剪切、复制和粘贴操作的

详细实现。

1)选定文本

顾客可按Ctrl+v■或CtH+,来选定文本,就详细实现而言,两者基本相似。在简介选定文本

的实现过程之前,先简要海介一种全局的构造数组川,它的元素的类型为record构造体类

型,每一种元素可保留一种字符的x坐标、y坐标和字符值。其文本选定的实现过程如下:

(1)当顾客按下Ctrl+《或CtH+->键时,程序将目前光标位置向左或向右移动一种位置。

(2)目前光标所在位置的字符的x坐标、y坐标和字符值保留在数组元素「[value]中value

从0开始,若按减为CtrI+<-,value值在本来基础上每次加1;若按键为Ctrl+->.value

值在本来基础上每次减1.

(3)调用Colorview。函数,用不一样的颜色来显示已经选定的目前文本,以到达突出选

定文本的效果。

2)剪切

顾客可按Qrl+X键或通过Edit菜单项选择项来剪切选定的文本,若之前没有选定的文本,

此按键无效。它的实现过程如下:

(1)若全局变量value时值不小于0(不小于。表达已经有文本选定),则执行下面操作。

(7)

(2)保留目前位置H勺坐标,运用循环语句,依次运用x|0]至xlvahic-ll数组元素保留已选定

字符的坐标,调用del()函数在单链表中一次删除一种选定的字符。

(3)运用全局变量backup保留value时值后,将value赋值为0。

(4)重新在文本编辑器中显示单链表中保留口勺所有字符,并将光标置位到本来日勺位置。

3)复制

顾客可按Ctrl+C键或通过Edit菜单项选择项来复制选定的文本,复制操作的实现比剪切操

作简朴,它的实现过程如下:

(1)保留目前位置的坐标。

(2)运用全局变量backup保留value时值后,将value赋值为0。

(3)重新在文本编辑器中显示单链表中保留的所有字符,并将光标置位到本来的位置。

4)粘贴

顾客可按CtH+V键或通过Edit菜单项选择项,完毕粘贴操作。这一操作必须在剪切或复制

操作之后出现。它的详细实现过程如下:

(1)若全局变量backup时值不小于0(不小于0表达已经有字符放入了剪贴板数组)中,

则执行下面的操作。

(2)保留目前位置的坐标,运用循环语句,依次运用x[0]至x[backup-l]数组元素保留已

选定字符的坐标和字符值,调用insert()函数在单链表中一次插入一种字符。

(3)重新在文本编辑器中显示单链表中保留的所有字符,并将光标置位到本来的位置。

5.菜单控制模块

在菜单控制模块中,重要完毕菜单时显示、光带条在子菜单之间日勺上下移动或菜单之间日勺左

右移动以及子菜单项的I选项T.作。下面分别简介这3项功能的I详细实现。

1)显示菜单

顾客可按Fl、F2和F3功能键来分别调用File、Edit和Help菜单,即完毕菜单时显示。当

按卜这3个功能键中的某个功能键时,程序会调用mcnuctrl()函数来完毕菜单口勺调用操作。

在mcnuctrl()函数中,会根据功能键口勺键值调用drawmenu(value,flag)函数,参数value>

flag都为局部变量,分别用来保留调用某个菜单、某个菜单下的第几种菜单项选择项。例如,

按F1键后,它的默认值为drawmenu(0,0),表达绘制File菜单及其5个菜单项选择项,并

将菜单项选择择光带条置于第一种菜单项选择项上。下面简要描述一下draw(value,flag)

函数的过程。

(1)先取value除以3的余数m(由于有3个菜单项,因此除数选择3),根据m的值来

绘制不一样的菜单。m的取值为。、1、2、。当m等于。时,表达绘制File菜单;具

他类推。

(2)然后绘制菜单的边框及菜单项选择项值。

(3)取File除以x的余数t,x的取值视m的取值而定,如当m=5时,x=5,由于File

菜单下有5个选项。

(4)根据t的值,用不一样的前景色和背景色在本来的位置重新显示菜单项选择项,以

到达光带条的效果。

2)移动菜单光带条

当顾客按Fl、F2和F3中的某个功能键调用了某个菜单后,可继续按光标左移、右移、上

移和下移键来实现菜单之旬的切换和菜单项选择项之间H勺切换。

(1)若为左移键,则调用drawmenu(-value»flag)函数,将切换至某个菜单的左边邻

居菜单。若忖前菜单为最左边的File菜单,则切换至最右边的Help菜单。若为右移

键,则调用drawmenu(++value,flag)函数。

(2)若为上移犍,则调用drawmenu(value,-flag)函数;若为卜移键,则调用drawmenu

(value,++flag)函数。

3)选用菜单

当顾客将光带选择条置于某个菜单项选择项上时,可按Enter键来选用该菜单项选择项。选

用菜单操作的I实现比较简朴,它重要运用a=(value%3)*10+flag%b来计算Hl选择的I菜单项

选择项的编号。选用不一样菜单项选择项后,aU勺值不一样。这样,程序可根据a的值,返

回给main()函数不一样的标识,在main()函数中,可根据标识的不一样来执行有关功

能。

6.协助及其他模块

协助模块重要用于提醒顾客怎样使用本软件,它日勺实现非常简朴。同样,文本的迅速预览模

块是在本来主窗口显示模块的基础上,清除了菜单日勺显示。

主窗口重要由菜单栏、文本编辑区和状态栏3大部分构成。菜单栏用来显示菜单项,文本编

辑区重要用来完毕文本字符的输入、删除等操作,状态栏重要用来显示目前光标在文本窗口

中的坐标值。它重要运用文本窗口小Jgotoxy()函数和cprintf()函数来实现,这里需要对

文本窗口口勺坐标进行仔细设计。

.3.2数据构造设计

本程序定义了3个构造体,分别与剪贴板、列单链表和行单链表有关。下面分别简介这3

个构造体及几种全局变量。

1.与剪贴板有关的record构造体

typedefstructrecord

charch;

intcol,line;

}record;

record构造体表达一种字符所具有的属性,当顾客使用有关按键选定文本后,选定日勺文本保

留在record构造体类型的数组中。构造体中各字段表达II勺意义如bo

charch:保留一种选定日勺文本字符。

intcol,line:分别保留选定字符所在位置的lx轴坐标和y轴坐标。

2.与列单链表有关的node构造体

typedefstructnode

(

charch;

structnode*next;

Jnode;

node构造体定义了在一种单链表中保留行中的单个字符的构造,我们称由node类型的节点

构成的单链表为列单链表,构造体中各字段表达的意义如下。

charch:数据域,保留一种字符。

structnode*next:指针域,指向列单链表中的下一种节点。

3.与行单链表有关的Hnode构造体

typedefstructHnode

node*next;

structHnodc*ncxtl;

}record;

Hnodc构造体定义了在一种单链表中保留列单链表首节点地址的I构造,我们称由Hnodc类

型的节点构成口勺单链表为行单链表。构造体中各字段表达的I意义如下。

node*ncxt:数据域,。指向列单链表的首节点口勺地址

structHnode*ncxtl:指针域,指向列单链表中的J下一种节点。

4.全局变量及数组

intvalue,backup,NUM:value保留有值数组元素的最大下标值,backup保留value欧|副本,

NUM保留目前行中顾客输入的字符个数。

recordr[500]:定义-•种有500个元素的构造体数组,每个数组元素可保留一种选定的文本

字符及其坐标值。

.3.3函数功能描述

1)drawmainO

函数原型:voiddrawmainO

drawmainO函数用于在程序中会只包括菜单栏,编辑区和状态栏在内U勺主窗口。

2)qview()

函数原型:voidqview(Hnode*q)

qview()函数用于迅速预览文本。q为指向行单链表中第一种节点的指针。

3)view()

函数原型:viodview(Hnode*q)

view。函数用于按行显示保留在单链表中的文本字符,q为指向行单链表中第一种节点的指

针。

4)chcck()

函数原型:intcheck(Hnodc*Hhead,intm,intn)

函数用于在单链表中检查第m行,第n列位置H勺字符,若为常规字符,则返回该字符:否

则返回0或

5)judgc()

函数原型:intjudjc(Hnodc*Hhead,intm)

judge。函数用于返回第m行中不包括回车符在内的常规字符的个数。

6)del()

函数原型:intdcl(Hnode*HheadJntni,intn)

del。函数用于在单链表中删除第m行,第n列位置的字符。

7)test()

函数原型:inttest(Hnode*Hn)

test。函数用于执行后,检查第n行及背面的数据,使其满足每行不多于76个字符的规则。

8)insert()

函数原型:viodinsert(Hnode*Hheadintn,chara)

insert。函数用于在第m行,第n列位置的前一种位置插入单个字符。

9)control()

函数原型:voidcontrol(intA,Hnode*Hhead)

control。函数用于对左移键(右移键)进行响应,A为按键的整数值,Hhead为行单链表的

首地址。

10)colorvicw()

函数原型:voicolorvicw(Hnodc*Hhcad,intx,inty)

colorview()函数用于用不一样H勺前、背景色现实选择的字符。

11)drawmcnu()

函数原型:voiddrawmcnu(intm,intn)

drawmenu函数用于画菜单,m表达第几项菜单,n表达第m项的第n个子菜单项。

12)mcnuctrl()

函数原型:intmenuctrl(Hnode*Hhcad,intA)

mcnuctHO函数用于菜单控制。

13)save()

函数原型:voidsavc(Hnodc*hcad)

save。函数用于将head所指的行单链表中所指的各个列单链表中的数据域口勺值写入文献,文

献途径和文献名由顾客指定。

14)saveas()

函数原型:voidsaveas(Hnode*head)

saveas()函数用于实现文献另存工作,文献途径和文献名由顾客指定。

15)opens()

函数原型:voidopens(Hnode*Hp)

opens。函数用于从任意文本文献中读取文献内容,保留至行单链表形式的数据构造中。

)main()

函数原型:voidmain()

main()函数为程序的主控函数,对它的描述可参见.3.1小节。

.4程序实现

.4.1源码分析

1.程序预处理

程序预处理包括头文献的加载,以及构造体,常量和全局变量的定义。

/*文本编辑器editor源代码*/

#include<stdio.h>

#include<conio.h>

#iDelude<bios.h>

#include<math.h>

#defineLEFT0x4b00/**-:光标左移*/

#defineRIGHT0x4d00/*f:光标右移*/

#defineDOWN0x5000伸1键:光标下移*/

#defineUP0x4800/*t键:光标上移*/

#defineESC0x01lb/*ESC键:取消菜单打开操作*/

#defineENTEROxlcOd/*回车键:换行*/

#defineDEL21248/*DEL键:删除目前字符*/

#defineBACK3592/*Backspace键:删除目前光标位置前一种字符*/

#defineCL29440/*ctrl+一键:从右至左,选定文本*/

#defineCR29696/*ctrl+f键:从左到右,选定文本*7

#defineCc11779/*ctrl+c键:将选定文本,复制一份到剪贴板中引

#dcfincCv12054/*ctrl+v键:将剪贴板中的内容复制到目前位置*/

#dcfincCx11544/*ctrl+x键:对选定文本,执行剪切操作*/

#dcfincFl15104/*F1键:打开文献菜单*/

#dcfineF215360/*F2键:打开编辑菜单*/

#dcfineF3156/*F3键:打开协助菜单*/

#defineF1017408/*F10键:进入文本迅速预览模式》/

intvalue,backup,NUM;

/"value保留有值数组元素II勺最大下标值,backup保留valueII勺副本,NUM保留目前行中的J

顾客输入的字符个数刃

typedefstructrecord

(

charch;/*保留一字符*/

intcol.line;/*x轴和y轴坐标*7

}record;

recordr[500];/*定义一种有500个元素的构造体数组,保留选定的文本字符的属性*/

typcdcfstructnode/*定义保留行中W、J单个字符F、J构造*/

(

charch;/*数据域:保留一字符*/

structnode*next;/*指针域:指向F一种结点的指针*/

}node;/*由此类型节点构成的单链表,命名为:列单链表*/

typcdcfstructHnode/*定义保留所有列单链表首节点的指针的构造*/

node*ncxt;/*指向列单链表日勺首节点的地址*/

structHnodc*ncxtl;/*指向下一种节点的I指针*/

}Hnode;/*由此类型节点构成的单链表,命名为:行单链表*/

2.绘制主窗口

绘制文本编辑器主窗口由drawmain()函数来完毕,通过精确定位有关输出对象的坐标来完毕

主窗口的绘制。主窗口共分为3个区域:菜单区,文本编辑去和状态栏区。

voiddrawmainO/*画主窗U函数*/

(

inti,j;

gotoxy(l,l);产在文本窗口中设置光标至(11)处*/

textbackground(7):/*选择新"勺文本背景颜色.7为LIGHTGRAY淡灰色*/

textcolor(O);/*在文本模式中选择新的字符颜色0为BLACK黑*/

insline();/*在文本窗口的(1,1)位置处中插入一种空行*/

for(i=l;i<=24;i++)

(

gotoxy(l,l+i);/*(x,y)中x不变,y++*/

cprintf(“%c”[96);/*在窗口左边输出-抑画出主窗口的左边界*/

gotoxy(80,l+i);

cprintf("%c”,196);/*在窗口右边,输出即画出主窗口的右边界*/

for(i=l;i<=79;i++)

gotoxy(l+i,2);/*在第2行,第2列开始*/

cprintf("%c”[96);/*在窗口顶端,输出・*/

gotoxy(l+i,25);/*在第25行,第2列开始*/

cprintf("%cM96);/*在窗口底端,输出-*/

gotoxy(l,l);cprintf("%c';l96);六在窗口左上角,愉出力

gotoxy(l,24);cprintf(“%c”[96);/*在窗口左下角,输出力

gotoxy(80,l);cprintf(”%c”,196);/*在窗口右上角,输出・*/

gotoxy(80,24);cprintf(M%cM,196);/*在窗口右下角,输出-*/

gotoxy(7.1):cprintf(M%c%cFile%c%c".l79,17..179):/*|<>|*/

gotoxy(27,1);cprintf("%c%cEdit%c%c",179,17„179);/*|<>|*/

gotoxy(47,l);cprintf("%c%cHelp%c%cH,179,17,,179);/*|<>|*/

gotoxy(5,25);/*跳至窗口底端*/

textcolor(1);

cprintfC"Row:lCol:l");

gotoxy(68,25);

cprintf("Version2.0");

3.文本字符显示输出

文本字符显示输出模块的作用是通过循环读取各单链表,酱爆错在单链表众多的字符在文本

编辑区中显示输出。

(I)通过qview(hnodexq)函数,可实现文本字符的I迅速预览。

(2)通过view(hondc*q)函数,可实现文本字符在编辑区域日勺显示。

voidqview(Hnode*q)/*迅速预览文本:开头:#,回车:**/

{

voidview(Hnode水q);/*view()函数申明*/

node*p;

inti;

window、,1,80,25);/*定义文本窗口大小*/

clrscr。;/*清屏*/

产循环读取两个单链表中的值:q是一种指向行单链表首节点的指针,

此单链表数据域的值为实际保留各行字符的列单链表p中的首节点地址*/

do{

p=q->next;/*p指向保留行数据的列单链表区J首节点的地址*/

cprintf("#");/*每行开头,打印此字符,不管前面与否有回车符号

while(p!:NULL)/*循环读取单链表p中时值*/

(

if(p->ch==13)putch('*');/*若为回车键,打印出水号*/

else

putch(p->ch);/*输出各行中的字符到预览窗口*/

p=p->next;/*指向下一种节点*/

}

q=q->nextl:/*指向下一种节点*/

printf("\n"):/*输出一种回车*/

}while(q!=NULL);

getch();

clrscr();

drawmain。;/*按任意键后,回到主窗口界面*/

window(2,2,79,23);

textbackground(9);

for(i=0;i<24;i++)

insline();/*插入24个空行*/

window(3,3,78,23);

textcolor(lO);

I

voidview(Hnode*q)/*按行显示保留在单链表中H勺文本字符,q为指向行单链表中第一种节

点的指针*/

node*p;/*p为保留列单链表节点元素地址的指针*/

clrscr();/*清屏*/

/*双重循环,读取并显示保留在单链表中字符*/

do{

p=q->next;

while(p!=NULL&&p->ch>=32&&p->ch<l27&&p->ch!=13&&p->ch!=-l)/*

指针p不能为空,且数据域必须为常规字符号

(

puich(p->ch);/*在文本窗口中输出该字符列

p=p->next;/*指向下一种节点*/

)

q二q->nextl;/*指向下一种节点*/

if((p->ch==13||p->ch==-1)&&q!=NULL)gotoxy(1.wherey()+1);/*若ch为回

车或EOF标识,光标跳至下行的开始处*/

}while(q!=NULL);/*逐行逐列显示文本字符*/

)

4.删除字符

程序调用del(Honde*Hhead,intm,intn)函数来完毕删除第行、笫列位置的字符。它的详细过

程在功能模块设计部分已经详细简介。下面简介此外两个对字符进行检测的函数,它在字符

的删除、插入等许多操作中均有用到。

(1)调用check(Hnode*Head,intm,intn)函数,在单链表中检查笫m行、第n列位置口勺字

符,若为常规字符,则返回该字符;否则返回。或-L,

(2)调用judge(Hnode*Hm)函数,在单链表中记录第m行中的J常规字符的总个

数,并返回记录值。

intdcl(Hnodc*Hhead,intm,intn)/*dcl():删除第m行,第n列位置口勺字符*/

(

Hnodc*q,*ql;

node♦pl,*p2,*tail;

inti,num=0,j,flag=0;

q=Hhcad;

if(n==0&&m==l)return;/*第1行,第0列不存在力

if(n=0&&m>l)/*若为第0列字符,但行必须不小于1,执行向上行移处理*/

{

n=76:

m=m-1;

gotoxy(n,m);/*移至第m-1行,第76列*/

flag=l;/*移位的标志置1*/

}

for(i=l;i<m;i++)严定位至行单链表中日勺第in个元素*/

q=q->nextl;

pl=q->next;

for(i=l;i<n-l;i++)/*定位至列单链表中的I第n-1个元素*/

pl=pl->ncxt;

p2=pl->next;/*p2指向列单链表中H勺第n个元素*/

if(n==l)/*若是删除第m行第1列的字符*/

{

q->next=pl->next;

free(pl);

I

else

(

pl->nexl=p2->nex【;/*在单链表中删除第m行第n列%I元素*/

free(p2);

)

/*删除掉第m行第n列II勺元素后,处理行单链表中第m个节点后的数据

向前移的任务*/

while((num=judge(Hhead,m++))>O)/*执行一次judge(Head,m)后,m才加

1.这里必须满足行常规字符数不为0的条件*/

(

pl=q->next;ql=q;

if(pl!=NULL)/*若目前行非空列

\vhilc(p1->ncxt!=NULL)

pl=pl->ncxt;

tail=p1;/*tai1保留列单链表最终一种元素/、J地址*/

q=q->nextl;/*指向F一行的元素欧I地址*/

pl=p2=q->ncxt;

tailoncxt=pl;/*tail的指针域指向卜.一4J讷第一种元素

的地址*/

)

else/*若目前行日勺字符个数为0,即删除该字符后,只剩余回

车符,则将下一种行单链表中节点H勺数据域移至前一下节点的数据域*/

(

q=q->nextl:p1=p2=q->ncxt:

qlonext=pl;/*ql->next指向下•行的J第•种元素日勺地

址*/

)

tor(i=U;K76-num;i++)

/*目前行尚有76-num个空位没有字符,在下一行的单链表中读

取字符,直至碰到回车符为止*/

pl=p2;/*pl指向p2%J前一种节点,p2指向行单链表中

下一种节点*/

p2=p2->ncxt;

if(p2->ch==13)break;/*若为回车,跳出循环*/

)

q->next=p2;/*在列单链表中去掉移至上行口勺元素*/

pl-〉next=NULL;/*下行移至上行的最终一种元素,指针置空*/

)

returnflag;/*返回0:表达没有换位,返回1:表达有换位*/

}

intchcck(Hnode*Hhead,intm,intn)/*check():在单链表中检查第in行第n列位置的字符,若

为常规字符,则返回该字符*/

{

inti;

Hnodc木q;

node*p;

q二Hhead;

for(i=l;i<m;i++)产定位至行单链表中欧)第in个元素*/

q=q->nextl;

p=qonext;/*获取第m个节点的数据域号

for(i=l;ivn;i++)/*定位至列单链表中U勺第n个元素*/

p=p->next;

if(p->ch==13)return-1;/*若第m行:,第n列的字符为回车键,则返回-1*/

if(p->ch>=32&&p->ch<127)returnp->ch;/*若第m行,第n列/口字符为常规字符,

则返回该字符*/

elsereturn。;/*若第m行,第n列的J字符既非回车符又非常规字符,则返回0*/

intjudge(Hnode*Hhead,in(m)/*judge():返回第m行中於J常规字符总H勺个数,不包括回车符*/

(

Hnode*q;

node*p;

inti,num=0;

q=Hhead;

for(i=l;i<m;i++);*定位至行单链表中日勺第m个元素*/

q=q->nextl;

if(q==NULL)return-1;/*返回-1,表达第m行不存在*/

p=q->next;

while(p->next!=NULL)

{

p=p->next;

num++;/*记录第m行口勺字符个数*/

/*行尾字符还没有判断,接下来判断行尾字符*/

if(p->ch==13&&num==0)return0;/*返回0,表达目前行只有一种回车字符*/

if(p->ch>=32&&p->ch<127)returnnum+1;/*返回num+1,表达目前行的最终一种

字符为常规字符*/

if(p->ch==13&&num!=0)returnnum;/*返回num,表达目前行的J最终一种字符为回

车符,不计算在内*/

elsereturn1;/*返回num,表达目前行中只有一种字符,且没有回车符*/

}

5.插入字符

在文本编辑区中插入字符的工作由insert(Hnode,*Hhead,intm,intn,chara)函数和

test(Hnode*Hhead,intn)函数配合完毕。

(1)通过inserKHnodexHn.chara)函数,在第m行、第n列的位置之前欧J一

种位置,在单链表中插入字符a。

⑵通过test(Hnode*n)函数,检查和处理第n行及背面的数据,使其满足每行

不超过76个字符的规则voidinsert(Hnode*Hhead,intm,intn,chara)/*第m行,第n列的位

置之前一种位置,插入单字符*/

{

inti;

Hnode*q;

node*p,*pl,*p2;

q=Hhcad;

for(i=l;i<m:i++);*定位至行单链表中日勺第m个元素*/

q=q->ncxtl;

p1=q->next;

for(i=l;i<n-l;i++j/*定位至列单链表中的J第n-1个元素*/

pl=pl->ncxt;

p=(nodc*)malloc(sizeof(node));/*创立一种新的)列单链表节点*/

p->ch=a;/*给此节点次)数据域赋值*/

if(n==l)/*插入之前,若只有一种字符在行中,则插在此节力、之前刃

{

p->next=q->next;

q->next=p;

}

else

(

p->next二pl->next;/*在第m行,第n列U勺字符前,插入一字符*/

p1->next=p;

)

test(Hhead,m);/*在插入新元素后,检查并处理单链表中第m行开始I向元素,使其满足

规则*/

/*执行insert。后,检查第n行及背面的数据,使其满足规则*/

inttest(Hnodc*Hhcad,intn)

{

inti=O,numl=l;

node*pl,*p2,*tail.*templ,*temp2;

Hnodc*q;

q=Hhcad;

for(i=l;i<n;i++)/*定位至行单链表中的第n个元素*/

q=q->nextl;

tail=pl=q->next;

if(pl==NULL)retum;/*若此行没有任何字符,则返回*/

while(tail->next!:NULL)/*定位至列单链表中II勺最终一种元素可

tail=tail->next:

/*若此单链表中没有回车符且有超过76个节点时,则pl会指向此列单链表中日勺第

76个节点*/

for(i=0;i<75;i++)

(

if(p1->ch==13||p1->next==NULL)break;

pl=pl->ncxt;

p2=pl->next;

pl->next=NULL;/*在此行的最终一种字符的前一种字符处断行,由于插入在此行插

入了一种新日勺字符*/

if(tail->ch!=13)/*若此行行尾不是回车键*/

{

if(p1->ch==13&&q->nextl==NULL)/*若p1的)数据域为回车符且行单链表中只

有n个节点*/

(

q->nextl=(Hnode*)malloc(sizeot(Hnodc));/*新建•种行单链表节

点,相称于添加一种新行*/

q->nextl->nextl=NULL;

tail->next=(node*)malloc(sizeof(node));/*izttail所指节点位置开始

继续准备添加字符*/

tail->next->ch=13;tail->next->next=NULL;

q->nextl->next=p2;/*新行单链表节点保留此行多出的字符*/

)

else/*若此行行尾和行中都没有回车键,或者q->nextl不为空*/

(

q=q->nextl;/*q->nextl有也许为空号

tail->next=q->next;/*4^多出IJ勺字符与下一行U勺字符相连*/

q->next=p2;/**/

if(q!=NULL)test(Hhead,++n);/*若行单链表第n个节点后尚有节点,

继续tcst()H勺相似处理*/

else/*若此列单德表最终一种元素为同车符为

{

temp2=p2;/*p2指向第77个字符,或者为空(为空表达此行插入一种字符后,

没有超过范围*/

while(q!=NULL&&p2;=NULL)/*q指向行列表中的第n个节点.条件:行单链表

中第n个节点存中且有第77个字符*/

{/*条件:在行单链表中只有n个节点,且字符超过了一行规定的76个,且

numl标志为I*/

if((q->nextl==NULL)&&(p1!=tail||p2!=NULL)&&(numl==l))

{

numl++;

q->ncxtl=(Hnode*)malloc(sizcof(Hnodc));/*新建一种行单链表节

点,准备存储此行中多出的字符*/

q->ncxtl->ncxtl=NULL;q->nextl->ncxt=NULL;/*初始化值*/

/*行单链表中第n+1个节点已经存在,下面为在行单链表中插入一种新H勺

节点*/

q=q->ncxtl;/*q指向行歹lj表中H勺第n+1个节点*/

tcmpl=q->ncxt;

q->ncxt=temp2;/*q的I数据域为此行中多出H勺字符所在的列单链表中的

节点地址可

tcmp2=tcmp1;

6.选定文本

在文本编辑区选定文本的工作由control(intA,Hnode*Hhead)函数和

colorview(Hnode*Hhead,intx,inty)函数配合完毕。

(1)通过controKintA.Hnode*Hhead)函数,对控制键进行响应,移动光标后并将光标所

在位置的字符保留在数组中。

(2)通过colorview(Hnode*Hhead,intx,inty)函数,用不

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论