当前位置: 首页 > news >正文

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

一、软件安装

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() 等。

#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()

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

#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():销毁编辑器。

#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() 函数,查找指定的原字符串并将其替换为新字符串。

#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() 销毁编辑器,释放资源。

#include "Editor.h"int main() {// 初始化文本编辑器initTextEditor();// 运行文本编辑器runTextEditor();// 销毁文本编辑器destroyTextEditor();return 0;
}

相关文章:

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

一、软件安装 Visual Studio 2022 Visual Studio 2022 是微软提供的强大集成开发环境&#xff08;IDE&#xff09;&#xff0c;广泛用于C/C、C#、Python等多种编程语言的开发。它提供了许多强大的工具&#xff0c;帮助开发者编写、调试和优化代码。 1.下载 Visual Studio 202…...

学习海康VisionMaster之路径提取

一&#xff1a;进一步学习了 今天学习下VisionMaster中的路径提取&#xff1a;可在绘制的路径上等间隔取点或查找边缘点 二&#xff1a;开始学习 1&#xff1a;什么是路径提取&#xff1f; 相当于事先指定一段路径&#xff0c;然后在对应的路径上查找边缘&#xff0c;这个也是…...

【MCP Node.js SDK 全栈进阶指南】中级篇(6):MCP与Web框架集成

背景 在现代Web开发生态中,框架已成为构建高效、可维护应用的核心基础设施。将MCP TypeScript-SDK与流行的Web框架集成,能够充分发挥两者的优势,构建功能丰富、交互智能的现代应用。本文将深入探讨MCP与主流Web框架的集成方法、最佳实践和架构设计,帮助开发者构建强大而灵…...

vue3+vite 项目中使用 Echarts 5.0 按需引入教程

效果图 第一步&#xff0c;封装 ECharts 工具函数 在 utils 目录下新建一个 echarts.js 文件&#xff0c;位置随意这里只引入了 折线图和拼团&#xff0c;需要其他的图自行引入 import * as echarts from "echarts/core"; import { LineChart, PieChart } from "…...

Unreal Engine 实现软件测试方案的仿真体验

以下将以一款模拟物流仓储管理软件的测试为例&#xff0c;详细阐述如何利用 Unreal Engine 实现软件测试方案的仿真体验。 1. 明确测试目标与需求 功能方面&#xff1a;要验证货物出入库管理、库存盘点、货物定位、叉车调度等功能的准确性和稳定性。性能方面&#xff1a;测试…...

蓝绿部署的详细规划文档

一、蓝绿部署概述 蓝绿部署是一种通过运行两套完全相同的生产环境(蓝色和绿色)实现零停机发布的策略。核心流程为:在绿色环境部署新版本并验证通过后,将流量逐步切换至绿色环境,若出现问题可快速回滚至蓝色环境。该策略适用于对可用性要求极高的系统(如金融、电商),可…...

【SpringMVC】概念引入与连接

目录 1.前言 2.正文 2.1SpringMVC是什么 2.2详解RequestMapping注解 2.3创建Spring项目 2.4建立连接 2.5Postman 3.小结 1.前言 哈喽大家好&#xff0c;今天来给大家带来Spring相关的学习&#xff0c;主要内容有概念的讲解以及如何分别通过Java代码和工具Postman来建立…...

NodeJs模块化与JavaScript的包管理工具

Js&#xff1a;模块化规范的文章链接&#xff1a;https://blog.csdn.net/Y1914960928/article/details/131793004?spm1011.2415.3001.5331 一、模块化&#xff1a; 1、导入文件的注意事项&#xff1a; ① 导入路径建议写 相对路径&#xff0c;且不能省略 ./ 和 ../ ② 文件…...

一、接口测试01

目录 一、接口1. 概念2. 接口的类型 二、接口测试1. 概念 三、HTTP协议1. HTTP协议简介2. URL格式2.1 练习 3. HTTP请求3.1 整体格式3.2 fiddler 抓包验证3.3 请求行3.4 请求头3.5 请求体3.6 练习 4. HTTP响应4.1 整体格式4.2 状态行4.3 响应头4.4 响应体4.5 练习 5. 传统风格接…...

