怎样实现一个可视化的文字编辑器(C语言版)?

[复制链接]
发表于 2025-9-22 02:14:25 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
一、软件安装

Visual Studio 2022

Visual Studio 2022 是微软提供的强大集成开发情况(IDE),广泛用于C/C++、C#、Python等多种编程语言的开发。它提供了很多强大的工具,资助开发者编写、调试和优化代码。
1.下载 Visual Studio 2022:访问Visual Studio 官网
2.点击 Download Visual Studio,选择 Community Edition(免费)或其他版本,根据需求选择。

2.安装 Visual Studio:运行下载的安装步伐,启动 Visual Studio 安装步伐。
在安装界面选择 Desktop development with C++,开发 C++ 步伐所需的工作负载。
可以根据必要选择其他组件,好比 Windows 10 SDK、C++ CMake tools 等,资助进行图形和图像处置惩罚的开发,完成安装后,启动 Visual Studio 2022,选择 Create a new project 来创建新的C++项目。(不会安装的可以搜一下干系教程)
安装 EasyX 图形库 

1.下载 EasyX 图形库:EasyX官网,根据必要选择符合版本。

2.安装 EasyX:


 
二、结果演示

1.界面样式

2.读入文件




3.查找


4.插入文字



5.更换

三、代码实现


Text.h:该文件是 Text.cpp 的头文件,声明了文本操作干系的结构体和函数接口。


  • Node 结构体:表现链表中的一个字符节点。包含字符内容、字符在屏幕上的位置、是否为平凡字符、是否被选中等信息。
  • Text 结构体:表现文本内容,包含头指针、尾指针和当前光标位置。
  • File 结构体:表现文件,包含文件路径和文本内容。
  • 函数声明:如 readFile()、writeFile()、insertText()、deleteCharacter() 等。
  1. #pragma once
  2. /*
  3. 该模块用于文本的操作
  4. */
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <stdbool.h>
  9. // 该结构体表示链表结点
  10. typedef struct Node Node;
  11. struct Node {
  12.         char content[3]; // 表示一个普通字符或中午字符
  13.         int rect[4]; // 字符在屏幕上所占的区域
  14.         bool normal; // 是否是普通字符
  15.         bool selected; // 是否被选中
  16.         Node* next;
  17.         Node* prev;
  18. };
  19. // 该结构体表示文本
  20. typedef struct Text Text;
  21. struct Text {
  22.         Node* head; // 头指针
  23.         Node* tail; // 尾指针
  24.         Node* cursor; // 当前指针位置
  25. };
  26. // 该结构体表示文件
  27. typedef struct File File;
  28. struct File {
  29.         char path[256]; // 文件的路径
  30.         Text* text; // 文件的内容
  31. };
  32. // 读入文件
  33. bool readFile(char* path);
  34. // 写入文件
  35. void writeFile();
  36. // 新建文件
  37. bool createFile(char* path);
  38. // 保存文件
  39. bool saveFile(char* path);
  40. // 获取当前文件
  41. File* getCurrentFile();
  42. // 释放相关内存
  43. void freeResources();
  44. // 插入文字
  45. void insertText(char* mContent);
  46. // 删除字符
  47. void deleteCharacter(bool isAfter);
  48. // 重置选中标志
  49. void resetSelected();
  50. // 查找字符串
  51. void findString(char* searchText);
  52. // 替换字符串
  53. void replaceString(char* srcText, char* dstText);
