C语言文本编辑器

上传人:仙*** 文档编号:97656981 上传时间:2022-05-27 格式:DOC 页数:57 大小:279KB
收藏 版权申诉 举报 下载
C语言文本编辑器_第1页
第1页 / 共57页
C语言文本编辑器_第2页
第2页 / 共57页
C语言文本编辑器_第3页
第3页 / 共57页
资源描述:

《C语言文本编辑器》由会员分享,可在线阅读,更多相关《C语言文本编辑器(57页珍藏版)》请在装配图网上搜索。

1、文本编辑器 文本编辑器是最常用的文档创建和编辑工具。随着计算机科学与技术的 发展,用来处理文本的编辑器随处可见,并且形式多样。比如, Windows 下的记事本, 写字板, EditPlus,UltraEdit 等都是十分优秀的文本编辑器和 处理工具。在本章中,我们将向读者讲解如何利用 C 语言来发展开发一个 简易的文本编辑器。1 设计目的利用 C 语言的单链表数据结构与相关函数,本章编程实现了一个与 DOS 操作系统下的 Edit 相似的文本编辑器。再次文本编辑器中,用户可 以通过快捷和选择菜单项,完成基本的文本编辑器和文件处理工作。通过文章的介绍,读者可以了解文本编辑器的开发过程,掌握菜单

2、的 开发技巧, 加深对文件操作的理解。 更重要的是, 希望此程序能抛砖引玉, 引领读者掌握编程的方法和技巧,开发出更优秀的程序。2 功能描述如图 .1 所示,文本编辑器主要由五大功能模块构成,它们分别是文件 操作模块,文本编辑模块,剪切操作模块,菜单控制模块和帮助与其他模 块。下面分别简要介绍功能模块的功能。(1)文件操作模块。 在文件操作模块中, 主要完成文件的创建, 打开, 保存和另存操作。用户可以选择 File 菜单上的 New 子菜单来完成新建文 本文件操作;选择 File 菜单上的 Save 子菜单来完成保存文件操作选择 File 菜单上的 Open 子菜单来完成打开文件操作;选择

3、Flie 菜单上的 Save as 子菜单来完成文件的另存为操作。在文件的打开,保存和另存为操作中, 系统会提示用户输入文件路径与文件名。值得一提的是,当用户打开一个 文件时,指定的文件必须存在,否则系统会报错。(2)文本编辑器模块。在文本编辑器模块中,主要完成在编辑窗口中 以添加或插入的方式输入字符,删除光标所在当前位置的单个字符或前一 个位置的单个字符,朝上下左右 4 个方向的光标移动操作。当光标所在位 置与后面的位置没有字符时,系统会以添加的方式输入字符;当光标所在 位置与后面的位置有字符时,系统会已插入的方式输入字符。用户可以使 用 BackSpace 键删除光标前一个字符,也可以使用

4、 Del 键删除当前位置 的字符或删除 Ctrl+ 左移(右移)键 i 选定了的多个字符。用户可以使用 左移键(j),右移键(T),上移键(f)和下移键(J)来移动光标位置。(3)剪贴板操作模块。在剪贴板操作模块中,主要完成对已选定文本 的剪切,复制,粘贴工作。如果用户要剪切文本以便可以将它移动到其他 位置,可通过 Ctrl+X 左移键(右移键)先选定文本,然后选择 Edit 菜单 上的 Cut 子菜单或按 Ctrl+X 快捷键来完成剪切任务。如果用户要复制文 本以便可以将它黏贴到其他位置, 必须先选定文本, 然后选择 Edit 菜单上 的 Copy 紫菜单或按 Ctrl+C 快捷键来完成复制

5、任务。如果用户要粘贴剪 切或复制的文本, 必须将光标置于要粘贴文本的位置, 然后选择 Edit 菜单 上的 Paste 子菜单或按 Ctrl+V 快捷键来完成粘贴任务。(4)菜单控制模块。在菜单控制模块中,主要完成菜单的显示。光带 条在子菜单之间的上下移动或菜单之间的左右移动和子菜单项的选取。本 文本编辑器共有 Flie,Edit 和 Help3 个子菜单项,用户可以分别按 F1,F2 和 F3 功能键来完成这 3 个菜单项的调用,即显示某项菜单。用户可按光 标上移或下移键在某菜单项的子菜单之间循环移动,也可使用光标的左移 或右移键在 3 个菜单项之间循环移动。当光带移动到某个字菜单项上时,

6、用户此时可使用 Enter 键来选取相关菜单选项。(5)帮助与其他模块。在帮助与其他模块中,主要完成系统功能与按 键的简要介绍。 其他模块包括文本的快速预览和窗口的显示。 用户可按 F10 功能键来打开快速预览窗口,在快速预览窗口中没有功能菜单条。主窗口 要有菜单栏, 文本编辑区和状态栏三大部分构成, 菜单栏用来显示菜单项, 文本编辑区主要用来文本字符的输入,删除等操作,状态栏主要用来显示 当前光标在文本窗口中的坐标值。注意:Turbo C2.默认定义的文本窗口为整个屏幕,共有80列(或40 列), 25 行的文本单元,每个单元包括一个字符和一个属性,字符即 ASCII 码字符,属性规定该字符