CISA、项目管理、信息系统项目等等电子书资料

概述 在数字化转型浪潮中&#xff0c;教育工作者与技术管理者如何把握前沿趋势&#xff1f;我们精选了覆盖教育研究、IT治理与项目管理的系列电子资源&#xff0c;为职场精英打造知识升级方案。资料已整理好&#xff1a;https://pan.quark.cn/s/9c8a32efc89e 内容介绍 包含教…...

神经网络(自己记录)

一、神经网络基础 5分钟-通俗易懂 - 神经网络 反向传播算法&#xff08;手算&#xff09;_哔哩哔哩_bilibili 二、GAT...

ARCGIS PRO 在地图中飞行

一、要将飞行添加到地图&#xff0c;请确保动画选项卡已处于打开状态。 如有必要&#xff0c;请单击视图选项卡上动画组中的添加动画 &#xff0c;如图&#xff1a; 二、在动画选项卡的创建组中&#xff0c;单击追加下拉菜单并验证过渡类型是固定还是线性。 三、将照相机导航到…...

Java 消息代理:企业集成的 5 项基本技术

大家好&#xff0c;这里是架构资源栈&#xff01;点击上方关注&#xff0c;添加“星标”&#xff0c;一起学习大厂前沿架构&#xff01; Java 消息代理通过实现分布式系统之间的可靠通信路径&#xff0c;改变了企业集成。我广泛使用了这些技术&#xff0c;发现它们对于构建可有…...

SpringBoot自动装配

自动装配就是自动地把其他组件中的Bean装载到IOC容器中&#xff0c;不需要开发人员再去配置文件中添加大量的配置 源码分析 EnableAutoConfiguration&#xff1a;SpringBoot实现自动化配置的核心注解 AutoConfigurationImportSelector类分析 public class AutoConfigurationIm…...

【项目篇之垃圾回收】仿照RabbitMQ模拟实现消息队列

实现垃圾回收 消息垃圾回收为什么要去实现垃圾回收如何实现这个垃圾回收&#xff1f; 编写代码编写触发垃圾回收的条件触发垃圾回收的条件约定新文件所在的位置实现垃圾回收的算法(重点) 总结 消息垃圾回收 为什么要去实现垃圾回收 由于当前会不停地往消息文件中写入新消息&a…...

【Redis】服务端高并发分布式结构演进之路

文章目录 前景概念架构演进 现在说起服务端&#xff0c;经常听到的就是分布式、集群、微服务这类词汇&#xff0c;这些到底是什么呢&#xff1f;又是如何而来的呢&#xff1f;本篇博客记录相关学习 前景概念 在认识上述架构之前&#xff0c;需要有些前景知识 应用(Applicatio…...

【SpringMVC文件上传终极指南:从基础配置到云存储集成】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…...

windows安装docker教程

1、参考博客 - 安装教程&#xff1a; https://blog.csdn.net/GoodburghCottage/article/details/131413312 - docker详解&#xff1a; https://www.cnblogs.com/yaok430/p/16738002.html 2、设计目标 - 提供一个简单的应用程序打包工具&#xff0c;可以将应用程序…...

基于物理信息的神经网络在异常检测Anomaly Detection中的应用:实践指南

物理信息神经网络(PINNs)代表了一种令人兴奋的新建模范式,这种范式正在各行各业迅速崭露头角。 PINNs 最有前景的应用之一是复杂物理系统中的异常检测Anomaly Detection。这一应用尤其值得关注,因为它解决了传统机器学习方法在实践中一直难以克服的几个关键痛点。 在这篇…...

Spark阶段学习总结

一、Spark 是什么 Spark 是一种基于内存的快速、通用、可扩展的大数据分析计算引擎&#xff0c;也可说是分布式内存迭代计算框架。 二、Spark 四大特点 速度快&#xff08;内存计算&#xff09; 易于使用 通用性强 运行方式多 三、与hadoop的核心差异 数据通信&#xf…...

统信操作系统使用默认yum源安装 Docker 的踩坑

