一、软件安装
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()
等。
cpp
#pragma once
/*
该模块用于文本的操作
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
// 该结构体表示链表结点
typedef struct Node Node;
struct Node {
char content[3]; // 表示一个普通字符或中午字符
int rect[4]; // 字符在屏幕上所占的区域
bool normal; // 是否是普通字符
bool selected; // 是否被选中
Node* next;
Node* prev;
};
// 该结构体表示文本
typedef struct Text Text;
struct Text {
Node* head; // 头指针
Node* tail; // 尾指针
Node* cursor; // 当前指针位置
};
// 该结构体表示文件
typedef struct File File;
struct File {
char path[256]; // 文件的路径
Text* text; // 文件的内容
};
// 读入文件
bool readFile(char* path);
// 写入文件
void writeFile();
// 新建文件
bool createFile(char* path);
// 保存文件
bool saveFile(char* path);
// 获取当前文件
File* getCurrentFile();
// 释放相关内存
void freeResources();
// 插入文字
void insertText(char* mContent);
// 删除字符
void deleteCharacter(bool isAfter);
// 重置选中标志
void resetSelected();
// 查找字符串
void findString(char* searchText);
// 替换字符串
void replaceString(char* srcText, char* dstText);
Text.cpp:实现了文本内容的管理与操作,包括文件的读取、保存、文本的插入、删除、查找和替换等。它使用了链表结构来组织文本内容。
-
readFile()
:-
读取指定路径的文件,并将文件内容解析为字符。读取的字符根据其字节数判断是普通字符还是中文字符,并将其存储到链表中。
-
使用
fread()
函数按字节读取文件内容,若字符为普通字符,则将其存储在content[]
中,若为中文字符,则按两个字节读取。
-
-
writeFile()
:- 将当前内存中的文本内容(链表结构)保存到文件中。通过
fopen()
打开文件,并逐个节点将文本内容写入。
- 将当前内存中的文本内容(链表结构)保存到文件中。通过
-
createFile()
:- 创建新文件并为其分配内存。调用
writeFile()
保存当前文件内容,释放内存,创建新文件,并初始化新的文本结构。
- 创建新文件并为其分配内存。调用
-
insertText()
:- 在当前光标位置插入文本。通过
appendString()
函数将新的文本插入到链表的对应位置。
- 在当前光标位置插入文本。通过
-
deleteCharacter()
:- 删除当前光标位置的字符。通过检查光标的位置(
isAfter
参数决定删除前或后字符)来删除指定的字符节点。
- 删除当前光标位置的字符。通过检查光标的位置(
-
findString()
:- 查找指定的字符串,并将找到的部分高亮显示。通过遍历链表中的节点,并检查每个节点的
content
是否与目标字符串匹配。
- 查找指定的字符串,并将找到的部分高亮显示。通过遍历链表中的节点,并检查每个节点的
-
replaceString()
:- 查找并替换文本中的指定字符串。通过遍历链表查找目标字符串,若找到则替换为指定的新字符串。
cpp
#include "Text.h"
// 在某个节点后添加字符串
void appendString(Node** beforeNode, char* mContent, bool modifyBeforeNode);
// 当前的文件
static File* curFile = NULL;
// 为新文件分配内容
static void initFile(File* file, char* path) {
strcpy(curFile->path, path);
curFile->text = (Text*)calloc(1, sizeof(Text));
curFile->text->head = (Node*)calloc(1, sizeof(Node));
curFile->text->tail = (Node*)calloc(1, sizeof(Node));
curFile->text->head->next = curFile->text->tail;
curFile->text->tail->prev = curFile->text->head;
curFile->text->cursor = curFile->text->head;
}
// 释放文件占用的内存
static void destroyFile(File** file) {
while ((*file)->text->head->next != (*file)->text->tail) {
Node* node = (*file)->text->head->next;
(*file)->text->head->next = node->next;
free(node);
}
free((*file)->text->head);
free((*file)->text->tail);
free(*file);
*file = NULL;
}
// 在Text中添加一个Node
static void insertNode(Node* beforeNode, char content[], bool normal) {
Node* node = (Node*)calloc(1, sizeof(Node));
strcpy(node->content, content);
node->normal = normal;
node->selected = false;
node->next = beforeNode->next;
node->prev = beforeNode;
beforeNode->next->prev = node;
beforeNode->next = node;
}
// 读入文件
bool readFile(char* path) {
// 确保文件存在
FILE* file = fopen(path, "rb");
if (!file) {
return false;
}
// 保存当前文件
writeFile();
// 释放内存
if (curFile) {
destroyFile(&curFile);
}
// 为新文件分配内存
curFile = (File*)calloc(1, sizeof(File));
initFile(curFile, path);
// 读取新的文件
char byte;
char content[3] = {0};
bool normal;
while (fread(&byte, 1, 1, file) == 1) {
if (byte >= 0) {
// 这是普通字符
content[0] = byte;
if (byte == '\r') {
char nextByte;
fread(&nextByte, 1, 1, file);
content[1] = nextByte;
normal = false;
}
else {
content[1] = '\0';
normal = true;
}
}
else {
// 这是中文,其占2个字节
char nextByte;
fread(&nextByte, 1, 1, file);
content[0] = byte;
content[1] = nextByte;
normal = false;
}
// 添加当前普通字符或者中文字符到文件的文本中
insertNode(curFile->text->tail->prev, content, normal);
}
fclose(file);
return true;
}
// 写入文件
void writeFile() {
if (!curFile) return;
// 把新内容写入文件
FILE* fp = fopen(curFile->path, "w");
Node* node = curFile->text->head->next;
while (node != curFile->text->tail) {
fprintf(fp, "%s", node->content);
node = node->next;
}
fclose(fp);
}
// 新建文件
bool createFile(char* path) {
// 保存当前文件
writeFile();
// 释放内存
if (curFile) {
destroyFile(&curFile);
}
FILE* fp = fopen(path, "w");
if (!fp) return false;
fclose(fp);
// 为新文件分配内存
curFile = (File*)calloc(1, sizeof(File));
initFile(curFile, path);
return true;
}
// 保存文件
bool saveFile(char* path) {
if (!curFile) return false;
// 把内容写入新的文件
FILE* fp = fopen(path, "w");
if (!fp) return false;
Node* node = curFile->text->head->next;
while (node != curFile->text->tail) {
fprintf(fp, "%s", node->content);
node = node->next;
}
fclose(fp);
return true;
}
// 获取当前文件
File* getCurrentFile() {
return curFile;
}
// 释放相关内存
void freeResources() {
if (curFile) {
destroyFile(&curFile);
}
}
// 插入文字
void insertText(char* mContent) {
if (!curFile || !mContent || strlen(mContent) == 0) return;
// 添加字符串到当前指针后面
appendString(&curFile->text->cursor, mContent, true);
}
// 删除当前字符
void deleteCharacter(bool isAfter) {
if (curFile) {
if (isAfter) {
// 删除指针后面的字符
Node* node = curFile->text->cursor->next;
if (node != curFile->text->tail) {
curFile->text->cursor->next = node->next;
node->next->prev = curFile->text->cursor;
free(node);
}
}
else {
// 删除指针指向的字符
Node* node = curFile->text->cursor;
if (node != curFile->text->head) {
curFile->text->cursor = node->prev;
curFile->text->cursor->next = node->next;
node->next->prev = curFile->text->cursor;
free(node);
}
}
}
}
// 重置选中标志
void resetSelected() {
if (!curFile) return;
Node* node = curFile->text->head->next;
while (node != curFile->text->tail) {
node->selected = false;
node = node->next;
}
}
// 查找字符串
void findString(char* searchText) {
if (!curFile) return;
char content[3] = { 0 };
char byte;
size_t len = strlen(searchText);
Node* curNode = curFile->text->head->next;
while (curNode != curFile->text->tail) {
Node* tmpNode = curNode;
bool isFound = true;
// 查找子串
for (int i = 0; i < len && tmpNode != curFile->text->tail; i++) {
byte = searchText[i];
if (byte >= 0) {
// 这是普通字符
content[0] = byte;
if (byte == '\r') {
char nextByte = searchText[++i];
content[1] = nextByte;
}
else {
content[1] = '\0';
}
}
else {
// 这是中文,其占2个字节
char nextByte = searchText[++i];
content[0] = byte;
content[1] = nextByte;
}
// 判断两个字符是否相同
if (strcmp(tmpNode->content, content) != 0) {
isFound = false;
break;
}
tmpNode = tmpNode->next;
}
if (isFound) {
// 设置对应的字符序列为选中
Node* node = curNode;
while (node != tmpNode) {
node->selected = true;
node = node->next;
}
}
curNode = curNode->next;
}
}
// 在某个节点后添加字符串
void appendString(Node** beforeNode, char* mContent, bool modifyBeforeNode) {
int i = 0;
char byte;
bool normal;
char content[3] = { 0 };
size_t len = strlen(mContent);
Node* prev = *beforeNode;
while (i < len) {
byte = mContent[i];
if (byte >= 0) {
// 这是普通字符
content[0] = byte;
if (byte == '\r') {
char nextByte = mContent[++i];
content[1] = nextByte;
normal = false;
}
else {
content[1] = '\0';
normal = true;
}
}
else {
// 这是中文,其占2个字节
char nextByte = mContent[++i];
content[0] = byte;
content[1] = nextByte;
normal = false;
}
// 添加当前普通字符或者中文字符到该指针后面
insertNode(prev, content, normal);
prev = prev->next;
if (modifyBeforeNode) {
*beforeNode = prev;
}
i++;
}
}
// 替换字符串
void replaceString(char* srcText, char* dstText) {
if (!curFile) return;
char content[3] = { 0 };
char byte;
size_t len = strlen(srcText);
Node* curNode = curFile->text->head->next;
while (curNode != curFile->text->tail) {
Node* tmpNode = curNode;
bool isFound = true;
// 查找子串
for (int i = 0; i < len && tmpNode != curFile->text->tail; i++) {
byte = srcText[i];
if (byte >= 0) {
// 这是普通字符
content[0] = byte;
if (byte == '\r') {
char nextByte = srcText[++i];
content[1] = nextByte;
}
else {
content[1] = '\0';
}
}
else {
// 这是中文,其占2个字节
char nextByte = srcText[++i];
content[0] = byte;
content[1] = nextByte;
}
// 判断两个字符是否相同
if (strcmp(tmpNode->content, content) != 0) {
isFound = false;
break;
}
tmpNode = tmpNode->next;
}
if (isFound) {
// 首先删除原字符串
Node* beforeNode = curNode->prev;
while (beforeNode->next != tmpNode) {
Node* node = beforeNode->next;
beforeNode->next = node->next;
node->next->prev = beforeNode;
free(node);
}
curNode = tmpNode;
// 添加替换字符串
appendString(&beforeNode, dstText, false);
}
else {
curNode = curNode->next;
}
}
}
Editor.h:是 Editor.cpp 的头文件,声明了文本编辑器相关的函数接口,确保其他文件能够调用 Editor.cpp 中定义的函数。
声明了文本编辑器相关的函数,如:
-
initTextEditor()
:初始化编辑器。 -
runTextEditor()
:运行编辑器的主循环。 -
destroyTextEditor()
:销毁编辑器。
cpp
#pragma once
/*
该模块用于显示文本编辑器的界面和用户交互
*/
// 初始化文本编辑器
void initTextEditor();
// 运行文本编辑器
void runTextEditor();
// 销毁文本编辑器
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()
函数,查找指定的原字符串并将其替换为新字符串。
- 替换字符串。通过
cpp
#include "Editor.h"
#include <graphics.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>
#include <math.h>
#include "Text.h"
// 窗口大小
static int WINDOW_WIDTH = 1000;
static int WINDOW_HEIGHT = 700;
// 设置每帧的时间
static double FPS = 30;
static double PER_FRAME_TIME = 1000.0 / FPS;
// 查找字符串
static char searchText[256] = {0};
// 原字符串
static char sourceText[256] = { 0 };
// 替换字符串
static char replaceText[256] = { 0 };
// 设置菜单区域的位置
static int MENU_LEFT_TOP[] = { 10, 80 };
static int MENU_RIGHT_BOTTOM[] = { 900, 220 };
static int PADDING[] = {50, 16};
// 读入文件菜单位置
static int READ_FILE_MENU[] = { MENU_LEFT_TOP[0] + PADDING[0], MENU_LEFT_TOP[1] + PADDING[1],
MENU_LEFT_TOP[0] + PADDING[0] + 104, MENU_LEFT_TOP[1] + PADDING[1] + 25 };
// 写入文件菜单位置
static int WRITE_FILE_MENU[] = { READ_FILE_MENU[2] + PADDING[0], MENU_LEFT_TOP[1] + PADDING[1],
READ_FILE_MENU[2] + PADDING[0] + 104, MENU_LEFT_TOP[1] + PADDING[1] + 25 };
// 新建文件菜单位置
static int CREATE_FILE_MENU[] = { WRITE_FILE_MENU[2] + PADDING[0], MENU_LEFT_TOP[1] + PADDING[1],
WRITE_FILE_MENU[2] + PADDING[0] + 104, MENU_LEFT_TOP[1] + PADDING[1] + 25 };
// 保存文件菜单位置
static int SAVE_FILE_MENU[] = { CREATE_FILE_MENU[2] + PADDING[0], MENU_LEFT_TOP[1] + PADDING[1],
CREATE_FILE_MENU[2] + PADDING[0] + 104, MENU_LEFT_TOP[1] + PADDING[1] + 25 };
// 退出菜单位置
static int EXIT_MENU[] = { SAVE_FILE_MENU[2] + PADDING[0], MENU_LEFT_TOP[1] + PADDING[1],
SAVE_FILE_MENU[2] + PADDING[0] + 52, MENU_LEFT_TOP[1] + PADDING[1] + 25 };
// 编辑文件菜单位置
static int EDIT_FILE_MENU[] = { MENU_LEFT_TOP[0] + PADDING[0], READ_FILE_MENU[3] + PADDING[1],
MENU_LEFT_TOP[0] + PADDING[0] + 104, READ_FILE_MENU[3] + PADDING[1] + 25 };
// 插入菜单位置
static int INSERT_TEXT_MENU[] = { MENU_LEFT_TOP[0] + PADDING[0], EDIT_FILE_MENU[3] + PADDING[1],
MENU_LEFT_TOP[0] + PADDING[0] + 104, EDIT_FILE_MENU[3] + PADDING[1] + 25 };
// 查找文本位置
static int SEARCH_TEXT[] = { EDIT_FILE_MENU[2] + PADDING[0], READ_FILE_MENU[3] + PADDING[1],
EDIT_FILE_MENU[2] + PADDING[0] + 208, READ_FILE_MENU[3] + PADDING[1] + 25 };
// 查找菜单位置
static int FIND_MENU[] = { SEARCH_TEXT[2] + PADDING[0], READ_FILE_MENU[3] + PADDING[1],
SEARCH_TEXT[2] + PADDING[0] + 52, READ_FILE_MENU[3] + PADDING[1] + 25 };
// 清除高亮菜单位置
static int CLEAR_MENU[] = { FIND_MENU[2] + PADDING[0], READ_FILE_MENU[3] + PADDING[1],
FIND_MENU[2] + PADDING[0] + 104, READ_FILE_MENU[3] + PADDING[1] + 25 };
// 原文本位置
static int SOURCE_TEXT[] = { EDIT_FILE_MENU[2] + PADDING[0], FIND_MENU[3] + PADDING[1],
EDIT_FILE_MENU[2] + PADDING[0] + 208, FIND_MENU[3] + PADDING[1] + 25 };
// 替换文本位置
static int REPLACE_TEXT[] = { SOURCE_TEXT[2] + PADDING[0], FIND_MENU[3] + PADDING[1],
SOURCE_TEXT[2] + PADDING[0] + 208, FIND_MENU[3] + PADDING[1] + 25 };
// 替换菜单位置
static int REPLACE_MENU[] = { REPLACE_TEXT[2] + PADDING[0], FIND_MENU[3] + PADDING[1],
REPLACE_TEXT[2] + PADDING[0] + 52, FIND_MENU[3] + PADDING[1] + 25 };
// 文本区域位置
static int TEXT_AREA[] = { 10, MENU_RIGHT_BOTTOM[1] + PADDING[1],
WINDOW_WIDTH-20, WINDOW_HEIGHT - 20 };
// 图片资源
static IMAGE editorImage;
// 读取图片资源
static void readResources();
// 绘制窗口
static void drawWindow();
// 绘制菜单区域
static void drawMenu();
// 绘制文本区域
static void drawText();
// 读入文件
static void ReadFile();
// 写入文件
static void WriteFile();
// 新建文件
static void CreateNewFile();
// 保存文件
static void SaveFile();
// 插入文字
static void InsertText();
// 查找
static void FindString();
// 清除输入
static void ClearInput();
// 替换
static void ReplaceString();
// 更新文件指针位置
static void updateCursor(int x, int y);
// 初始化文本编辑器
void initTextEditor() {
// 创建窗口
initgraph(WINDOW_WIDTH, WINDOW_HEIGHT);
setbkcolor(RGB(255, 255, 255));
// 设置窗口名称
HWND hWnd = GetHWnd();
SetWindowText(hWnd, "文本编辑器");
// 读取图片资源
readResources();
// 设置直线样式
LINESTYLE style;
style.thickness = 2;
setlinestyle(&style);
}
// 运行文本编辑器
void runTextEditor() {
bool exitCode = false;
while (!exitCode) {
int startTime = clock();
// 双缓冲
BeginBatchDraw();
cleardevice();
// 绘制窗口
drawWindow();
EndBatchDraw();
// 处理消息
static ExMessage msg;
while (peekmessage(&msg, EM_KEY | EM_MOUSE)) {
// 键盘按下事件
if (msg.message == WM_KEYDOWN) {
if (msg.vkcode == VK_BACK) {
// 删除指针指向的字符
deleteCharacter(false);
}
else if (msg.vkcode == VK_DELETE) {
// 删除指针后面的字符
deleteCharacter(true);
}
}
// 鼠标左键按下事件
else if (msg.message == WM_LBUTTONDOWN) {
int x = msg.x;
int y = msg.y;
// 点击了读入文件按钮
if (x > READ_FILE_MENU[0] && x < READ_FILE_MENU[2] &&
y > READ_FILE_MENU[1] && y < READ_FILE_MENU[3]) {
ReadFile();
}
// 点击了写入文件按钮
else if (x > WRITE_FILE_MENU[0] && x < WRITE_FILE_MENU[2] &&
y > WRITE_FILE_MENU[1] && y < WRITE_FILE_MENU[3]) {
WriteFile();
}
// 点击了创建文件按钮
else if (x > CREATE_FILE_MENU[0] && x < CREATE_FILE_MENU[2] &&
y > CREATE_FILE_MENU[1] && y < CREATE_FILE_MENU[3]) {
CreateNewFile();
}
// 点击了保存文件按钮
else if (x > SAVE_FILE_MENU[0] && x < SAVE_FILE_MENU[2] &&
y > SAVE_FILE_MENU[1] && y < SAVE_FILE_MENU[3]) {
SaveFile();
}
// 点击了退出按钮
else if (x > EXIT_MENU[0] && x < EXIT_MENU[2] &&
y > EXIT_MENU[1] && y < EXIT_MENU[3]) {
// 释放相关内存
freeResources();
exitCode = true;
break;
}
// 点击了插入文字按钮
else if (x > INSERT_TEXT_MENU[0] && x < INSERT_TEXT_MENU[2] &&
y > INSERT_TEXT_MENU[1] && y < INSERT_TEXT_MENU[3]) {
InsertText();
}
// 点击了查找按钮
else if (x > FIND_MENU[0] && x < FIND_MENU[2] &&
y > FIND_MENU[1] && y < FIND_MENU[3]) {
FindString();
}
// 点击了清楚高亮按钮
else if (x > CLEAR_MENU[0] && x < CLEAR_MENU[2] &&
y > CLEAR_MENU[1] && y < CLEAR_MENU[3]) {
ClearInput();
}
// 点击了替换按钮
else if (x > REPLACE_MENU[0] && x < REPLACE_MENU[2] &&
y > REPLACE_MENU[1] && y < REPLACE_MENU[3]) {
ReplaceString();
}
// 点击了文本区域
else if (x > TEXT_AREA[0] && x < TEXT_AREA[2] &&
y > TEXT_AREA[1] && y < TEXT_AREA[3]) {
updateCursor(x, y);
}
// 输入查找字符串
else if (x > SEARCH_TEXT[0] && x < SEARCH_TEXT[2] &&
y > SEARCH_TEXT[1] && y < SEARCH_TEXT[3]) {
InputBox(searchText, 255, "输入查找字符串:");
}
// 输入原字符串
else if (x > SOURCE_TEXT[0] && x < SOURCE_TEXT[2] &&
y > SOURCE_TEXT[1] && y < SOURCE_TEXT[3]) {
InputBox(sourceText, 255, "输入原字符串:");
}
// 输入替换字符串
else if (x > REPLACE_TEXT[0] && x < REPLACE_TEXT[2] &&
y > REPLACE_TEXT[1] && y < REPLACE_TEXT[3]) {
InputBox(replaceText, 255, "输入替换字符串:");
}
}
}
// 控制每帧时间
int duration = clock() - startTime;
if (duration < PER_FRAME_TIME) {
Sleep(PER_FRAME_TIME - duration);
}
}
}
// 销毁文本编辑器
void destroyTextEditor() {
closegraph();
}
// 读取图片资源
static void readResources() {
loadimage(&editorImage, "editor.png");
}
// 绘制窗口
static void drawWindow() {
// 绘制编辑器图片
putimage(0, 0, &editorImage);
// 绘制菜单区域
drawMenu();
// 绘制文本区域
drawText();
}
// 绘制菜单区域
static void drawMenu() {
// 设置字体
LOGFONT f;
gettextstyle(&f);
f.lfHeight = 25;
_tcscpy(f.lfFaceName, _T("黑体"));
f.lfQuality = ANTIALIASED_QUALITY;
f.lfWeight = 800;
settextstyle(&f);
settextcolor(RGB(0, 0, 0));
// 绘制文件编辑器的菜单
setlinecolor(RGB(0, 0, 0));
rectangle(MENU_LEFT_TOP[0], MENU_LEFT_TOP[1], MENU_RIGHT_BOTTOM[0], MENU_RIGHT_BOTTOM[1]);
// 读入文件菜单
outtextxy(READ_FILE_MENU[0], READ_FILE_MENU[1], "读入文件");
roundrect(READ_FILE_MENU[0], READ_FILE_MENU[1], READ_FILE_MENU[2], READ_FILE_MENU[3], 5, 5);
// 写入文件菜单
outtextxy(WRITE_FILE_MENU[0], WRITE_FILE_MENU[1], "写入文件");
roundrect(WRITE_FILE_MENU[0], WRITE_FILE_MENU[1], WRITE_FILE_MENU[2], WRITE_FILE_MENU[3], 5, 5);
// 新建文件菜单
outtextxy(CREATE_FILE_MENU[0], CREATE_FILE_MENU[1], "新建文件");
roundrect(CREATE_FILE_MENU[0], CREATE_FILE_MENU[1], CREATE_FILE_MENU[2], CREATE_FILE_MENU[3], 5, 5);
// 保存文件菜单
outtextxy(SAVE_FILE_MENU[0], SAVE_FILE_MENU[1], "保存文件");
roundrect(SAVE_FILE_MENU[0], SAVE_FILE_MENU[1], SAVE_FILE_MENU[2], SAVE_FILE_MENU[3], 5, 5);
// 退出菜单
outtextxy(EXIT_MENU[0], EXIT_MENU[1], "退出");
roundrect(EXIT_MENU[0], EXIT_MENU[1], EXIT_MENU[2], EXIT_MENU[3], 5, 5);
// 编辑文件菜单
outtextxy(EDIT_FILE_MENU[0], EDIT_FILE_MENU[1], "编辑文件");
// 插入菜单
outtextxy(INSERT_TEXT_MENU[0], INSERT_TEXT_MENU[1], "插入文字");
roundrect(INSERT_TEXT_MENU[0], INSERT_TEXT_MENU[1], INSERT_TEXT_MENU[2], INSERT_TEXT_MENU[3], 5, 5);
// 查找菜单
outtextxy(FIND_MENU[0], FIND_MENU[1], "查找");
roundrect(FIND_MENU[0], FIND_MENU[1], FIND_MENU[2], FIND_MENU[3], 5, 5);
// 清除输入菜单
outtextxy(CLEAR_MENU[0], CLEAR_MENU[1], "清除输入");
roundrect(CLEAR_MENU[0], CLEAR_MENU[1], CLEAR_MENU[2], CLEAR_MENU[3], 5, 5);
// 替换菜单
outtextxy(REPLACE_MENU[0], REPLACE_MENU[1], "替换");
roundrect(REPLACE_MENU[0], REPLACE_MENU[1], REPLACE_MENU[2], REPLACE_MENU[3], 5, 5);
// 设置字体
gettextstyle(&f);
f.lfHeight = 18;
_tcscpy(f.lfFaceName, _T("宋体"));
f.lfQuality = ANTIALIASED_QUALITY;
f.lfWeight = 800;
settextstyle(&f);
settextcolor(RGB(0, 0, 0));
// 查找文本
if (strlen(searchText) > 0) {
outtextxy(SEARCH_TEXT[0], SEARCH_TEXT[1]+3, searchText);
}
roundrect(SEARCH_TEXT[0], SEARCH_TEXT[1], SEARCH_TEXT[2], SEARCH_TEXT[3], 5, 5);
// 原文本
if (strlen(sourceText) > 0) {
outtextxy(SOURCE_TEXT[0], SOURCE_TEXT[1] + 3, sourceText);
}
roundrect(SOURCE_TEXT[0], SOURCE_TEXT[1], SOURCE_TEXT[2], SOURCE_TEXT[3], 5, 5);
// 替换文本
if (strlen(replaceText) > 0) {
outtextxy(REPLACE_TEXT[0], REPLACE_TEXT[1] + 3, replaceText);
}
roundrect(REPLACE_TEXT[0], REPLACE_TEXT[1], REPLACE_TEXT[2], REPLACE_TEXT[3], 5, 5);
}
// 绘制文本区域
static void drawText() {
// 设置字体
LOGFONT f;
gettextstyle(&f);
f.lfHeight = 20;
f.lfWeight = 600;
_tcscpy(f.lfFaceName, _T("宋体"));
f.lfQuality = ANTIALIASED_QUALITY;
settextstyle(&f);
settextcolor(RGB(0, 0, 0));
// 显示文本区域框
rectangle(TEXT_AREA[0], TEXT_AREA[1], TEXT_AREA[2], TEXT_AREA[3]);
// 显示文件内容
File* file = getCurrentFile();
if (!file) return;
int leftX = TEXT_AREA[0] + 5;
int x = leftX;
int y = TEXT_AREA[1] + 5;
int w = textwidth("a");
int h = f.lfHeight;
Node* node = file->text->head->next;
// 设置头指针的位置
file->text->head->rect[0] = TEXT_AREA[0]+4;
file->text->head->rect[1] = y;
file->text->head->rect[2] = TEXT_AREA[0]+4;
file->text->head->rect[3] = y;
// 如果文件是空的,则在开头显示指针
if (node == file->text->tail) {
line(node->prev->rect[2], node->prev->rect[1], node->prev->rect[2], node->prev->rect[1] + h);
return;
}
while (node != file->text->tail) {
// 设置字符所占的区域
node->rect[0] = x;
node->rect[1] = y;
node->rect[2] = x + (node->normal ? w : w*2);
node->rect[3] = y + h;
// 判断是否需要换行
if (strcmp(node->content, "\r\n") == 0 || strcmp(node->content, "\n") == 0
|| node->rect[2] >= TEXT_AREA[2]) {
// 需要换行,更新位置
x = leftX;
y += f.lfHeight;
node->rect[0] = x;
node->rect[1] = y;
node->rect[2] = x + (node->normal ? w : w * 2);
node->rect[3] = y + h;
}
if (strcmp(node->content, "\r\n") != 0 && strcmp(node->content, "\n") != 0) {
// 如果字符被选中,则更改颜色
if (node->selected) {
setcolor(RED);
}
else {
setcolor(BLACK);
}
// 显示该字符
outtextxy(node->rect[0], node->rect[1], node->content);
// 更新x值
x = node->rect[2];
}
// 绘制当前位置指针
if (file->text->cursor == node->prev) {
line(node->prev->rect[2], node->prev->rect[1], node->prev->rect[2], node->prev->rect[1] + h);
}
else if (file->text->cursor == node && node->next == file->text->tail) {
line(node->rect[2], node->rect[1], node->rect[2], node->rect[1] + h);
}
node = node->next;
}
}
// 更新文件指针位置
static void updateCursor(int x, int y) {
File* file = getCurrentFile();
if (!file) return;
// 设置文件指针到最靠近鼠标的文字的位置(距离不能超过26)
int minDistance = INT_MAX;
Node* node = file->text->head->next;
while (node != file->text->tail) {
if (x > node->rect[0] && x < node->rect[2] &&
y > node->rect[1] && y < node->rect[3]) {
file->text->cursor = node;
break;
}
else {
// 判断该文字是否更加靠近鼠标点击的位置
int dx = (node->rect[0] + node->rect[2]) / 2 - x;
int dy = (node->rect[1] + node->rect[3]) / 2 - y;
double dist = sqrt(dx * dx + dy * dy);
if (dist < 26 && dist < minDistance) {
minDistance = dist;
file->text->cursor = node;
}
}
node = node->next;
}
}
// 读入文件
static void ReadFile() {
// 提示用户输入文件路径
char path[256];
InputBox(path, 255, "输入文件路径:");
// 读入文件内容
if (!readFile(path)) {
MessageBox(GetHWnd(), "该文件不存在", "提示", MB_OK);
}
}
// 写入文件
static void WriteFile() {
if (getCurrentFile()) {
writeFile();
MessageBox(GetHWnd(), "内容已被写入文件", "提示", MB_OK);
}
}
// 新建文件
static void CreateNewFile() {
// 提示用户输入文件路径
char path[256];
InputBox(path, 255, "输入文件路径:");
// 创建新的文件
if (!createFile(path)) {
MessageBox(GetHWnd(), "创建文件失败", "提示", MB_OK);
}
}
// 保存文件
static void SaveFile() {
// 提示用户输入文件路径
char path[256];
InputBox(path, 255, "输入文件路径:");
if (!saveFile(path)) {
MessageBox(GetHWnd(), "保存文件失败", "提示", MB_OK);
}
else {
MessageBox(GetHWnd(), "文件已被保存", "提示", MB_OK);
}
}
// 插入文字
static void InsertText() {
// 提示输入要插入的文字
char content[256];
InputBox(content, 255, "输入要插入的文字:");
// 把该文字插入指针所在位置
insertText(content);
}
// 查找
static void FindString() {
resetSelected();
if (strlen(searchText) > 0) {
findString(searchText);
}
}
// 清除输入
static void ClearInput() {
memset(searchText, 0, sizeof(searchText));
memset(sourceText, 0, sizeof(sourceText));
memset(replaceText, 0, sizeof(replaceText));
// 重置选中标志
resetSelected();
}
// 替换
static void ReplaceString() {
if (strlen(sourceText) > 0 && strlen(replaceText) > 0) {
replaceString(sourceText, replaceText);
}
}
Main.cpp:程序的入口文件,主要用于启动文本编辑器的初始化、运行和销毁。
main()
:
-
程序启动时首先调用
initTextEditor()
函数初始化文本编辑器。 -
接着调用
runTextEditor()
启动文本编辑器的主循环,允许用户进行各种操作(如文件操作、文本编辑等)。 -
最后通过
destroyTextEditor()
销毁编辑器,释放资源。
cpp
#include "Editor.h"
int main() {
// 初始化文本编辑器
initTextEditor();
// 运行文本编辑器
runTextEditor();
// 销毁文本编辑器
destroyTextEditor();
return 0;
}