7、的颜色和强度。同时,他还规定整个屏幕 的左上角坐标为( 1, 1),右下角坐标为( 80, 25)。并规定沿水平方向 为 X 轴,方向朝右;眼垂直方向为 Y 轴,方向朝下。3 总体设计3.1 功能模块设计 在.2节中,简单描述了各功能模块的作用,下面分别介绍各功能模块 的具体设计。在介绍各功能模块的具体设计之前,有必要先描述一下主程 序的执行流程。1. 程序执行主流程文本编辑器程序执行主流程如图 .2 所示,它是在 main ()函数中实 现的。他首先初始化一些全局变量与结构数组,接着调用 drawmain() 函 数来显示主窗口,然后调用 while(1) 进入主循环,等待用户按键,最后程

8、序根据用户的按键值,进行相应的处理,完成文本编辑的相关工作。下面 对图 .2 中的按键判断和相关处理作补充说明。(1)若按键为常规字符,即其 ASCII 码大于 32 小于 127 ,则继续判 断在文本编辑区的当前光标位置有没有字符,若有字符,则调用 insert() 函数,将此字符插入在当前位置,否则在判断没有满行后,将此字符添加 在单链表的数据域中,若此行已满,则执行添加新行操作。( 2) 若按键为 Enter 键,则将光标移至下一行的行首,等待用户输入 新的字符。(3)若按键为光标移动键(左,右,上,下)且移动后的位置满足相 关条件,则执行 gotoxy() 操作,将光标移动至目标位置。

9、( 4) 若按键为 BackSpace 键,则将调用 Del() 函数将光标的前一个 字符从单链表中删除;若按键为 Del 键,也将调用 del() 函数将光标的当 前位置的字符从单链表中删除。( 5) 若按键为 Ctrl 开头的按键,则执行与其相关的操作。具体来说,若为Ctrl+左移键(),则将选定当前光标的位置幵始向右的一个字符, 若按住 Ctrl 键不放,连续按右移键,可以选定多个字符。若为 Ctrl+ 左移 键(J),则将执行与以上相同的操作。若为Ctrl+X键,则将选定相关内容保存起来,且从单链表中删除选定的字符后重新显示单链表的内容。若 为 Ctrl+C 键,则将选定的相关内容保存

10、起来,重新显示单链表中的内容(目的:为了去除字符的底色) 。若为 Ctrl+V 键,则调用 insert() 函数将 保存起来的字符插入在单链表中,并重新显示单链表中的内容。( 6) 若按键为 F10 键,则调用 qview() 函数,实现文本的快速预览。 若按键为 F1,F2,F3 功能键,则调用 menuctrl() 菜单控制函数,在此函数 中完成案件的具体判断和执行相应功能操作。若为 F1 键,则调用 File 菜 单;若为 F2 键,则调用 Edit 菜单;若为 F3 键,则调用 Help 菜单。 2文件操作模块 在此模块中,主要实现文件的新建、打开、保存和另存为操作。在此系统 中,文

11、件的新建操作实现比较简单,文件另存为操作与保存操作类似,下 面重点介绍在此文本编辑器程序中,文件的打开和保存操作的具体设计和 实现。在介绍之前,我们先简单描述一下程序中用到的保存数据的数据结 构。在此程序中,共有两种类型的单链表,我们称其为行单链表和列单链 表,一个列单链表用来保存一行的字符,有多少行即有多少个这样的单链 表。行单链表只有一个,它的每个节点的数据域用来保存不同列单链表的 首节点的地址。 例如, 第 4 行第 4 列的字符保存在行单链表的第 4 个节点 的数据域所指的列单链表的第 4 个节点的数据域中。 有关具体数据结构的 定义,在后面的小节中会有具体介绍。1)打开文件文件的打开

12、流程如图 .3 所示, 它首先提示用户输入要打开文件的文件名, 若该文件不存在或由于其他原因打开失败,则会结束文件打开操作。若文 件成功打开并且文件指针没有到文件尾,则从文件中一次读取一个字符, 并将该字符添加到一列单链表节点中,直至遇到换行符(ASCII 码 10 )或连续读取字符个数大于 76 (在此文件编辑器中,每行最多为 76 个字符)。 当列单链表形成后,它的首地址将被保存至行单链表的相应节点的数据域C 语言文本编辑器 中,如此动作,直至文件指针指向文件尾部而结束。注意:由于本程序中每行以回车符( ASCII 码为 13 )结束,而当用 Windows 的记事本创建一个文本文件,打开