事件 在使用 docker 运行 es 的时候&#xff0c;es 报错 ulimit 的值为1024&#xff0c;但是服务器已经设置成了65535。 排查结果 在装完 docker 之后发现 docker systemd 的启动命令引用了 /etc/sysconfig/docker 这个文件里面设定了 ulimit 为 1024 如下&#xff1a; [ro…...

HK1RBOX K8 RK3528 Via浏览器_插件_央视频的组合验证(失败)

文章目录 前言软件和设备信息过程方案插件代码 运行效果问题 前言 实践的结果为失败,设备性能不满足, 无法流畅播放视频 软件和设备信息 via浏览器, 版本4.9.1HK1RBOX K8 RK3528设备win10, 逍遥游安卓虚拟机(开发插件)央视频官网(不是cctv那个) 过程 方案 浏览器设置央视…...

XMOS直播声卡——可支持实时音频DSP处理的低延迟音频方案

对于游戏玩家和短视频直播工作者来说&#xff0c;声卡不可或缺。它除了能将计算设备的数字信号转换为声音信号&#xff0c;还能够提供各种逼真的或者定制的3D音效&#xff0c;提升游戏的沉浸感&#xff0c;特别是在大型开放联网游戏或射击游戏中&#xff0c;声音细节直接影响玩…...

DB2备份恢复操作文档及其注意事项

备份BACKUP 备份语法&#xff1a; 在线备份&#xff1a;db2 backup db MYDB online to /tmp/backup_db2_20250326 离线备份&#xff1a;db2 backup db MYDB to /tmp/backup_db2_20250326 需要注意&#xff0c;在执行在线备份时需要开启归档&#xff0c;即执行db2 get db cfg f…...

flask uri 怎么统一加前缀

在 Flask 中为 URI 统一添加前缀&#xff0c;可以通过多种方式实现&#xff0c;下面为你详细介绍几种常见的方法。 方法一&#xff1a;使用 Blueprint&#xff08;推荐&#xff09; Blueprint&#xff08;蓝图&#xff09;是 Flask 中组织路由的一种方式&#xff0c;它可以将…...

创建一个springboot的项目-简洁步骤

1. 打开IDEA&#xff0c;新建项目&#xff1a; 2. 设置项目的基本信息&#xff0c;其中注意jdk版本要与Java版本匹配&#xff0c;这里使用jdk17和java17 3. 选择SpringBoot版本&#xff0c;选择项目依赖&#xff08;依赖也可以创建完项目后在pom文件中修改&#xff09; 这里选…...

杭电oj(1008、1012、1013、1014、1017)题解

目录 ​编辑 1008 题目 思路 代码 1012 题目 思路 代码 1013 题目 思路 代码 1014 题目 思路 代码 1017 题目 思路 处理每组测试数据 计算满足条件的整数对数量 代码 1008 题目 思路 s a[0];&#xff1a;初始化 s 为数组的第一个元素&#xff0c;即电…...

VRRP与BFD在冗余设计中的核心区别:从“备用网关”到“毫秒级故障检测”

&#xff08;本文完全由deepseek生成&#xff0c;特此声明&#xff09; 在网络冗余设计中&#xff0c;VRRP&#xff08;Virtual Router Redundancy Protocol&#xff09;和BFD&#xff08;Bidirectional Forwarding Detection&#xff09;是两种关键协议&#xff0c;但它们的定…...

蓝桥杯 2. 确定字符串是否是另一个的排列

确定字符串是否是另一个的排列 原题目链接 题目描述 实现一个算法来识别一个字符串 str2 是否是另一个字符串 str1 的排列。 排列的解释如下&#xff1a;如果将 str1 的字符拆分开&#xff0c;重新排列后再拼接起来&#xff0c;能够得到 str2&#xff0c;那么就说字符串 st…...

巧记英语四级单词 Unit6-上【晓艳老师版】

master n.雇主&#xff0c;主人 发音“骂死他”&#xff0c;骂死谁&#xff1f;雇主&#xff0c;主人masterpiece n.代表作&#xff0c;名著 主人的作品就是名著deputy n.副手 de表示往下&#xff0c;put放&#xff0c;往下放给副手appeal n.要求&#xff0c;呼吁 一再的要求剥…...