复制代码
Text.cpp:实现了文本内容的管理与操作,包罗文件的读取、生存、文本的插入、删除、查找和更换等。它利用了链表结构来构造文本内容。


  • readFile():

    • 读取指定路径的文件,并将文件内容分析为字符。读取的字符根据其字节数判定是平凡字符还是中文字符,并将其存储到链表中。
    • 利用 fread() 函数按字节读取文件内容,若字符为平凡字符,则将其存储在 content[] 中,若为中文字符,则按两个字节读取。

  • writeFile():

    • 将当前内存中的文本内容(链表结构)生存到文件中。通过 fopen() 打开文件,并逐个节点将文本内容写入。

  • createFile():

    • 创建新文件并为其分配内存。调用 writeFile() 生存当前文件内容,释放内存,创建新文件,并初始化新的文本结构。

  • insertText():

    • 在当前光标位置插入文本。通过 appendString() 函数将新的文本插入到链表的对应位置。

  • deleteCharacter():

    • 删除当前光标位置的字符。通过检查光标的位置(isAfter 参数决定删除前或后字符)来删除指定的字符节点。

  • findString():

    • 查找指定的字符串,并将找到的部门高亮表现。通过遍历链表中的节点,并检查每个节点的 content 是否与目的字符串匹配。

  • replaceString():

    • 查找并更换文本中的指定字符串。通过遍历链表查找目的字符串,若找到则更换为指定的新字符串。

  1. #include "Text.h"
  2. // 在某个节点后添加字符串
  3. void appendString(Node** beforeNode, char* mContent, bool modifyBeforeNode);
  4. // 当前的文件
  5. static File* curFile = NULL;
  6. // 为新文件分配内容
  7. static void initFile(File* file, char* path) {
  8.         strcpy(curFile->path, path);
  9.         curFile->text = (Text*)calloc(1, sizeof(Text));
  10.         curFile->text->head = (Node*)calloc(1, sizeof(Node));
  11.         curFile->text->tail = (Node*)calloc(1, sizeof(Node));
  12.         curFile->text->head->next = curFile->text->tail;
  13.         curFile->text->tail->prev = curFile->text->head;
  14.         curFile->text->cursor = curFile->text->head;
  15. }
  16. // 释放文件占用的内存
  17. static void destroyFile(File** file) {
  18.         while ((*file)->text->head->next != (*file)->text->tail) {
  19.                 Node* node = (*file)->text->head->next;
  20.                 (*file)->text->head->next = node->next;
  21.                 free(node);
  22.         }
  23.         free((*file)->text->head);
  24.         free((*file)->text->tail);
  25.         free(*file);
  26.         *file = NULL;
  27. }
  28. // 在Text中添加一个Node
  29. static void insertNode(Node* beforeNode, char content[], bool normal) {
  30.         Node* node = (Node*)calloc(1, sizeof(Node));
  31.         strcpy(node->content, content);
  32.         node->normal = normal;
  33.         node->selected = false;
  34.         node->next = beforeNode->next;
  35.         node->prev = beforeNode;
  36.         beforeNode->next->prev = node;
  37.         beforeNode->next = node;
  38. }
  39. // 读入文件
  40. bool readFile(char* path) {
  41.         // 确保文件存在
  42.         FILE* file = fopen(path, "rb");
  43.         if (!file) {
  44.                 return false;
  45.         }
  46.        
  47.         // 保存当前文件
  48.         writeFile();
  49.         // 释放内存
  50.         if (curFile) {
  51.                 destroyFile(&curFile);
  52.         }
  53.         // 为新文件分配内存
  54.         curFile = (File*)calloc(1, sizeof(File));
  55.         initFile(curFile, path);
  56.         // 读取新的文件
  57.         char byte;
  58.         char content[3] = {0};
  59.         bool normal;
  60.         while (fread(&byte, 1, 1, file) == 1) {
  61.                 if (byte >= 0) {
  62.                         // 这是普通字符
  63.                         content[0] = byte;
  64.                         if (byte == '\r') {
  65.                                 char nextByte;
  66.                                 fread(&nextByte, 1, 1, file);
  67.                                 content[1] = nextByte;
  68.                                 normal = false;
  69.                         }
  70.                         else {
  71.                                 content[1] = '\0';
  72.                                 normal = true;
  73.                         }
  74.                 }
  75.                 else {
  76.                         // 这是中文,其占2个字节
  77.                         char nextByte;
  78.                         fread(&nextByte, 1, 1, file);
  79.                         content[0] = byte;
  80.                         content[1] = nextByte;
  81.                         normal = false;
  82.                 }
  83.                 // 添加当前普通字符或者中文字符到文件的文本中
  84.                 insertNode(curFile->text->tail->prev, content, normal);
  85.         }
  86.         fclose(file);
  87.         return true;
  88. }
  89. // 写入文件
  90. void writeFile() {
  91.         if (!curFile) return;
  92.        
  93.         // 把新内容写入文件
  94.         FILE* fp = fopen(curFile->path, "w");
  95.         Node* node = curFile->text->head->next;
  96.         while (node != curFile->text->tail) {
  97.                 fprintf(fp, "%s", node->content);
  98.                 node = node->next;
  99.         }
  100.         fclose(fp);
  101. }
  102. // 新建文件
  103. bool createFile(char* path) {
  104.         // 保存当前文件
  105.         writeFile();
  106.         // 释放内存
  107.         if (curFile) {
  108.                 destroyFile(&curFile);
  109.         }
  110.         FILE* fp = fopen(path, "w");
  111.         if (!fp) return false;
  112.         fclose(fp);
  113.         // 为新文件分配内存
  114.         curFile = (File*)calloc(1, sizeof(File));
  115.         initFile(curFile, path);
  116.         return true;
  117. }
  118. // 保存文件
  119. bool saveFile(char* path) {
  120.         if (!curFile) return false;
  121.         // 把内容写入新的文件
  122.         FILE* fp = fopen(path, "w");
  123.         if (!fp) return false;
  124.         Node* node = curFile->text->head->next;
  125.         while (node != curFile->text->tail) {
  126.                 fprintf(fp, "%s", node->content);
  127.                 node = node->next;
  128.         }
  129.         fclose(fp);
  130.         return true;
  131. }
  132. // 获取当前文件
  133. File* getCurrentFile() {
  134.         return curFile;
  135. }
  136. // 释放相关内存
  137. void freeResources() {
  138.         if (curFile) {
  139.                 destroyFile(&curFile);
  140.         }
  141. }
  142. // 插入文字
  143. void insertText(char* mContent) {
  144.         if (!curFile || !mContent || strlen(mContent) == 0) return;
  145.         // 添加字符串到当前指针后面
  146.         appendString(&curFile->text->cursor, mContent, true);
  147. }
  148. // 删除当前字符
  149. void deleteCharacter(bool isAfter) {
  150.         if (curFile) {
  151.                 if (isAfter) {
  152.                         // 删除指针后面的字符
  153.                         Node* node = curFile->text->cursor->next;
  154.                         if (node != curFile->text->tail) {
  155.                                 curFile->text->cursor->next = node->next;
  156.                                 node->next->prev = curFile->text->cursor;
  157.                                 free(node);
  158.                         }
  159.                 }
  160.                 else {
  161.                         // 删除指针指向的字符
  162.                         Node* node = curFile->text->cursor;
  163.                         if (node != curFile->text->head) {
  164.                                 curFile->text->cursor = node->prev;
  165.                                 curFile->text->cursor->next = node->next;
  166.                                 node->next->prev = curFile->text->cursor;
  167.                                 free(node);
  168.                         }
  169.                 }
  170.         }
  171. }
  172. // 重置选中标志
  173. void resetSelected() {
  174.         if (!curFile) return;
  175.         Node* node = curFile->text->head->next;
  176.         while (node != curFile->text->tail) {
  177.                 node->selected = false;
  178.                 node = node->next;
  179.         }
  180. }
  181. // 查找字符串
  182. void findString(char* searchText) {
  183.         if (!curFile) return;
  184.         char content[3] = { 0 };
  185.         char byte;
  186.         size_t len = strlen(searchText);
  187.         Node* curNode = curFile->text->head->next;
  188.         while (curNode != curFile->text->tail) {
  189.                 Node* tmpNode = curNode;
  190.                 bool isFound = true;
  191.                 // 查找子串
  192.                 for (int i = 0; i < len && tmpNode != curFile->text->tail; i++) {
  193.                         byte = searchText[i];
  194.                         if (byte >= 0) {
  195.                                 // 这是普通字符
  196.                                 content[0] = byte;
  197.                                 if (byte == '\r') {
  198.                                         char nextByte = searchText[++i];
  199.                                         content[1] = nextByte;
  200.                                 }
  201.                                 else {
  202.                                         content[1] = '\0';
  203.                                 }
  204.                         }
  205.                         else {
  206.                                 // 这是中文,其占2个字节
  207.                                 char nextByte = searchText[++i];
  208.                                 content[0] = byte;
  209.                                 content[1] = nextByte;
  210.                         }
  211.                         // 判断两个字符是否相同
  212.                         if (strcmp(tmpNode->content, content) != 0) {
  213.                                 isFound = false;
  214.                                 break;
  215.                         }
  216.                         tmpNode = tmpNode->next;
  217.                 }
  218.                 if (isFound) {
  219.                         // 设置对应的字符序列为选中
  220.                         Node* node = curNode;
  221.                         while (node != tmpNode) {
  222.                                 node->selected = true;
  223.                                 node = node->next;
  224.                         }
  225.                 }
  226.                 curNode = curNode->next;
  227.         }
  228. }
  229. // 在某个节点后添加字符串
  230. void appendString(Node** beforeNode, char* mContent, bool modifyBeforeNode) {
  231.         int i = 0;
  232.         char byte;
  233.         bool normal;
  234.         char content[3] = { 0 };
  235.         size_t len = strlen(mContent);
  236.         Node* prev = *beforeNode;
  237.         while (i < len) {
  238.                 byte = mContent[i];
  239.                 if (byte >= 0) {
  240.                         // 这是普通字符
  241.                         content[0] = byte;
  242.                         if (byte == '\r') {
  243.                                 char nextByte = mContent[++i];
  244.                                 content[1] = nextByte;
  245.                                 normal = false;
  246.                         }
  247.                         else {
  248.                                 content[1] = '\0';
  249.                                 normal = true;
  250.                         }
  251.                 }
  252.                 else {
  253.                         // 这是中文,其占2个字节
  254.                         char nextByte = mContent[++i];
  255.                         content[0] = byte;
  256.                         content[1] = nextByte;
  257.                         normal = false;
  258.                 }
  259.                 // 添加当前普通字符或者中文字符到该指针后面
  260.                 insertNode(prev, content, normal);
  261.                 prev = prev->next;
  262.                 if (modifyBeforeNode) {
  263.                         *beforeNode = prev;
  264.                 }
  265.                 i++;
  266.         }
  267. }
  268. // 替换字符串
  269. void replaceString(char* srcText, char* dstText) {
  270.         if (!curFile) return;
  271.         char content[3] = { 0 };
  272.         char byte;
  273.         size_t len = strlen(srcText);
  274.         Node* curNode = curFile->text->head->next;
  275.         while (curNode != curFile->text->tail) {
  276.                 Node* tmpNode = curNode;
  277.                 bool isFound = true;
  278.                 // 查找子串
  279.                 for (int i = 0; i < len && tmpNode != curFile->text->tail; i++) {
  280.                         byte = srcText[i];
  281.                         if (byte >= 0) {
  282.                                 // 这是普通字符
  283.                                 content[0] = byte;
  284.                                 if (byte == '\r') {
  285.                                         char nextByte = srcText[++i];
  286.                                         content[1] = nextByte;
  287.                                 }
  288.                                 else {
  289.                                         content[1] = '\0';
  290.                                 }
  291.                         }
  292.                         else {
  293.                                 // 这是中文,其占2个字节
  294.                                 char nextByte = srcText[++i];
  295.                                 content[0] = byte;
  296.                                 content[1] = nextByte;
  297.                         }
  298.                         // 判断两个字符是否相同
  299.                         if (strcmp(tmpNode->content, content) != 0) {
  300.                                 isFound = false;
  301.                                 break;
  302.                         }
  303.                         tmpNode = tmpNode->next;
  304.                 }
  305.                 if (isFound) {
  306.                         // 首先删除原字符串
  307.                         Node* beforeNode = curNode->prev;
  308.                         while (beforeNode->next != tmpNode) {
  309.                                 Node* node = beforeNode->next;
  310.                                 beforeNode->next = node->next;
  311.                                 node->next->prev = beforeNode;
  312.                                 free(node);
  313.                         }
  314.                         curNode = tmpNode;
  315.                         // 添加替换字符串
  316.                         appendString(&beforeNode, dstText, false);
  317.                 }
  318.                 else {
  319.                         curNode = curNode->next;
  320.                 }
  321.         }
  322. }