13、此文件并用 fgetc() 函数读取 时,程序写入列单链表节点中的值是 ASCII 码为 13 的回车符。2)保存文件保存文件操作主要完成将单链表中的数据写入文件中的任务,它的具体 实现流程如下。(1)用户输入一个保存此单链表数据的文件名。(2)以只写方式打开此文件,若成功打开此文件,则执行步骤(3 );否则退出。(3)读取行单链表中的节点数据域的值, 若值不为空, 则执行步骤 (4 ); 否则执行步骤( 6)。(4)依次读取行单链表节点中保存的首地址的相应列单链表节点的数据 域的值,若其值为回车符,则用换行符替代后将其写入文件中;否 则直接将其值写入文件中,直至该列单链表中指针域为 NULL

14、 的最 后一个元素结束。(5)读取行单链表中的下一个节点,并跳至步骤( 3)。(6)关闭文件,退出。 3文件编辑模块 在文件编辑模块中,主要完成以添加或插入的方式输入字符、删除光标所 在的当前位置或前一个位置的单个字符、 朝上下左右 4 个方向的光标的移 动操作。下面介绍这 4 个功能的具体设计与实现。1) 添加字符 当光标处在文本编辑的最后一行的位置且光标后面没有字符时,若此时输 入字符,程序会判断一行中字符的个数, 若字符个数不等于 76 ,则在当前 的列单链表的最后一个节点中保存输入的字符,然后添加一个新的节点来 保存下一个输入的字符: 若等于 76 ,则在当前的列单链表的最后一个节点

15、中保存输入的字符,然后在行单链表中添加一个新节点用来保存下一行的 列单链表的首地址,添加一个新的列单链表节点来保存下一个用户输入的 字符。2) 插入字符 若光标所在处已经存在字符,当用户在当前位置输入字符时,程序会调用 insert() 函数将输入的字符在光标所在的位置处在列单链表中插入, 插入完 成后,会调用 test() 函数来检查各行是否满足只有 76 个字符的条件, 若不 满足此条件,则在此函数中会对多出的字符进行处理。下面分别对列单链 表中字符的插入过程和单链表的检查过程进行介绍。若在第 m 行,第 n 列的位置插入一个字符,其 insert() 过程描述如下:(1) 定位至行单链表

16、中的第 m 个节点, 得到这个节点的数据域的值, 其 值为对应列单链表中第一个节点的地址。(2) 定位至列单链表中的第 n-1 个节点。(3) 创建一个新的列单链表节点,用其数据域保存输入的字符。(4) 若字符插入在第 m 行第 1 列,则直接将行单链表中第 m 个节点的 数据域的值改变为新的列单链表节点的地址,新的列单链表节点的 指针域指向列单链表中原来的第 1 个节点。若字符不是插入在第 m 行第 1 列,则执行简单的单链表中插入节点的操作。5) 插入此字符后,调用 test() 函数,从第 m 行开始检查各行是否满足 每行只允许有 76 个字符的条件,若不满足此条件, 则必须进行处理。其

17、 test() 检查处理过程描述如下:1) 用指针 tail 指向已经插入了新节点的列单链表中的最后一个节点。2) 若此单链表中节点数超过 76 个,则指针 p1 会指向此列单链表中的 第 76 个节点,指针 p2 指向第 77 个节点,并将 p1 所指节点的指 针域设置为 NULL 。3) 若 tail 所指节点的数据域为 Enter 键( ASCII 为 13 )且在行单链表 中只有 m 个节点, 则在此行单链表中添加一个新的节点, 新节点的 数据域为 p2 的值,指针域为空,并将 m 节点的指针域指向它 ;若 tail 所指节点反而数据域为 Enter键(ASCII为13)且在行单链表中

18、有多 于m个节点,与上面不同的是,它执行的是在行单链表插入一个新 的节点的操作。4) 若 tail 所指节点的数据域不是回车符, p1 的数据域为回车符并且行 单链表中只有 m 个节点, 则在行单链表中添加一个新的节点, 新节 点的数据域为 p2 的值,指针域为空,并将第 m 节点的指针域指向 它;若 tail 所指节点的数据域不为回车符并且行单链表中有多于 m 节点,则将 tail 的指针域指向行单链表中第 m+1 个节点所指的列 单链表的首节点,并将行单链表中第 m+1 个节点的数据域修改成 指针 p2 的值,并对行单链表中第 m+1 个节点所指的列单链表进行 test() 检查,相似的处

19、理过程至行单链表中的最后一个节点结束。3) 删除字符当用户按下 Del 键时,系统会调用 del() 函数在单链表中删除当前光标所 在处的字符;当用户按下 BackSpace 键时,系统也会调用这个函数在单 链表中删除当前光标所在处前一个位置的字符。若在第 m 行、第 n 列的位置删除一个字符,其在列单链表中删除一个节 点的操作域插入工作十分相似,所以这里重点介绍删除该字符后,单链表 中数据的前移工作过程。(1)在相应的列单链表中删除第 n 个节点。(2)判断第 m 行是否存在并且判断在此行中是否有字符,若第 m 行不 存在,或此行中没有字符, 则结束字符删除过程, 否则执行步骤 (3)。(3

20、)用 tail 保存第 m 行相应列单链表中最后一个节点的地址, 并将最后 一个节点的指针域保存为第 m+1 行中相应列单链表的第一个元素 的地址。(4)计算出第 m 行中没有字符的位置的个数 num ,然后在第 m+1 行的 相应列单链表中截取 num 个节点, 并将行单链表中的第 m+1 节点 的数据域改为相应列单链表中的第 num 个节点后的节点的地址。(5)调用 m+ 语句,是变量 m 增 1,跳至步骤( 3 ),开始对下一行进 行处理。4) 移动光标移动光标的操作主要利用 gotoxy() 函数来实现, 过程非常简单, 只需对当 前的光标位置和移动方向进行判断后,即可执行 gotox