Java求职面试:从Spring Boot到微服务架构的全面解析

场景&#xff1a;互联网大厂Java面试 在某互联网大厂的面试房间里&#xff0c;面试官李老师正准备面试一位传说中的“水货程序员”——谢飞机。 第一轮提问&#xff1a;基础框架与工具 李老师&#xff1a; “谢飞机&#xff0c;你好。我们先聊聊Spring Boot吧。你能简单说说…...

来自B站AIGC科技官的“vLLM简介“视频截图

来自B站AIGC科技官的"vLLM简介"视频截图 0. 引言1. vLLM简介2. vLLM启动日志解析3. vLLM压力测试4.vLLM分布式推理 0. 引言 这篇文章主要记录了B站AIGC科技官的"vLLM简介"视频截图。 1. vLLM简介 笔记 From Up主&#xff1a; KV Cache的大小与序列长度的…...

CSS元素动画篇:基于当前位置的变换动画(四)

基于当前位置的变换动画&#xff08;四&#xff09; 前言透明效果类元素动画闪烁动画效果效果预览代码实现 淡入动画效果效果预览代码实现 淡出动画效果效果预览代码实现 结语 前言 CSS元素动画一般分为两种&#xff1a;一种是元素基于当前位置的变换动画&#xff0c;通过不明…...

如何打包一个QT 程序

如何打包一个QT 程序 找到 vcvarsall.bat 文件 打开 图中框选的命令行 输入命令 D:\MicrosoftVisualStdio2022\Community\VC\Auxiliary\Build\vcvarsall.bat x64命令行进入待打包的目录&#xff0c;只留下一个exe 文件即可 windeployqt 程序名打包完成...

【vLLM 学习】CPU 离线处理

vLLM 是一款专为大语言模型推理加速而设计的框架&#xff0c;实现了 KV 缓存内存几乎零浪费&#xff0c;解决了内存管理瓶颈问题。 更多 vLLM 中文文档及教程可访问 →https://vllm.hyper.ai/ 源代码&#xff1a;vllm-project/vllm from vllm import LLM, SamplingParams# S…...

德州仪器(TI)—TDA4VM芯片详解—目录

写在前面 本系列文章主要讲解德州仪器&#xff08;TI&#xff09;TDA4VM芯片的相关知识&#xff0c;希望能帮助更多的同学认识和了解德州仪器&#xff08;TI&#xff09;TDA4VM芯片。 若有相关问题&#xff0c;欢迎评论沟通&#xff0c;共同进步。(*^▽^*) 本篇是此系列的目录…...

深入解读:2025 数字化转型管理 参考架构

《GB/T 45341—2025 数字化转型管理 参考架构》规定了数字化转型参考架构&#xff0c;涵盖主要视角、过程方法、发展阶段与水平档次。主要视角包含发展战略、业务创新转型等 5 个方面&#xff0c;明确任务及关联&#xff1b; 过程方法基于 “策划 — 支持、实施与运行 — 评测 …...

dma_buf学习记录之二核心接口

dma_buf学习记录之一基础知识-CSDN博客 本章学习linux\include\linux\dma-buf.h dma-buf.h 是 Linux 内核中用于实现 DMA 缓冲区共享框架的核心头文件。它定义了 dma-buf 子系统的主要数据结构和操作接口&#xff0c;允许设备驱动程序之间共享缓冲区&#xff0c;并支持异步硬件…...

java Optional

我还没用过java8的一些语法&#xff0c;有点老古董了&#xff0c;记录下Optional怎么用。 从源码看&#xff0c;Optional内部持有一个对象&#xff0c; 有一些api对这个对象进行判空处理。 静态方法of &#xff0c;生成Optional对象&#xff0c; 但这个value不能为空&#…...

一文说清Token这个大模型中的数字乐高积木的作用

第一章&#xff1a;语言解码的底层逻辑 1.1 人类大脑的"偷懒智慧" 想象你走在街头&#xff0c;突然看到"星巴克"的招牌。你的大脑不会逐个分析"星""巴""克"三个字的笔画&#xff0c;而是瞬间将其识别为一个整体。这种将高…...

