add TextArea class

This commit is contained in:
梦凌汐 2024-12-06 14:20:39 +08:00
parent ca4d37ce3b
commit e432c9c95d
6 changed files with 208 additions and 94 deletions

View File

@ -51,7 +51,8 @@
"text_encoding": "cpp", "text_encoding": "cpp",
"typeinfo": "cpp", "typeinfo": "cpp",
"variant": "cpp", "variant": "cpp",
"cassert": "cpp" "cassert": "cpp",
"cstdarg": "cpp"
}, },
"Codegeex.RepoIndex": true "Codegeex.RepoIndex": true
} }

4
.vscode/tasks.json vendored
View File

@ -3,7 +3,7 @@
{ {
"type": "cppbuild", "type": "cppbuild",
"label": "C/C++: g++.exe 生成活动文件", "label": "C/C++: g++.exe 生成活动文件",
"command": "c:\\mingw64\\bin\\g++.exe", "command": "e:\\mingw64\\bin\\g++.exe",
"args": [ "args": [
"-fdiagnostics-color=always", "-fdiagnostics-color=always",
"-g", "-g",
@ -12,7 +12,7 @@
"${fileDirname}\\${fileBasenameNoExtension}.exe" "${fileDirname}\\${fileBasenameNoExtension}.exe"
], ],
"options": { "options": {
"cwd": "c:\\mingw64\\bin" "cwd": "e:\\mingw64\\bin"
}, },
"problemMatcher": [ "problemMatcher": [
"$gcc" "$gcc"

View File

@ -4,17 +4,21 @@
#include "BaseComponent.h" #include "BaseComponent.h"
#include <windows.h> #include <windows.h>
#include <vector> #include <vector>
#include <conio.h>
#include "../utils/RichText.h" #include "../utils/RichText.h"
class TextArea : public BaseComponent { class TextArea : public BaseComponent {
private: private:
RichText text; RichText text;
int viewLeft = 0, viewTop = 0; // 视图左上角坐标 int viewLeft = 0, viewTop = 0;
std::vector<RichText> lines;
int maxLineWidth = 0;
RichText title;
int findnth(std::string str, std::string target, int n){ int findnth(std::string str, std::string target, int n){
if(n == 0) return -1; if(n == 0) return -1;
int count = 0; int count = 0;
unsigned int begin=0; size_t begin = 0;
while((begin = str.find(target, begin)) != std::string::npos){ while((begin = str.find(target, begin)) != std::string::npos){
count++; count++;
begin += target.length(); begin += target.length();
@ -27,106 +31,154 @@ private:
public: public:
TextArea(int top, int left, int width, int height) : BaseComponent(top, left, width, height){
text = RichText();
}
TextArea(int top, int left, int width, int height, const RichText& text) : BaseComponent(top, left, width, height){
this->text = text;
}
~TextArea() override {}
void setText(const RichText& text) { void setText(const RichText& text) {
this->text = text; this->text = text;
lines.clear();
RichText line;
maxLineWidth = 0;
for(auto part : text.getParts()) {
if(part.text.find('\n') == std::string::npos) {
line += part;
// printf("Add: %s\n", part.text.c_str());
} else {
size_t begin = 0;
while((begin = part.text.find('\n', begin)) != std::string::npos) {
line += StringPart(part.text.substr(0, begin), part.color);
// printf("Add: %s\n", part.text.substr(0, begin).c_str());
lines.push_back(line);
if(maxLineWidth < line.length()) {
maxLineWidth = line.length();
}
// printf("Push: %s\n", line.plainText().c_str());
line = RichText();
part.text = part.text.substr(begin + 1);
// printf("Rest: %s\n", part.text.c_str());
}
line += part;
// printf("Add: %s\n", part.text.c_str());
}
}
if(line.length() > 0) {
lines.push_back(line);
if(maxLineWidth < line.length()) {
maxLineWidth = line.length();
}
}
} }
RichText getText() { RichText getText() {
return text; return text;
} }
TextArea(int top, int left, int width, int height) : BaseComponent(top, left, width, height){
setText(RichText());
}
TextArea(int top, int left, int width, int height, const RichText& text) : BaseComponent(top, left, width, height){
setText(text);
}
~TextArea() override {}
void draw() override { void draw() override {
//使用渲染边框,超出屏幕边缘的区域不渲染
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
//获得缓冲区信息 //获得缓冲区信息
CONSOLE_SCREEN_BUFFER_INFO csbi; CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hConsole, &csbi); GetConsoleScreenBufferInfo(hConsole, &csbi);
//绘制边框到缓冲区 //清空区域
for(int i = 0; i < height && top + i < csbi.dwSize.Y; i++) { for(int i = 0; i < height && top + i < csbi.dwSize.Y; i++) {
for(int j = 0; j < width && left + j < csbi.dwSize.X; j++) {
SetConsoleCursorPosition(hConsole, {static_cast<short>(left + j), static_cast<short>(top + i)});
printf(" ");
}
}
//绘制边框到缓冲区
for(int i = 1; i < height - 1 && top + i < csbi.dwSize.Y - 1; i++) {
if(left >= 0) { if(left >= 0) {
SetConsoleCursorPosition(hConsole, {static_cast<short>(left - 1), static_cast<short>(top + i - 1)}); SetConsoleCursorPosition(hConsole, {static_cast<short>(left - 1), static_cast<short>(top + i - 1)});
printf("|"); putchar('|');
} }
if(left + width - 1 < csbi.dwSize.X) { if(left + width - 1 < csbi.dwSize.X) {
SetConsoleCursorPosition(hConsole, {static_cast<short>(left + width - 2), static_cast<short>(top + i - 1)}); SetConsoleCursorPosition(hConsole, {static_cast<short>(left + width - 2), static_cast<short>(top + i - 1)});
printf("|"); putchar('|');
} }
} }
for(int i = 0; i < width && left + i < csbi.dwSize.X; i++) { for(int i = 0; i < width && left + i < csbi.dwSize.X; i++) {
if(top >= 0) { if(top >= 0) {
SetConsoleCursorPosition(hConsole, {static_cast<short>(left + i - 1), static_cast<short>(top - 1)}); SetConsoleCursorPosition(hConsole, {static_cast<short>(left + i - 1), static_cast<short>(top - 1)});
printf("-"); putchar('-');
} }
if(top + height - 1 < csbi.dwSize.Y) { if(top + height - 1 < csbi.dwSize.Y) {
SetConsoleCursorPosition(hConsole, {static_cast<short>(left + i - 1), static_cast<short>(top + height - 2)}); SetConsoleCursorPosition(hConsole, {static_cast<short>(left + i - 1), static_cast<short>(top + height - 2)});
printf("-"); putchar('-');
} }
} }
//绘制文本到缓冲区,保证不超出边框
// int textWidth = 0, i = 0;
// while(textWidth <= width - 2 && left + textWidth + 2 < csbi.dwSize.X && i < text.size()) {
// auto part = text.getParts()[i];
// SetConsoleCursorPosition(hConsole, {static_cast<short>(left + textWidth), static_cast<short>(top)});
// SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(getBackColor(part.color)) | FrontColorToWinColor(getFrontColor(part.color)));
// if(left + textWidth + part.text.length() + 2 < csbi.dwSize.X && textWidth + part.text.length() <= width - 2) {
// printf("%s", part.text.c_str());
// } else {
// printf("%s", part.text.substr(0, std::min(csbi.dwSize.X - left - textWidth - 2, width - 2 - textWidth)).c_str());
// }
// textWidth += text.getParts()[i].text.length();
// i++;
// }
// 根据换行预处理文本 //绘制标题
std::vector<RichText> lines; SetConsoleCursorPosition(hConsole, {static_cast<short>(left + 1), static_cast<short>(top - 1)});
RichText line; for(auto part : title.getParts()) {
for(auto part : text.getParts()) { SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(getBackColor(part.color)) | FrontColorToWinColor(getFrontColor(part.color)));
if(part.text.find('\n') == std::string::npos) { printf("%s", part.text.c_str());
line += part;
} else {
unsigned int begin = 0;
while((begin = part.text.find('\n', begin)) != std::string::npos) {
line += StringPart(part.text.substr(0, begin), part.color);
lines.push_back(line);
line = RichText();
part.text = part.text.substr(begin + 1);
}
line += part;
}
} }
for(int i = viewTop; i < viewTop + height - 2 && i < lines.size(); i++) { for(int i = viewTop; i < viewTop + height - 2 && i < lines.size(); i++) {
line = lines[i]; RichText drawTarget = lines[i].substr(viewLeft, std::min(width - 2, csbi.dwSize.X - left - 2));
RichText drawTarget = line.substr(viewLeft, width - 2); SetConsoleCursorPosition(hConsole, {static_cast<short>(left), static_cast<short>(top + i - viewTop)});
int textWidth = 0, ite = 0; for(auto part : drawTarget.getParts()) {
while(textWidth <= width - 2 && left + textWidth + 2 < csbi.dwSize.X && ite < text.size()) {
auto part = line.getParts()[i];
SetConsoleCursorPosition(hConsole, {static_cast<short>(left + textWidth), static_cast<short>(top)});
SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(getBackColor(part.color)) | FrontColorToWinColor(getFrontColor(part.color))); SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(getBackColor(part.color)) | FrontColorToWinColor(getFrontColor(part.color)));
if(left + textWidth + part.text.length() + 2 < csbi.dwSize.X && textWidth + part.text.length() <= width - 2) {
printf("%s", part.text.c_str()); printf("%s", part.text.c_str());
} else {
printf("%s", part.text.substr(0, std::min(csbi.dwSize.X - left - textWidth - 2, width - 2 - textWidth)).c_str());
}
textWidth += part.text.length();
ite++;
} }
} }
SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(COLOR_BLACK) | FrontColorToWinColor(COLOR_WHITE)); SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(COLOR_BLACK) | FrontColorToWinColor(COLOR_WHITE));
} }
void setViewTop(int top) {
this->viewTop = top;
}
int getViewTop() {
return this->viewTop;
}
void setViewLeft(int left) {
this->viewLeft = left;
}
int getViewLeft() {
return this->viewLeft;
}
void moveLeft() {
if(viewLeft > 0) {
viewLeft--;
}
}
void moveRight() {
if(viewLeft < maxLineWidth - width + 2) {
viewLeft++;
}
}
void moveUp() {
if(viewTop > 0) {
viewTop--;
}
}
void moveDown() {
if(viewTop < lines.size() - height + 2) {
viewTop++;
}
}
void onKeyPress(int key) override { void onKeyPress(int key) override {
//不处理按键 //不处理按键
} }
void setTitle(const RichText& title) {
this->title = title;
}
}; };
#endif #endif

View File

@ -1,23 +1,79 @@
#include "BaseComponent.h" #include "BaseComponent.h"
#include "TextArea.h" #include "TextArea.h"
#include "../utils/RichText.h" #include "../utils/RichText.h"
#include <conio.h>
int main() { int main() {
RichText richText; RichText richText;
richText = "Hello, World"; richText = "Hello, World";
richText += StringPart(" with colors!", COLOR_RED); richText += StringPart(" with colors!\n", COLOR_RED);
richText += " And more text."; richText += "And more text.\n";
richText += StringPart("And more more more text.", COLOR_GREEN); richText += StringPart("And more more more text.", COLOR_GREEN);
richText += " And more more more more more text."; richText += " And more more more more more text.\n";
richText += StringPart("And more more more more more more text.", COLOR_BLUE); richText += StringPart("And more more more more more more text.", COLOR_BLUE);
richText += " And more more more more more more more text."; richText += " And more more more more more more more text.\n";
richText += StringPart(" And more more more more more more more more text.", COLOR_YELLOW); richText += StringPart("And more more more more more more more more text.\n", COLOR_YELLOW);
richText += " And more more more more more more more more more text."; richText += "And more more more more more more more more more text.\n";
richText += StringPart(" And more more more more more more more more more more text.", COLOR_CYAN); richText += StringPart("And more more more more more more more more more more text.\n", COLOR_CYAN);
TextArea textArea(3, 3, 40, 5, richText); TextArea textArea(3, 3, 64, 7, richText);
// 创建后台缓冲区
HANDLE hBackBuffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
// 清空后台缓冲区
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hConsole, &csbi);
DWORD dwBytesWritten;
FillConsoleOutputCharacter(hBackBuffer, ' ', csbi.dwSize.X * csbi.dwSize.Y, {0, 0}, &dwBytesWritten);
FillConsoleOutputAttribute(hBackBuffer, csbi.wAttributes, csbi.dwSize.X * csbi.dwSize.Y, {0, 0}, &dwBytesWritten);
CONSOLE_CURSOR_INFO cci;
cci.bVisible = false;
cci.dwSize = 1;
SetConsoleCursorInfo(hBackBuffer, &cci);
SetConsoleCursorInfo(hConsole, &cci);
textArea.setTitle(RichText("TextArea Demo", COLOR_RED));
textArea.draw(); textArea.draw();
printf("\n"); while(true) {
if (_kbhit()) {SetConsoleActiveScreenBuffer(hBackBuffer);
char opt = _getch();
textArea.setText(richText + StringPart("Last Key: " + std::to_string(opt), COLOR_CYAN));
switch(opt) {
case 72:
textArea.moveUp();
break;
case 80:
textArea.moveDown();
break;
case 75:
textArea.moveLeft();
break;
case 77:
textArea.moveRight();
break;
case 'q':
SetConsoleActiveScreenBuffer(hConsole);
CloseHandle(hBackBuffer);
return 0;
}
// 清空后台缓冲区
FillConsoleOutputCharacter(hBackBuffer, ' ', csbi.dwSize.X * csbi.dwSize.Y, {0, 0}, &dwBytesWritten);
FillConsoleOutputAttribute(hBackBuffer, csbi.wAttributes, csbi.dwSize.X * csbi.dwSize.Y, {0, 0}, &dwBytesWritten);
// 在后台缓冲区中绘制
textArea.draw();
// 切换到后台缓冲区,显示绘制的内容
SetConsoleActiveScreenBuffer(hConsole);
}
Sleep(1);
}
return 0; return 0;
} }

View File

@ -55,18 +55,11 @@ public:
} }
} }
//绘制文本到缓冲区,保证不超出边框 //绘制文本到缓冲区,保证不超出边框
int textWidth = 0, i = 0; RichText drawTarget = text.substr(0, std::min(width - 2, csbi.dwSize.X - left - 2));
while(textWidth <= width - 2 && left + textWidth + 2 < csbi.dwSize.X && i < text.size()) { SetConsoleCursorPosition(hConsole, {static_cast<short>(left), static_cast<short>(top)});
auto part = text.getParts()[i]; for(auto part : drawTarget.getParts()) {
SetConsoleCursorPosition(hConsole, {static_cast<short>(left + textWidth), static_cast<short>(top)});
SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(getBackColor(part.color)) | FrontColorToWinColor(getFrontColor(part.color))); SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(getBackColor(part.color)) | FrontColorToWinColor(getFrontColor(part.color)));
if(left + textWidth + part.text.length() + 2 < csbi.dwSize.X && textWidth + part.text.length() <= width - 2) {
printf("%s", part.text.c_str()); printf("%s", part.text.c_str());
} else {
printf("%s", part.text.substr(0, std::min(csbi.dwSize.X - left - textWidth - 2, width - 2 - textWidth)).c_str());
}
textWidth += part.text.length();
i++;
} }
SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(COLOR_BLACK) | FrontColorToWinColor(COLOR_WHITE)); SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(COLOR_BLACK) | FrontColorToWinColor(COLOR_WHITE));

View File

@ -43,6 +43,18 @@ public:
RichText() { RichText() {
parts.push_back({""}); parts.push_back({""});
} }
// 构造函数,初始化为一段指定文本和颜色的文本
RichText(const std::string& text, const MColor& color) {
parts.push_back({text, color});
}
// 构造函数,初始化为一段指定文本的文本
RichText(const std::string& text) {
parts.push_back({text});
}
// 构造函数,初始化为一段指定文本和颜色的文本
RichText(const StringPart& part) {
parts.push_back(part);
}
// 重载运算符= // 重载运算符=
RichText& operator=(const RichText& other) { RichText& operator=(const RichText& other) {