21、y() 过程。例如,如 果当前光标在第 m 行第 1 列,且按下了光标左移键,只需将光标移至第 m-1 行,第 76 列。4.剪贴板操作模块 在剪切板操作模块中,主要完成对已选定文本的剪切、复制和粘贴工作, 因此剪贴板操作与文本选定工作密切相关。下面分别介绍文本的选定和对 选定文本的剪切、复制和粘贴操作的具体实现。1) 选定文本用户可按 Ctrl+ 来选定文本,就具体实现而言,两者基本相 同。在介绍选定文本的实现过程之前, 先简要介绍一个全局的结构数组 r , 它的元素的类型为 record 结构体类型,每一个元素可保存一个字符的 x 坐标、 y 坐标和字符值。其文本选定的实现过程如下:(1)

22、当用户按下 Ctrl+ 键时,程序将当前光标位置向左或 向右移动一个位置。(2)当前光标所在位置的字符的 x 坐标、 y 坐标和字符值保存在数组元素 rvalue 中 value 从 0 开始,若按减为 Ctrl+,value 值在原来基础上每次减1.(3)调用 Colorview() 函数,用不同的颜色来显示已经选定的当前文本,以达到突出选定文本的效果。2) 剪切用户可按 Ctrl+X 键或通过 Edit 菜单选项来剪切选定的文本,若之前没有 选定的文本,此按键无效。它的实现过程如下:( 1)若全局变量 value 的值大于 0(大于 0 表示已经有文本选定) ,则执行下面操作。(7)( 2

23、)保存当前位置的坐标,利用循环语句,依次利用x0 至 xvalue-1数组元素保存已选定字符的坐标,调用 del ()函数在单链表中一次删除 一个选定的字符。( 3)利用全局变量 backup 保存 value 的值后,将 value 赋值为 0。(4)重新在文本编辑器中显示单链表中保存的所有字符,并将光标置位 到原来的位置。3)复制用户可按 Ctrl+C 键或通过 Edit 菜单选项来复制选定的文本,复制操作的 实现比剪切操作简单,它的实现过程如下:(1)保存当前位置的坐标。(2)利用全局变量 backup 保存 value 的值后,将 value 赋值为 0 。(3)重新在文本编辑器中显示

24、单链表中保存的所有字符,并将光标置位 到原来的位置。4)粘贴用户可按 Ctrl+V 键或通过 Edit 菜单选项,完成粘贴操作。这一操作必须 在剪切或复制操作之后出现。它的具体实现过程如下:(1)若全局变量 backup 的值大于 0(大于 0 表示已经有字符放入了剪 贴板数组)中,则执行下面的操作。(2)保存当前位置的坐标, 利用循环语句, 依次利用 x0 至 xbackup-1 数组元素保存已选定字符的坐标和字符值,调用 insert ()函数在 单链表中一次插入一个字符(3)重新在文本编辑器中显示单链表中保存的所有字符,并将光标置位 到原来的位置。5菜单控制模块 在菜单控制模块中,主要完

25、成菜单的显示、光带条在子菜单之间的上下移 动或菜单之间的左右移动以与子菜单项的选项工作。 下面分别介绍这 3 项 功能的具体实现。1) 显示菜单用户可按 F1 、F2 和 F3 功能键来分别调用和 Help 菜单,即完成菜单的显 示。当按下这 3 个功能键中的某个功能键时,程序会调用 menuctrl () 函数来完成菜单的调用操作。在 menuctrl ()函数中,会根据功能键的 键值调用 drawmenu (value ,flag )函数,参数 value 、 flag 都为局部 变量,分别用来保存调用某个菜单、 某个菜单下的第几个菜单选项。 例如, 按 F1 键后,它的默认值为 draw

26、menu ( 0,0 ),表示绘制 File 菜单与其 5 个菜单选项,并将菜单选择光带条置于第一个菜单选项上。下面简要描述 一下 draw ( value ,flag )函数的过程。(1) 先取value除以3的余数m (因为有3个菜单项,所以除数选择3), 根据 m 的值来绘制不同的菜单。 m 的取值为 0、1、2、。当 m 等于 0 时,表示绘制 File 菜单;其余类推。(2)然后绘制菜单的边框与菜单选项值。(3)取File除以x的余数t, x的取值视m的取值而定,如当 m=5时, x=5 ,因为 File 菜单下有 5 个选项。( 4) 根据 t 的值,用不同的前景色和背景色在原来的