界面打印和重定向同时实现

在 Shell 中&#xff0c;若要让程序运行时既在界面打印输出内容&#xff0c;又将其重定向到文件&#xff0c;可使用tee命令达成此目的。tee命令的作用是从标准输入读取数据&#xff0c;然后将这些数据同时输出到标准输出&#xff08;也就是屏幕&#xff09;和指定的文件中。 基…...

最佳实践-HENGSHI SENSE 可视化创作中如何引入数据集市的成果

HENGSHI SENSE 提供了 中心化的数据集市管理 &#xff0c;即数据集市的功能&#xff1a; 数据集市&#xff0c;支持层级结构的数据集市建立&#xff0c;按用户&#xff0c;用户组&#xff0c;组织架构授权&#xff0c;将数据分配到合适的人。支持统一的计算字段&#xff0c;计算…...

YOLO旋转检测模型简化

YOLO模型作为单阶段目标检测方法的代表&#xff0c;其已经应用在多个领域。 但要想将其部署到单片机上&#xff0c;其模型的大小需要受到极大的限制&#xff0c;而采用剪枝的方式模型体积下降效果有限&#xff0c;因此我们直接修改网络结构&#xff0c;将其进行删减&#xff0c…...

JavaScript之Webpack的模块加载机制

目录 目标 概述 IIFE语法分析 无参数的IIFE 有参数的IIFE Webpack语法分析 基本结构 缓存加载过的模块 ES5的格式 ES6的格式 目标 本文站在js逆向的角度总结知识&#xff0c;所以不讲解Webpack打包技术&#xff0c;只分析模块加载机制。 概述 Webpack Webpack是一个…...

深度解析如何将图像帧和音频片段特征高效存储到向量数据库 Milvus

在视频和音频分析领域&#xff0c;如何高效地处理和检索海量的多模态数据一直是一个重大挑战。本文将深度解析一种行之有效的解决方案&#xff1a;利用 OpenCV 和音频处理库提取数据特征后&#xff0c;将这些特征向量存储到 Milvus 向量数据库&#xff0c;以实现高效的相似性检…...

《Vue3学习手记6》

组件通信 props props 可以父传子&#xff0c;也可以子传父 1.父传子 子组件&#xff1a; <template><div class"child"><h2>子组件</h2><h3>礼物&#xff1a;{{ gift }}</h3><h3 v-show"zichan">父亲给我的…...

抗体品牌推荐

默克超级英雄抗体的披荆斩棘之路 自保罗埃尔利希1891年10月提出“Antikrper”一词后&#xff0c;科研人逐渐意识到抗体&#xff08;Antibody&#xff09;可以应用于各种类型的研究中。 从结构、功能、人体免疫应答……到基因治疗、药物研究&#xff0c;抗体的身影无处不在。值…...

生成式人工智能认证(GAI认证)有什么用?

在人工智能的浪潮中,我们正站在一个前所未有的十字路口。有人将生成式人工智能(Generative AI)视为技术迭代的工具,有人将其视为颠覆行业的“黑匣子”,而更少有人意识到:它正在重新定义人类与技术的共生关系。当AI不再局限于辅助人类,而是开始参与创作、决策甚至伦理判断…...

全新升级:BRAV-7601-T003高性能无风扇AI边缘计算系统,助力智能未来!

在数字化与智能化飞速发展的今天&#xff0c;AI边缘计算正成为各行各业的核心驱动力。BRAV-7601作为一款高性能无风扇AI边缘计算系统&#xff0c;凭借其强大的硬件配置与丰富的扩展能力&#xff0c;为车路协同、特种车辆车载、机器视觉、医疗影像等领域提供了卓越的解决方案。最…...

基于c++的LCA倍增法实现

原理就不写了&#xff0c;自己找b站视频学习 #include <iostream> #include <vector> #include <cmath> #include <algorithm> using namespace std; const int MAXN 100005; // 最大节点数 const int MAXLOG 20; // 最大对数深度 vector<…...