复制代码
Editor.h:是 Editor.cpp 的头文件,声明了文本编辑器干系的函数接口,确保其他文件可以大概调用 Editor.cpp 中定义的函数。
声明了文本编辑器干系的函数,如:


  • initTextEditor():初始化编辑器。
  • runTextEditor():运行编辑器的主循环。
  • destroyTextEditor():烧毁编辑器。
  1. #pragma once
  2. /*
  3. 该模块用于显示文本编辑器的界面和用户交互
  4. */
  5. // 初始化文本编辑器
  6. void initTextEditor();
  7. // 运行文本编辑器
  8. void runTextEditor();
  9. // 销毁文本编辑器
  10. void destroyTextEditor();
复制代码
Editor.cpp:文本编辑器的核心,负责创建并表现图形界面,同时处置惩罚文件操作、文本编辑、用户输入变乱等。它利用 EasyX 图形库来绘制窗口和菜单,支持文件的读写操作、文本的插入与删除、文本的查找和更换。



  • initTextEditor():

    • 初始化文本编辑器,创建窗口并设置配景致。
    • 利用 initgraph() 函数来初始化窗口,setbkcolor() 设置配景致为白色,SetWindowText() 设置窗口的标题为 "文本编辑器"。
    • 还通过 readResources() 函数加载图像资源(如 editor.png),并设置图形界面的直线样式。

  • runTextEditor():

    • 启动文本编辑器的主循环。在这个循环中,步伐不绝更新窗口,扫除设备并重新绘制全部组件(如菜单和文当地域)。
    • 处置惩罚键盘变乱(如删除字符)和鼠标点击变乱(如选择菜单项):

      • 键盘变乱:当按下删除键(VK_BACK)时,删除当前光标位置的字符。
      • 鼠标变乱:检测鼠标点击的地域,根据用户点击的菜单项执行不同操作,如读入文件、写入文件、新建文件等。


  • drawWindow():

    • 用于绘制编辑器窗口,包罗配景图像、菜单地域和文当地域。
    • 利用 putimage() 函数绘制配景图像,并调用 drawMenu() 和 drawText() 来绘制菜单和文当地域。

  • drawMenu():

    • 绘制顶部的菜单地域,包罗文件操作(如读入、写入、生存等)和文本编辑操作(如插入文本、查找、更换)。
    • 利用 outtextxy() 函数绘制菜单项文本,并用 roundrect() 绘制按钮。

  • InsertText():

    • 提示用户输入要插入的文字,并调用 insertText() 函数将文字插入到当前光标位置。

  • FindString():

    • 查找字符串。调用 findString() 函数查找指定的字符串并将找到的文本高亮表现。

  • ReplaceString():

    • 更换字符串。通过 replaceString() 函数,查找指定的原字符串并将其更换为新字符串。

  1. #include "Editor.h"
  2. #include <graphics.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <stdbool.h>
  7. #include <time.h>
  8. #include <math.h>
  9. #include "Text.h"
  10. // 窗口大小
  11. static int WINDOW_WIDTH = 1000;
  12. static int WINDOW_HEIGHT = 700;
  13. // 设置每帧的时间
  14. static double FPS = 30;
  15. static double PER_FRAME_TIME = 1000.0 / FPS;
  16. // 查找字符串
  17. static char searchText[256] = {0};
  18. // 原字符串
  19. static char sourceText[256] = { 0 };
  20. // 替换字符串
  21. static char replaceText[256] = { 0 };
  22. // 设置菜单区域的位置
  23. static int MENU_LEFT_TOP[] = { 10, 80 };
  24. static int MENU_RIGHT_BOTTOM[] = { 900, 220 };
  25. static int PADDING[] = {50, 16};
  26. // 读入文件菜单位置
  27. static int READ_FILE_MENU[] = { MENU_LEFT_TOP[0] + PADDING[0], MENU_LEFT_TOP[1] + PADDING[1],
  28.                                                 MENU_LEFT_TOP[0] + PADDING[0] + 104, MENU_LEFT_TOP[1] + PADDING[1] + 25 };
  29. // 写入文件菜单位置
  30. static int WRITE_FILE_MENU[] = { READ_FILE_MENU[2] + PADDING[0], MENU_LEFT_TOP[1] + PADDING[1],
  31.                                                 READ_FILE_MENU[2] + PADDING[0] + 104, MENU_LEFT_TOP[1] + PADDING[1] + 25 };
  32. // 新建文件菜单位置
  33. static int CREATE_FILE_MENU[] = { WRITE_FILE_MENU[2] + PADDING[0], MENU_LEFT_TOP[1] + PADDING[1],
  34.                                                 WRITE_FILE_MENU[2] + PADDING[0] + 104, MENU_LEFT_TOP[1] + PADDING[1] + 25 };
  35. // 保存文件菜单位置
  36. static int SAVE_FILE_MENU[] = { CREATE_FILE_MENU[2] + PADDING[0], MENU_LEFT_TOP[1] + PADDING[1],
  37.                                                 CREATE_FILE_MENU[2] + PADDING[0] + 104, MENU_LEFT_TOP[1] + PADDING[1] + 25 };
  38. // 退出菜单位置
  39. static int EXIT_MENU[] = { SAVE_FILE_MENU[2] + PADDING[0], MENU_LEFT_TOP[1] + PADDING[1],
  40.                                                 SAVE_FILE_MENU[2] + PADDING[0] + 52, MENU_LEFT_TOP[1] + PADDING[1] + 25 };
  41. // 编辑文件菜单位置
  42. static int EDIT_FILE_MENU[] = { MENU_LEFT_TOP[0] + PADDING[0], READ_FILE_MENU[3] + PADDING[1],
  43.                                                 MENU_LEFT_TOP[0] + PADDING[0] + 104, READ_FILE_MENU[3] + PADDING[1] + 25 };
  44. // 插入菜单位置
  45. static int INSERT_TEXT_MENU[] = { MENU_LEFT_TOP[0] + PADDING[0], EDIT_FILE_MENU[3] + PADDING[1],
  46.                                                 MENU_LEFT_TOP[0] + PADDING[0] + 104, EDIT_FILE_MENU[3] + PADDING[1] + 25 };
  47. // 查找文本位置
  48. static int SEARCH_TEXT[] = { EDIT_FILE_MENU[2] + PADDING[0], READ_FILE_MENU[3] + PADDING[1],
  49.                                                 EDIT_FILE_MENU[2] + PADDING[0] + 208, READ_FILE_MENU[3] + PADDING[1] + 25 };
  50. // 查找菜单位置
  51. static int FIND_MENU[] = { SEARCH_TEXT[2] + PADDING[0], READ_FILE_MENU[3] + PADDING[1],
  52.                                                 SEARCH_TEXT[2] + PADDING[0] + 52, READ_FILE_MENU[3] + PADDING[1] + 25 };
  53. // 清除高亮菜单位置
  54. static int CLEAR_MENU[] = { FIND_MENU[2] + PADDING[0], READ_FILE_MENU[3] + PADDING[1],
  55.                                                 FIND_MENU[2] + PADDING[0] + 104, READ_FILE_MENU[3] + PADDING[1] + 25 };
  56. // 原文本位置
  57. static int SOURCE_TEXT[] = { EDIT_FILE_MENU[2] + PADDING[0], FIND_MENU[3] + PADDING[1],
  58.                                                 EDIT_FILE_MENU[2] + PADDING[0] + 208, FIND_MENU[3] + PADDING[1] + 25 };
  59. // 替换文本位置
  60. static int REPLACE_TEXT[] = { SOURCE_TEXT[2] + PADDING[0], FIND_MENU[3] + PADDING[1],
  61.                                                 SOURCE_TEXT[2] + PADDING[0] + 208, FIND_MENU[3] + PADDING[1] + 25 };
  62. // 替换菜单位置
  63. static int REPLACE_MENU[] = { REPLACE_TEXT[2] + PADDING[0], FIND_MENU[3] + PADDING[1],
  64.                                                 REPLACE_TEXT[2] + PADDING[0] + 52, FIND_MENU[3] + PADDING[1] + 25 };
  65. // 文本区域位置
  66. static int TEXT_AREA[] = { 10, MENU_RIGHT_BOTTOM[1] + PADDING[1],
  67.                                                 WINDOW_WIDTH-20, WINDOW_HEIGHT - 20 };
  68. // 图片资源
  69. static IMAGE editorImage;
  70. // 读取图片资源
  71. static void readResources();
  72. // 绘制窗口
  73. static void drawWindow();
  74. // 绘制菜单区域
  75. static void drawMenu();
  76. // 绘制文本区域
  77. static void drawText();
  78. // 读入文件
  79. static void ReadFile();
  80. // 写入文件
  81. static void WriteFile();
  82. // 新建文件
  83. static void CreateNewFile();
  84. // 保存文件
  85. static void SaveFile();
  86. // 插入文字
  87. static void InsertText();
  88. // 查找
  89. static void FindString();
  90. // 清除输入
  91. static void ClearInput();
  92. // 替换
  93. static void ReplaceString();
  94. // 更新文件指针位置
  95. static void updateCursor(int x, int y);
  96. // 初始化文本编辑器
  97. void initTextEditor() {
  98.         // 创建窗口
  99.         initgraph(WINDOW_WIDTH, WINDOW_HEIGHT);
  100.         setbkcolor(RGB(255, 255, 255));
  101.         // 设置窗口名称
  102.         HWND hWnd = GetHWnd();
  103.         SetWindowText(hWnd, "文本编辑器");
  104.         // 读取图片资源
  105.         readResources();
  106.         // 设置直线样式
  107.         LINESTYLE style;
  108.         style.thickness = 2;
  109.         setlinestyle(&style);
  110. }
  111. // 运行文本编辑器
  112. void runTextEditor() {
  113.         bool exitCode = false;
  114.         while (!exitCode) {
  115.                 int startTime = clock();
  116.                 // 双缓冲
  117.                 BeginBatchDraw();
  118.                 cleardevice();
  119.                 // 绘制窗口
  120.                 drawWindow();
  121.                 EndBatchDraw();
  122.                 // 处理消息
  123.                 static ExMessage msg;
  124.                 while (peekmessage(&msg, EM_KEY | EM_MOUSE)) {
  125.                         // 键盘按下事件
  126.                         if (msg.message == WM_KEYDOWN) {
  127.                                 if (msg.vkcode == VK_BACK) {
  128.                                         // 删除指针指向的字符
  129.                                         deleteCharacter(false);
  130.                                 }
  131.                                 else if (msg.vkcode == VK_DELETE) {
  132.                                         // 删除指针后面的字符
  133.                                         deleteCharacter(true);
  134.                                 }
  135.                         }
  136.                         // 鼠标左键按下事件
  137.                         else if (msg.message == WM_LBUTTONDOWN) {
  138.                                 int x = msg.x;
  139.                                 int y = msg.y;
  140.                                 // 点击了读入文件按钮
  141.                                 if (x > READ_FILE_MENU[0] && x < READ_FILE_MENU[2] &&
  142.                                         y > READ_FILE_MENU[1] && y < READ_FILE_MENU[3]) {
  143.                                         ReadFile();
  144.                                 }
  145.                                 // 点击了写入文件按钮
  146.                                 else if (x > WRITE_FILE_MENU[0] && x < WRITE_FILE_MENU[2] &&
  147.                                         y > WRITE_FILE_MENU[1] && y < WRITE_FILE_MENU[3]) {
  148.                                         WriteFile();
  149.                                 }
  150.                                 // 点击了创建文件按钮
  151.                                 else if (x > CREATE_FILE_MENU[0] && x < CREATE_FILE_MENU[2] &&
  152.                                         y > CREATE_FILE_MENU[1] && y < CREATE_FILE_MENU[3]) {
  153.                                         CreateNewFile();
  154.                                 }
  155.                                 // 点击了保存文件按钮
  156.                                 else if (x > SAVE_FILE_MENU[0] && x < SAVE_FILE_MENU[2] &&
  157.                                         y > SAVE_FILE_MENU[1] && y < SAVE_FILE_MENU[3]) {
  158.                                         SaveFile();
  159.                                 }
  160.                                 // 点击了退出按钮
  161.                                 else if (x > EXIT_MENU[0] && x < EXIT_MENU[2] &&
  162.                                         y > EXIT_MENU[1] && y < EXIT_MENU[3]) {
  163.                                         // 释放相关内存
  164.                                         freeResources();
  165.                                         exitCode = true;
  166.                                         break;
  167.                                 }
  168.                                 // 点击了插入文字按钮
  169.                                 else if (x > INSERT_TEXT_MENU[0] && x < INSERT_TEXT_MENU[2] &&
  170.                                         y > INSERT_TEXT_MENU[1] && y < INSERT_TEXT_MENU[3]) {
  171.                                         InsertText();
  172.                                 }
  173.                                 // 点击了查找按钮
  174.                                 else if (x > FIND_MENU[0] && x < FIND_MENU[2] &&
  175.                                         y > FIND_MENU[1] && y < FIND_MENU[3]) {
  176.                                         FindString();
  177.                                 }
  178.                                 // 点击了清楚高亮按钮
  179.                                 else if (x > CLEAR_MENU[0] && x < CLEAR_MENU[2] &&
  180.                                         y > CLEAR_MENU[1] && y < CLEAR_MENU[3]) {
  181.                                         ClearInput();
  182.                                 }
  183.                                 // 点击了替换按钮
  184.                                 else if (x > REPLACE_MENU[0] && x < REPLACE_MENU[2] &&
  185.                                         y > REPLACE_MENU[1] && y < REPLACE_MENU[3]) {
  186.                                         ReplaceString();
  187.                                 }
  188.                                 // 点击了文本区域
  189.                                 else if (x > TEXT_AREA[0] && x < TEXT_AREA[2] &&
  190.                                         y > TEXT_AREA[1] && y < TEXT_AREA[3]) {
  191.                                         updateCursor(x, y);
  192.                                 }
  193.                                 // 输入查找字符串
  194.                                 else if (x > SEARCH_TEXT[0] && x < SEARCH_TEXT[2] &&
  195.                                         y > SEARCH_TEXT[1] && y < SEARCH_TEXT[3]) {
  196.                                         InputBox(searchText, 255, "输入查找字符串:");
  197.                                 }
  198.                                 // 输入原字符串
  199.                                 else if (x > SOURCE_TEXT[0] && x < SOURCE_TEXT[2] &&
  200.                                         y > SOURCE_TEXT[1] && y < SOURCE_TEXT[3]) {
  201.                                         InputBox(sourceText, 255, "输入原字符串:");
  202.                                 }
  203.                                 // 输入替换字符串
  204.                                 else if (x > REPLACE_TEXT[0] && x < REPLACE_TEXT[2] &&
  205.                                         y > REPLACE_TEXT[1] && y < REPLACE_TEXT[3]) {
  206.                                         InputBox(replaceText, 255, "输入替换字符串:");
  207.                                 }
  208.                         }
  209.                 }
  210.                 // 控制每帧时间
  211.                 int duration = clock() - startTime;
  212.                 if (duration < PER_FRAME_TIME) {
  213.                         Sleep(PER_FRAME_TIME - duration);
  214.                 }
  215.         }
  216. }
  217. // 销毁文本编辑器
  218. void destroyTextEditor() {
  219.         closegraph();
  220. }
  221. // 读取图片资源
  222. static void readResources() {
  223.         loadimage(&editorImage, "editor.png");
  224. }
  225. // 绘制窗口
  226. static void drawWindow() {
  227.         // 绘制编辑器图片
  228.         putimage(0, 0, &editorImage);
  229.         // 绘制菜单区域
  230.         drawMenu();
  231.         // 绘制文本区域
  232.         drawText();
  233. }
  234. // 绘制菜单区域
  235. static void drawMenu() {
  236.         // 设置字体
  237.         LOGFONT f;
  238.         gettextstyle(&f);
  239.         f.lfHeight = 25;
  240.         _tcscpy(f.lfFaceName, _T("黑体"));
  241.         f.lfQuality = ANTIALIASED_QUALITY;
  242.         f.lfWeight = 800;
  243.         settextstyle(&f);
  244.         settextcolor(RGB(0, 0, 0));
  245.         // 绘制文件编辑器的菜单
  246.         setlinecolor(RGB(0, 0, 0));
  247.         rectangle(MENU_LEFT_TOP[0], MENU_LEFT_TOP[1], MENU_RIGHT_BOTTOM[0], MENU_RIGHT_BOTTOM[1]);
  248.         // 读入文件菜单
  249.         outtextxy(READ_FILE_MENU[0], READ_FILE_MENU[1], "读入文件");
  250.         roundrect(READ_FILE_MENU[0], READ_FILE_MENU[1], READ_FILE_MENU[2], READ_FILE_MENU[3], 5, 5);
  251.         // 写入文件菜单
  252.         outtextxy(WRITE_FILE_MENU[0], WRITE_FILE_MENU[1], "写入文件");
  253.         roundrect(WRITE_FILE_MENU[0], WRITE_FILE_MENU[1], WRITE_FILE_MENU[2], WRITE_FILE_MENU[3], 5, 5);
  254.         // 新建文件菜单
  255.         outtextxy(CREATE_FILE_MENU[0], CREATE_FILE_MENU[1], "新建文件");
  256.         roundrect(CREATE_FILE_MENU[0], CREATE_FILE_MENU[1], CREATE_FILE_MENU[2], CREATE_FILE_MENU[3], 5, 5);
  257.         // 保存文件菜单
  258.         outtextxy(SAVE_FILE_MENU[0], SAVE_FILE_MENU[1], "保存文件");
  259.         roundrect(SAVE_FILE_MENU[0], SAVE_FILE_MENU[1], SAVE_FILE_MENU[2], SAVE_FILE_MENU[3], 5, 5);
  260.         // 退出菜单
  261.         outtextxy(EXIT_MENU[0], EXIT_MENU[1], "退出");
  262.         roundrect(EXIT_MENU[0], EXIT_MENU[1], EXIT_MENU[2], EXIT_MENU[3], 5, 5);
  263.         // 编辑文件菜单
  264.         outtextxy(EDIT_FILE_MENU[0], EDIT_FILE_MENU[1], "编辑文件");
  265.         // 插入菜单
  266.         outtextxy(INSERT_TEXT_MENU[0], INSERT_TEXT_MENU[1], "插入文字");
  267.         roundrect(INSERT_TEXT_MENU[0], INSERT_TEXT_MENU[1], INSERT_TEXT_MENU[2], INSERT_TEXT_MENU[3], 5, 5);
  268.         // 查找菜单
  269.         outtextxy(FIND_MENU[0], FIND_MENU[1], "查找");
  270.         roundrect(FIND_MENU[0], FIND_MENU[1], FIND_MENU[2], FIND_MENU[3], 5, 5);
  271.         // 清除输入菜单
  272.         outtextxy(CLEAR_MENU[0], CLEAR_MENU[1], "清除输入");
  273.         roundrect(CLEAR_MENU[0], CLEAR_MENU[1], CLEAR_MENU[2], CLEAR_MENU[3], 5, 5);
  274.         // 替换菜单
  275.         outtextxy(REPLACE_MENU[0], REPLACE_MENU[1], "替换");
  276.         roundrect(REPLACE_MENU[0], REPLACE_MENU[1], REPLACE_MENU[2], REPLACE_MENU[3], 5, 5);
  277.         // 设置字体
  278.         gettextstyle(&f);
  279.         f.lfHeight = 18;
  280.         _tcscpy(f.lfFaceName, _T("宋体"));
  281.         f.lfQuality = ANTIALIASED_QUALITY;
  282.         f.lfWeight = 800;
  283.         settextstyle(&f);
  284.         settextcolor(RGB(0, 0, 0));
  285.         // 查找文本
  286.         if (strlen(searchText) > 0) {
  287.                 outtextxy(SEARCH_TEXT[0], SEARCH_TEXT[1]+3, searchText);
  288.         }
  289.         roundrect(SEARCH_TEXT[0], SEARCH_TEXT[1], SEARCH_TEXT[2], SEARCH_TEXT[3], 5, 5);
  290.         // 原文本
  291.         if (strlen(sourceText) > 0) {
  292.                 outtextxy(SOURCE_TEXT[0], SOURCE_TEXT[1] + 3, sourceText);
  293.         }
  294.         roundrect(SOURCE_TEXT[0], SOURCE_TEXT[1], SOURCE_TEXT[2], SOURCE_TEXT[3], 5, 5);
  295.         // 替换文本
  296.         if (strlen(replaceText) > 0) {
  297.                 outtextxy(REPLACE_TEXT[0], REPLACE_TEXT[1] + 3, replaceText);
  298.         }
  299.         roundrect(REPLACE_TEXT[0], REPLACE_TEXT[1], REPLACE_TEXT[2], REPLACE_TEXT[3], 5, 5);
  300. }
  301. // 绘制文本区域
  302. static void drawText() {
  303.         // 设置字体
  304.         LOGFONT f;
  305.         gettextstyle(&f);
  306.         f.lfHeight = 20;
  307.         f.lfWeight = 600;
  308.         _tcscpy(f.lfFaceName, _T("宋体"));
  309.         f.lfQuality = ANTIALIASED_QUALITY;
  310.         settextstyle(&f);
  311.         settextcolor(RGB(0, 0, 0));
  312.         // 显示文本区域框
  313.         rectangle(TEXT_AREA[0], TEXT_AREA[1], TEXT_AREA[2], TEXT_AREA[3]);
  314.         // 显示文件内容
  315.         File* file = getCurrentFile();
  316.         if (!file) return;
  317.         int leftX = TEXT_AREA[0] + 5;
  318.         int x = leftX;
  319.         int y = TEXT_AREA[1] + 5;
  320.         int w = textwidth("a");
  321.         int h = f.lfHeight;
  322.         Node* node = file->text->head->next;
  323.         // 设置头指针的位置
  324.         file->text->head->rect[0] = TEXT_AREA[0]+4;
  325.         file->text->head->rect[1] = y;
  326.         file->text->head->rect[2] = TEXT_AREA[0]+4;
  327.         file->text->head->rect[3] = y;
  328.         // 如果文件是空的,则在开头显示指针
  329.         if (node == file->text->tail) {
  330.                 line(node->prev->rect[2], node->prev->rect[1], node->prev->rect[2], node->prev->rect[1] + h);
  331.                 return;
  332.         }
  333.         while (node != file->text->tail) {
  334.                 // 设置字符所占的区域
  335.                 node->rect[0] = x;
  336.                 node->rect[1] = y;
  337.                 node->rect[2] = x + (node->normal ? w : w*2);
  338.                 node->rect[3] = y + h;
  339.                 // 判断是否需要换行
  340.                 if (strcmp(node->content, "\r\n") == 0 || strcmp(node->content, "\n") == 0
  341.                         || node->rect[2] >= TEXT_AREA[2]) {
  342.                         // 需要换行,更新位置
  343.                         x = leftX;
  344.                         y += f.lfHeight;
  345.                         node->rect[0] = x;
  346.                         node->rect[1] = y;
  347.                         node->rect[2] = x + (node->normal ? w : w * 2);
  348.                         node->rect[3] = y + h;
  349.                 }
  350.                 if (strcmp(node->content, "\r\n") != 0 && strcmp(node->content, "\n") != 0) {
  351.                         // 如果字符被选中,则更改颜色
  352.                         if (node->selected) {
  353.                                 setcolor(RED);
  354.                         }
  355.                         else {
  356.                                 setcolor(BLACK);
  357.                         }
  358.                         // 显示该字符
  359.                         outtextxy(node->rect[0], node->rect[1], node->content);
  360.                         // 更新x值
  361.                         x = node->rect[2];
  362.                 }
  363.                 // 绘制当前位置指针
  364.                 if (file->text->cursor == node->prev) {
  365.                         line(node->prev->rect[2], node->prev->rect[1], node->prev->rect[2], node->prev->rect[1] + h);
  366.                 }
  367.                 else if (file->text->cursor == node && node->next == file->text->tail) {
  368.                         line(node->rect[2], node->rect[1], node->rect[2], node->rect[1] + h);
  369.                 }
  370.                 node = node->next;
  371.         }
  372. }
  373. // 更新文件指针位置
  374. static void updateCursor(int x, int y) {
  375.         File* file = getCurrentFile();
  376.         if (!file) return;
  377.         // 设置文件指针到最靠近鼠标的文字的位置(距离不能超过26)
  378.         int minDistance = INT_MAX;
  379.         Node* node = file->text->head->next;
  380.         while (node != file->text->tail) {
  381.                 if (x > node->rect[0] && x < node->rect[2] &&
  382.                         y > node->rect[1] && y < node->rect[3]) {
  383.                         file->text->cursor = node;
  384.                         break;
  385.                 }
  386.                 else {
  387.                         // 判断该文字是否更加靠近鼠标点击的位置
  388.                         int dx = (node->rect[0] + node->rect[2]) / 2 - x;
  389.                         int dy = (node->rect[1] + node->rect[3]) / 2 - y;
  390.                         double dist = sqrt(dx * dx + dy * dy);
  391.                         if (dist < 26 && dist < minDistance) {
  392.                                 minDistance = dist;
  393.                                 file->text->cursor = node;
  394.                         }
  395.                 }
  396.                 node = node->next;
  397.         }
  398. }
  399. // 读入文件
  400. static void ReadFile() {
  401.         // 提示用户输入文件路径
  402.         char path[256];
  403.         InputBox(path, 255, "输入文件路径:");
  404.         // 读入文件内容
  405.         if (!readFile(path)) {
  406.                 MessageBox(GetHWnd(), "该文件不存在", "提示", MB_OK);
  407.         }
  408. }
  409. // 写入文件
  410. static void WriteFile() {
  411.         if (getCurrentFile()) {
  412.                 writeFile();
  413.                 MessageBox(GetHWnd(), "内容已被写入文件", "提示", MB_OK);
  414.         }
  415. }
  416. // 新建文件
  417. static void CreateNewFile() {
  418.         // 提示用户输入文件路径
  419.         char path[256];
  420.         InputBox(path, 255, "输入文件路径:");
  421.         // 创建新的文件
  422.         if (!createFile(path)) {
  423.                 MessageBox(GetHWnd(), "创建文件失败", "提示", MB_OK);
  424.         }
  425. }
  426. // 保存文件
  427. static void SaveFile() {
  428.         // 提示用户输入文件路径
  429.         char path[256];
  430.         InputBox(path, 255, "输入文件路径:");
  431.         if (!saveFile(path)) {
  432.                 MessageBox(GetHWnd(), "保存文件失败", "提示", MB_OK);
  433.         }
  434.         else {
  435.                 MessageBox(GetHWnd(), "文件已被保存", "提示", MB_OK);
  436.         }
  437. }
  438. // 插入文字
  439. static void InsertText() {
  440.         // 提示输入要插入的文字
  441.         char content[256];
  442.         InputBox(content, 255, "输入要插入的文字:");
  443.         // 把该文字插入指针所在位置
  444.         insertText(content);
  445. }
  446. // 查找
  447. static void FindString() {
  448.         resetSelected();
  449.         if (strlen(searchText) > 0) {
  450.                 findString(searchText);
  451.         }
  452. }
  453. // 清除输入
  454. static void ClearInput() {
  455.         memset(searchText, 0, sizeof(searchText));
  456.         memset(sourceText, 0, sizeof(sourceText));
  457.         memset(replaceText, 0, sizeof(replaceText));
  458.         // 重置选中标志
  459.         resetSelected();
  460. }
  461. // 替换
  462. static void ReplaceString() {
  463.         if (strlen(sourceText) > 0 && strlen(replaceText) > 0) {
  464.                 replaceString(sourceText, replaceText);
  465.         }
  466. }
复制代码
Main.cpp:步伐的入口文件,紧张用于启动文本编辑器的初始化、运行和烧毁。
main():


  • 步伐启动时起首调用 initTextEditor() 函数初始化文本编辑器。
  • 接着调用 runTextEditor() 启动文本编辑器的主循环,答应用户进行各种操作(如文件操作、文本编辑等)。
  • 末了通过 destroyTextEditor() 烧毁编辑器,释放资源。
  1. #include "Editor.h"
  2. int main() {
  3.         // 初始化文本编辑器
  4.         initTextEditor();
  5.         // 运行文本编辑器
  6.         runTextEditor();
  7.         // 销毁文本编辑器
  8.         destroyTextEditor();
  9.         return 0;
  10. }
复制代码

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表