27、位置重新显示菜单选项,以达到光带条的效果。2) 移动菜单光带条当用户按 F1 、F2 和 F3 中的某个功能键调用了某个菜单后, 可继续按光标 左移、右移、上移和下移键来实现菜单之间的切换和菜单选项之间的切换。(1) 若为左移键,则调用 drawmenu ( -value ,flag )函数,将切换至 某个菜单的左边邻居菜单。若当前菜单为最左边的 File 菜单,则切 换至 最 右边 的 Help 菜 单 。若 为右 移 键, 则 调用 drawmenu (+value , flag )函数。(2) 若为上移键,则调用 drawmenu ( value ,-flag )函数;若为下移 键,则调

28、用 drawmenu (value ,+flag )函数。3) 选取菜单当用户将光带选择条置于某个菜单选项上时,可按 Enter 键来选取该菜单 选项。选取菜单操作的实现比较简单,它主要利用a= ( value%3 )*10+flag%b 来计算出选择的菜单选项的编号。选取不同菜单选项后, a 的值不同。这样,程序可根据 a 的值,返回给 main ()函数不同的标记, 在 main ()函数中,可根据标记的不同来执行相关功能。6帮助与其他模块 帮助模块主要用于提示用户如何使用本软件,它的实现非常简单。同样, 文本的快速预览模块是在原来主窗口显示模块的基础上,去除了菜单的显 示。主窗口主要由菜

29、单栏、文本编辑区和状态栏 3 大部分构成。菜单栏用来显 示菜单项,文本编辑区主要用来完成文本字符的输入、删除等操作,状态 栏主要用来显示当前光标在文本窗口中的坐标值。它主要利用文本窗口的 gotoxy ()函数和 cprintf ()函数来实现,这里需要对文本窗口的坐标 进行仔细设计。.3.2 数据结构设计本程序定义了 3 个结构体,分别与剪贴板、列单链表和行单链表相关。下面分别介绍这 3 个结构体与几个全局变量。1 与剪贴板相关的 record 结构体typedef struct recordchar ch;int col,line;record;record 结构体表示一个字符所具有的属性

30、, 当用户使用相关按键选定文本 后,选定的文本保存在 record 结构体类型的数组中。结构体中各字段表 示的意义如下。char ch :保存一个选定的文本字符。int col , line :分别保存选定字符所在位置的 x 轴坐标和 y 轴坐标。2 与列单链表相关的 node 结构体typedef struct nodechar ch;struct node *next;node;node 结构体定义了在一个单链表中保存行中的单个字符的结构,我们称 由 node 类型的节点构成的单链表为列单链表。结构体中各字段表示的意 义如下。char ch :数据域,保存一个字符。struct node*

31、next :指针域,指向列单链表中的下一个节点。3 与行单链表相关的 Hnode 结构体typedef struct Hnodenode *next;struct Hnode *next1;record;Hnode 结构体定义了在一个单链表中保存列单链表首节点地址的结构, 我们称由 Hnode 类型的节点构成的单链表为行单链表。结构体中各字段 表示的意义如下。node *next :数据域,。指向列单链表的首节点的地址struct Hnode*next1 :指针域,指向列单链表中的下一个节点。4 全局变量与数组int value , backup ,NUM :value 保存有值数组元素的最大

32、下标值, backup 保存 value 的副本, NUM 保存当前行中用户输入的字符个数。 record r500 :定义一个有 500 个元素的结构体数组, 每个数组元素可保 存一个选定的文本字符与其坐标值。.3.3 函数功能描述1 ) drawmain()函数原型: void drawmain()drawmain() 函数用于在程序中会只包括菜单栏, 编辑区和状态栏在内的主 窗口。2)qview()函数原型: void qview(Hnode*q)qview() 函数用于快速预览文本。 q 为指向行单链表中第一个节点的指针。3 ) view()函数原型: viod view(Hnode*

33、q)view() 函数用于按行显示保存在单链表中的文本字符, q 为指向行单链表 中第一个节点的指针。4 ) check()函数原型: int check(Hnode*Hhead,int m,int n)函数用于在单链表中检查第 m 行,第 n 列位置的字符,若为常规字符, 则返回该字符;否则返回 0 或 -1.5) judge()函数原型: int judje(Hnode*Hhead,int m)judge() 函数用于返回第 m 行中不包括回车符在内的常规字符的个数。6) del()函数原型: int del(Hnode*Hhead,int m,int n)del() 函数用于在单链表中删

34、除第 m 行,第 n 列位置的字符。C 语言文本编辑器7)test()函数原型:int test(Hnode*Hhead,int n)test() 函数用于执行后,检验第 n 行与后面的数据,使其满足每行不多于 76 个字符的规则。8 ) insert()函数原型: viod insert(Hnode*Hheadint m,int n,char a)insert() 函数用于在第 m 行,第 n 列位置的前一个位置插入单个字符。9 ) control()函数原型: void control(int A,Hnode*Hhead)control() 函数用于对左移键(右移键)进行响应, A 为按键

35、的整数值, Hhead 为行单链表的首地址。10 ) colorview()函数原型: voi colorview(Hnode*Hhead,int x,int y)colorview() 函数用于用不同的前、背景色现实选择的字符。11 ) drawmenu()函数原型: void drawmenu(int m,int n)drawmenu 函数用于画菜单, m 表示第几项菜单, n 表示第 m 项的第 n 个子菜单项。12 ) menuctrl()函数原型: int menuctrl(Hnode*Hhead,int A)menuctrl() 函数用于菜单控制。13 ) save()函数原型:

36、void save(Hnode*head)save() 函数用于将 head 所指的行单链表中所指的各个列单链表中的数据 域的值写入文件,文件路径和文件名由用户指定。14 ) saveas()函数原型: void saveas(Hnode*head)saveas() 函数用于实现文件另存工作,文件路径和文件名由用户指定。15 ) opens()函数原型: void opens(Hnode*Hp)opens() 函数用于从任意文本文件中读取文件内容,保存至行单链表形式 的数据结构中。)main()函数原型: void main()main() 函数为程序的主控函数,对它的描述可参见 .3.1 小

37、节。.4 程序实现.4.1 源码分析1. 程序预处理程序预处理包括头文件的加载,以与结构体,常量和全局变量的定义。/* 文本编辑器 editor 源代码 */#include #include #include #include C 语言文本编辑器#define LEFT 0x4b00/* J:光标左移*/#define RIGHT 0x4d00/* I:光标右移*/#define DOWN 0x5000/* J键:光标下移*/#define UP 0x4800/* f键:光标上移*/#define ESC 0x011b/*ESC 键:取消菜单打开操作 */#define ENTER 0x1c

38、0d/* 回车键:换行 */#define DEL 21248/*DEL 键:删除当前字符 */#define BACK 3592/*BackSpace 键:删除当前光标位置前一个字符*/#define CL 29440/*ctrl+ J键:从右至左,选定文本*/#define CR 29696/*ctrl+ I键:从左到右,选定文本 */#define Cc 11779/*ctrl+c 键:将选定文本,复制一份到剪贴板中*/#define Cv 12054/*ctrl+v 键:将剪贴板中的内容复制到当前位置*/#define Cx 11544/*ctrl+x 键:对选定文本,执行剪切操作 *

39、/#define F1 15104/*F1 键:打开文件菜单 */#define F2 15360/*F2 键:打开编辑菜单 */#define F3 156/*F3 键:打开帮助菜单 */#define F10 17408/*F10 键:进入文本快速预览模式 */int value,backup,NUM;/*value 保存有值数组元素的最大下标值, backup 保存 value 的副本,NUM 保存当前行中的用户输入的字符个数 */typedef struct recordchar ch; /* 保存一字符 */int col, line; /*x 轴和 y 轴坐标 */record;r

40、ecord r500; /* 定义一个有 500 个元素的结构体数组,保存选定的文本 字符的属性 */typedef struct node /* 定义保存行中的单个字符的结构 */char ch; /* 数据域:保存一字符 */struct node *next; /* 指针域:指向下一个结点的指针 */node;/* 由此类型节点构成的单链表,命名为:列单链表 */typedef struct Hnode /* 定义保存所有列单链表首节点的指针的结构 */node *next; /* 指向列单链表的首节点的地址 */struct Hnode *nextl; /* 指向下一个节点的指针 */

41、Hnode;/* 由此类型节点构成的单链表,命名为:行单链表 */2. 绘制主窗口绘制文本编辑器主窗口由 drawmain() 函数来完成,通过准确定位相关输 出对象的坐标来完成主窗口的绘制。主窗口共分为 3 个区域:菜单区,文 本编辑去和状态栏区。void drawmain() /* 画主窗口函数 */int i,j;gotoxy(1,1); /* 在文本窗口中设置光标至 (1,1) 处 */ textbackground(7); /* 选 择 新 的 文 本 背 景 颜 色 ,7 为 LIGHTGRAY 淡灰色 */textcolor(0); /* 在文本模式中选择新的字符颜色 0 为 B

42、LACK 黑 */insline(); /* 在文本窗口的 (1,1) 位置处中插入一个空 行*/for(i=1;i=24;i+)gotoxy(1,1+i);/* (x,y)中 x 不变,y+*/cprintf(%c,196);/* 在窗口左边输出 -,即画出主窗口的左边界 */gotoxy(80,1+i);cprintf(%c,196); /* 在窗口右边,输出 -,即画出主窗口 的右边界 */for(i=1;i=79;i+) |*/gotoxy(1+i,2); cprintf(%c,196); /* gotoxy(1+i,25);cprintf(%c,196); /* /*在第 2 行,第

43、 2列开始*/ 在窗口顶端,输出 -*/* 在第 25 行,第 2 列开始 */在窗口底端,输出 -*/gotoxy(1,1);cprintf(%c,196); /*在窗口左上角,输出-*/gotoxy(1,24);cprintf(%c,196); /*在窗口左下角,输出-*/gotoxy(80,1);cprintf(%c,196); /*在窗口右上角,输出-*/gotoxy(80,24); cprintf(%c,196); /*在窗口右下角,输出-*/gotoxy(7,1);cprintf(%c %c%c,179,17,179);/*/* | |*/Help %cgotoxy(27,1);

44、cprintf(%c%c Edit %c %c,179,17,179);gotoxy(47,1); cprintf(%c %c %c,179,17,179); /* | |*/gotoxy(5,25); /* 跳至窗口底端 */textcolor(1);cprintf( Row:1 Col:1);gotoxy(68,25);cprintf(Version 2.0);3. 文本字符显示输出 文本字符显示输出模块的作用是通过循环读取各单链表,酱爆错在单链表 众多的字符在文本编辑区中显示输出。(1) 通过 qview(hnode*q) 函数,可实现文本字符的快速预览。(2) 通过 view(hond

45、e*q) 函数,可实现文本字符在编辑区域的显示。 void qview(Hnode *q) /*快速预览文本:开头: #,回车: * */void view(Hnode *q); /*view()函数声明 */node *p;int i;window(1,1,80,25); /* 定义文本窗口大小 */clrscr(); /* 清屏 */* 循环读取两个单链表中的值: q 是一个指向行单链表首节点的指 针,此单链表数据域的值为实际保存各行字符的列单链表 p 中的首节 点地址 */dop=q-next; /*p 指向保存行数据的列单链表的首节 点的地址 */cprintf(#); /* 每行开头

46、,打印此字符,不管前面是否有 回车符 */while(p!=NULL) /* 循环读取单链表 p 中的值 */出*号*/*/if(p-ch=13) putch(*); /* 若为回车键,打印elseputch(p-ch); /* 输出各行中的字符到预览窗口 p=p-next; /* 指向下一个节点 */q=q-nextl; /* 指向下一个节点 */printf(n);/* 输出一个回车 */while(q!=NULL);getch();clrscr();drawmain();/* 按任意键后,回到主窗口界面 */window(2,2,79,23);textbackground(9);for(

47、i=0;inext;while(p!=NULL&p-ch=32&p-chch!=13&p-ch!=-1) /* 指针 p 不能为空,且数据域必须为常规字符 */putch(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,

48、int m,int n) 函数来完成删除第行、 第列位置 的字符。它的具体过程在功能模块设计部分已经详细介绍。下面介绍另外 两个对字符进行检测的函数,它在字符的删除、插入等许多操作中都有用 到。(1) 调用 check(Hnode*Head,int m,int n)函数,在单链表中检查第 m行、第 n 列位置的字符,若为常规字符,则返回该字符;否则返回 0 或-1. ,(2) 调用 judge(Hnode*Hhead,int m)函数,在单链表中统计第 m 行中的常规字符的总个数,并返回统计值。int del(Hnode *Hhead,int m,int n)/*del(): 删除第 m 行,

49、第 n 列位置的字符 */Hnode *q,*q1; node *p1,*p2,*tail; int i,num=0,j,flag=0; q=Hhead;if(n=0&m=1)return; /* 第 1 行,第 0 列不存在 */if(n=0&m1) /*若为第 0 列字符,但行必须大于 1,执行向上行移处理 */n=76;m=m-1;gotoxy(n,m);/* 移至第 m-1 行,第 76 列 */ flag=1; /* 移位的标志置 1*/for(i=1;inextl;p1=q-next;for(i=1;inext;p2=p1-next; /*p2指向列单链表中的第 n 个元素 */i

50、f(n=1) /* 若是删除第 m 行第 1 列的字符 */q-next=p1-next;free(p1);elsep1-next=p2-next; /* 在单链表中删除第第n列的元素*/free(p2);/* 删除掉第 m 行第 n 列的元素后,处理行单链表中第 m 个节点后的数据向前移的任务 */while(num=judge(Hhead,m+)0) /* 执 行 一 次judge(Head,m)后,m才加1.这里必须满足行常规字符数不为 0的条件*/ p1=q-next; q1=q; if(p1!=NULL) /* 若当前行非空 */ while(p1-next!=NULL)p1=p1-

51、next;tail=p1;/*tail 保存列单链表最后一 个元素的地址 */q=q-nextl; /* 指向下一行的元素的 地址*/p1=p2=q-next;tail-next=p1; /*tail 的指针域指向 下一行的第一个元素的地址 */else /* 若当前行的字符个数为 0 ,即删除该 字符后,只剩下回车符,则将下一个行单链表中节点的数据域移至前一下 节点的数据域 */q=q-nextl; p1=p2=q-next; q1-next=p1;/*q1-next 指向下 一行的第一个元素的地址 */for(i=0;inext;if(p2-ch=13)break; /* 若为回车,跳出循

52、环 */q-next=p2; /* 在列单链表中去掉移至上行的元素 */p1-next=NULL;/* 下行移至上行的最后一 个元素,指针置空 */return flag; /* 返回 0 :表示没有换位,返回 1 :表示有换位 */int check(Hnode *Hhead,int m,int n) /*check(): 在单链表中检查第 m 行 第 n 列位置的字符,若为常规字符,则返回该字符 */int i;Hnode *q;node *p;q=Hhead;for(i=1;inextl;p=q-next;/* 获取第 m 个节点的数据域 */for(i=1;inext;if(p-ch=

53、13)return -1; /* 若第 m 行,第 n 列的字符为回车键,则返回 -1*/if(p-ch=32&p-chch; /* 若第 m 行,第 n 列的字符为常规字符 ,则返回该字符 */else return 0; /* 若第 m 行,第 n 列的字符既非回车符又非常规 字符,则返回 0*/返回第 m 行中的常规字符总int judge(Hnode *Hhead,int m) /*judge(): 的个数,不包括回车符 */Hnode *q;node *p;int i,num=0;q=Hhead;for(i=1;inextl;if(q=NULL) return -1; /* 返回 -

54、1, 表示第 m 行不存在 */ p=q-next;while(p-next!=NULL)p=p-next;num+; /* 统计第 m 行的字符个数 */ /* 行尾字符还没有判断,接下来判断行尾字符 */ if(p-ch=13&num=0)return 0;/* 返回 0, 表示当前行只有一个回车字符 */if(p-ch=32&p-chch=13&num!=0)return num; /* 返回 num, 表示当前行的最后一个字符为回车符,不计算在内 */else return 1;/* 返回 num, 表示当前行中只有一个字符,且没有回车符 */5. 插入字符在文本编辑 区中插 入字符的

55、工 作由 insert(Hnode,*Hhead,int m,int n,char a) 函数和 test(Hnode*Hhead,int n) 函数配合完成。(1) 通过 insert(Hnode*Hhead,int m,int n,char a) 函数,在第 m 行、第n列的位置之前的一个位置,在单链表中插入字符a。(2) 通过 test(Hnode*hhead,int n) 函数, 检查和处理第 n 行与后面的 数据 ,使 其 满足 每 行不 超 过 76 个字 符的 规 则 void insert(Hnode *Hhead,int m,int n, char a) /* 第 m 行,第

56、 n 列的位置之前一个位置,插 入单字符 */int i;Hnode *q;node *p,*p1,*p2;q=Hhead;for(i=1;inextl;定位至列单链表中的第 n-1 个元素 */p1=q-next; for(i=1;inext;p=(node *)malloc(sizeof(node); /* 创建一个新的列单链表节点*/八、p-ch=a; /* 给此节点的数据域赋值 */if(n=1) /* 插入之前,若只有一个字符在行中,则插在此节点之 前*/p-next=q-next;q-next=p;elsep-next=p1-next; /* 在第 m 行,第 n 列的字符前, 插

57、入一字符 */p1-next=p;test(Hhead,m); /* 在插入新元素后,检验并处理单链表中第m 行开始的元素,使其满足规则 */* 执行 insert() 后,检验第 n 行与后面的数据,使其满足规则 */int test(Hnode *Hhead,int n)int i=0,num1=1;node *p1,*p2,*tail,*temp1,*temp2;Hnode *q;q=Hhead;for(i=1;inextl;tail=p1=q-next;if(p1=NULL) return; /* 若此行没有任何字符,则返回 */while(tail-next!=NULL) /* 定位

58、至列单链表中的最后一个元素*/tail=tail-next;/* 若此单链表中没有回车符且有超过 76 个节点时,则 p1 会指向此列单链表中的第 76 个节点 */for(i=0;ich=13|p1-next=NULL) break;p1=p1-next;p2=p1-next;p1-next=NULL; /* 在此行的最后一个字符的前一个字符处断行 因为插入在此行插入了一个新的字符 */if(tail-ch!=13) /* 若此行行尾不是回车键 */if(p1-ch=13&q-nextl=NULL)/* 若 p1 的数据域 为回车符且行单链表中只有 n 个节点 */q-nextl=(Hnod

59、e *)malloc(sizeof(Hnode);/* 新建一个行单链表节点,相当于添加一个新行 */q-nextl-nextl=NULL;tail-next=(node *)malloc(sizeof(node);/*在 tail 所指节点位置开始继续准备添加字符 */tail-next-ch=13;tail-next-next=NULL;q-nextl-next=p2; /* 新行单链表节点保存 此行多出的字符 */else /* 若此行行尾和行中都没有回车键 ,或者 q-nextl 不 为空*/q=q-nextl;/*q-nextl 有可能为空 */tail-next=q-next;/* 将多出的字符与下一行的字 符相连 */q-next=p2;/*/if(q!=NULL) test(Hhead,+

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

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!