1 Commits

Author SHA1 Message Date
0c1cf2938f feat: add a new awesome feature 2025-12-20 17:29:03 +08:00
25 changed files with 2015 additions and 2024 deletions

View File

@@ -7,9 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[中文文档](CHANGELOG.md)
## [v2.3.2] - 2025 - 12 - 20
### ✨ Added
- **Table: runtime reset for headers and data:** added `Table::clearHeaders()`, `Table::clearData()`, and `Table::resetTable()`. This allows a single `Table` instance to dynamically update its headers/data at runtime, and triggers the required recalculation (cell sizing / pagination info) and redraw.
- **TextBox: password mode:** added `PASSWORD_MODE` to `TextBoxmode`. User input is stored internally, while the render layer displays masked characters (e.g., `*`). The real text can be retrieved via `TextBox::getText()`.
### ⚙️ Changed
- **TabControl: clarified default active page semantics:**
- Calling `TabControl::setActiveIndex()` **before the first draw** now only records the default active index; it no longer immediately triggers the tab button click callback.
- **After the first draw completes**, if a default active index was set, the active state is applied and the active page is drawn (if the index is out of range, the last page is activated by default).
- Calling `TabControl::setActiveIndex()` **during runtime (non-first draw)** switches the active page immediately when the index is valid; out-of-range indices are ignored.
### ✅ Fixed
- **TabControl::setActiveIndex crash when called before drawing:** fixed a null-pointer access caused by triggering the tab button click callback before initialization. The default activation is now applied after the first draw completes, preventing crashes and ensuring the active page is rendered on first draw.
- **TabControl rendering glitches when toggling visibility (hidden -> visible):** fixed multi-page overlap/ghosting caused by non-active pages being incorrectly drawn after `setIsVisible(false) -> setIsVisible(true)`. Now, when TabControl is visible, only the active page is visible/drawable; if there is no active page, nothing is drawn.
## [v2.3.1] - 2025-11-30
## 🙏 Acknowledgements
### 🙏 Acknowledgements
- Special thanks to user [@To-KongBai](https://github.com/To-KongBai) for providing stable reproduction steps and key phenomenon comparisons (container nested child control coordinate transformation issue), which helped us quickly identify and fix the control coordinate transformation problem in deeply nested containers. ([Issues#6](https://github.com/Ysm-04/StellarX/issues/6))
- In the upcoming website (currently undergoing ICP filing), we plan to add a contributors' wall to acknowledge users. We welcome everyone to report bugs or share interfaces created with StellarX, and we will carefully read and include acknowledgements.

View File

@@ -7,9 +7,28 @@ StellarX 项目所有显著的变化都将被记录在这个文件中。
[English document](CHANGELOG.en.md)
## [v2.3.2] - 2025 - 12 - 20
### ✨ 新增
- **Table 支持运行期重置表头与数据:**新增 `Table::clearHeaders()``Table::clearData()``Table::resetTable()`,允许同一 `Table` 在运行过程中动态切换表头与数据,并触发必要的单元格尺寸/分页信息重算与重绘。
- **TextBox 新增密码模式:**`TextBoxmode` 新增 `PASSWORD_MODE`;输入内容内部保存,绘制层面使用掩码字符(如 `*`)替代显示,真实文本可通过 `TextBox::getText()` 获取。
### ⚙️ 变更
- **TabControl 默认激活页语义明确化:**
- 首次绘制前调用 `TabControl::setActiveIndex()`:仅记录默认激活索引,不再立即触发页签按钮点击回调;
- 首次绘制完成后:若设置了默认激活索引则应用激活状态并绘制激活页(索引越界时默认激活最后一个页);
- 程序运行过程中调用 `TabControl::setActiveIndex()`:索引合法则立即切换激活页并绘制;索引越界则不做处理。
### ✅ 修复
- **TabControl::setActiveIndex 绘制前调用导致程序中断:**修复绘制前设置默认激活索引时触发空指针访问的问题;现在默认激活逻辑延后到首次绘制完成后再生效,避免崩溃并保证首次绘制即可绘制激活页。
- **TabControl 由不可见设置为可见时绘制错乱:**修复 `setIsVisible(false) -> setIsVisible(true)` 后非激活页被错误绘制导致的多页重叠/残影;现在 TabControl 可见时仅激活页可见/可绘制,无激活页则不绘制任何页。
## [v2.3.1] - 2025 - 11 - 30
## 🙏 鸣谢
### 🙏 鸣谢
- 感谢用户 [@To-KongBai](https://github.com/To-KongBai) 提供稳定复现步骤与关键现象对比(容器嵌套孙控件坐标转换问题),帮助我们快速确认多容器嵌套时的控件坐标转换问题并修复。([Issues#6](https://github.com/Ysm-04/StellarX/issues/6)
- 在即将上线的官网中ICP备案中我们计划加入一个贡献者鸣谢墙欢迎各位用户反馈BUG或者分享自己用星垣做的界面我们将认真阅读并收录鸣谢

View File

@@ -7,8 +7,8 @@
![GitHub all releases](https://img.shields.io/github/downloads/Ysm-04/StellarX/total)
[![Star GitHub Repo](https://img.shields.io/github/stars/Ysm-04/StellarX.svg?style=social&label=Star%20This%20Repo)](https://github.com/Ysm-04/StellarX)
![Version](https://img.shields.io/badge/Version-2.3.0-brightgreen.svg)
![Download](https://img.shields.io/badge/Download-2.3.0_Release-blue.svg)
![Version](https://img.shields.io/badge/Version-2.3.2-brightgreen.svg)
![Download](https://img.shields.io/badge/Download-2.3.2_Release-blue.svg)
![C++](https://img.shields.io/badge/C++-17+-00599C?logo=cplusplus&logoColor=white)
![Windows](https://img.shields.io/badge/Platform-Windows-0078D6?logo=windows)
@@ -25,30 +25,6 @@ This is a **teaching-grade and tooling-grade** framework that helps developers u
------
## 🆕 V2.3.0 - Major Update
**This version represents a significant milestone, introducing a responsive layout system that transitions from static to dynamic layout management, and comprehensively resolves the previously encountered random rendering corruption issues caused by reentrant drawing operations.**
- **Optimized Window Resizing Mechanism**: Refactored `WndProcThunk`, `runEventLoop`, and `pumpResizeIfNeeded` to uniformly record size changes and perform centralized repainting at the end of the event loop, eliminating jitter and sequencing confusion caused by repeated redraws.
- **New Dialog Size Scheduling Interface**: Introduced the combination of `Window::scheduleResizeFromModal()` and `pumpResizeIfNeeded()`, enabling modal dialogs to notify the parent window of size updates even during resizing operations. Underlying controls are relayout during unified finalization while dialogs maintain their original dimensions.
- **Enhanced Adaptive Layout System**: Internally added the `adaptiveLayout()` function to recalculate control positions and sizes based on anchor points, allowing dual-anchored controls (left-right or top-bottom) to adaptively stretch with window resizing.
- **Fixed Modal Dialog Resizing Issues**: Resolved the problem where window resizing while modal dialogs were open prevented underlying controls from updating their positions and sizes according to anchor points; simultaneously eliminated ghosting artifacts caused by repeated dialog redraws.
- **Further Resolved Drawing Sequence Confusion**: Replaced `InvalidateRect` with `ValidateRect` during resizing operations, ensuring the window is marked as valid only after a single unified drawing pass, preventing system-triggered `WM_PAINT` messages from causing reentrancy.
- **Additional Fixes**: Corrected delayed background snapshot updates in tables and dialogs under certain edge cases.
![](image/1.png)
![](image/2.png)
For details, please refer to the [CHANGELOG.en](CHANGELOG.en.md).
------
## 📦 Project Structure & Design Philosophy
StellarX adopts classic **OOP** and **modular** design with a clear structure:

View File

@@ -14,8 +14,8 @@
![GitHub all releases](https://img.shields.io/github/downloads/Ysm-04/StellarX/total)
[![Star GitHub Repo](https://img.shields.io/github/stars/Ysm-04/StellarX.svg?style=social&label=Star%20This%20Repo)](https://github.com/Ysm-04/StellarX)
![Version](https://img.shields.io/badge/Version-2.3.1-brightgreen.svg)
![Download](https://img.shields.io/badge/Download-2.3.1_Release-blue.svg)
![Version](https://img.shields.io/badge/Version-2.3.2-brightgreen.svg)
![Download](https://img.shields.io/badge/Download-2.3.2_Release-blue.svg)
![C++](https://img.shields.io/badge/C++-17+-00599C?logo=cplusplus&logoColor=white)
![Windows](https://img.shields.io/badge/Platform-Windows-0078D6?logo=windows)
@@ -32,30 +32,26 @@
---
## ==公告==
## 🙏 鸣谢
- 感谢用户 [@To-KongBai](https://github.com/To-KongBai) 提供稳定复现步骤与关键现象对比(容器嵌套孙控件坐标转换问题),帮助我们快速确认多容器嵌套时的控件坐标转换问题并修复。([Issues#6](https://github.com/Ysm-04/StellarX/issues/6)
- 在即将上线的官网中ICP备案中我们计划加入一个贡献者鸣谢墙欢迎各位用户反馈BUG或者分享自己用星垣做的界面我们将认真阅读并收录鸣谢
- 真诚的感谢每一位反馈BUG的用户你们的反馈将使星垣更加稳定和健壮
## 🆕V2.3.2——重要更新
---
### 新增
## 🆕V2.3.1——重要更新
### ✨ 新增
新增一个登录界面Demo在主仓库**examples/**目录下
- **Table 支持运行期重置表头与数据:**新增 `Table::clearHeaders()``Table::clearData()``Table::resetTable()`,允许同一 `Table` 在运行过程中动态切换表头与数据,并触发必要的单元格尺寸/分页信息重算与重绘。
- **TextBox 新增密码模式:**`TextBoxmode` 新增 `PASSWORD_MODE`;输入内容内部保存,绘制层面使用掩码字符(如 `*`)替代显示,真实文本可通过 `TextBox::getText()` 获取。
### ⚙️ 变更
- **Dialog背景快照机制**`Dialog`不在自己抓取和销毁快照,**删除**重载的抓取和恢复快照的方法,完全交由基类`Canvas`处理,`Dialog``draw`方法中不在处理快照
- **窗口变化重绘时控件和窗口重绘的时机调整:**主事件循环中窗口大小发生变化时先处理控件尺寸,并回贴和释放旧快照,然后再重绘新尺寸窗口,最后绘制控件
- **TabControl 默认激活页语义明确化:**
- 首次绘制前调用 `TabControl::setActiveIndex()`:仅记录默认激活索引,不再立即触发页签按钮点击回调;
- 首次绘制完成后:若设置了默认激活索引则应用激活状态并绘制激活页(索引越界时默认激活最后一个页);
- 程序运行过程中调用 `TabControl::setActiveIndex()`:索引合法则立即切换激活页并绘制;索引越界则不做处理。
本次针对用户反馈和已知内容进行了一些修复……
### ✅ 修复
详细变更请参阅[更新日志](CHANGELOG.md)
- **TabControl::setActiveIndex 绘制前调用导致程序中断:**修复绘制前设置默认激活索引时触发空指针访问的问题;现在默认激活逻辑延后到首次绘制完成后再生效,避免崩溃并保证首次绘制即可绘制激活页。
- **TabControl 由不可见设置为可见时绘制错乱:**修复 `setIsVisible(false) -> setIsVisible(true)` 后非激活页被错误绘制导致的多页重叠/残影;现在 TabControl 可见时仅激活页可见/可绘制,无激活页则不绘制任何页。
---

View File

@@ -21,17 +21,14 @@
#include "Control.h"
#include"label.h"
#define DISABLEDCOLOUR RGB(96, 96, 96) //禁用状态颜色
#define TEXTMARGINS_X 6
#define TEXTMARGINS_Y 4
constexpr int bordWith = 1; //边框宽度,用于快照恢复时的偏移计算
constexpr int bordHeight = 1; //边框高度,用于快照恢复时的偏移计算
class Button : public Control
{
std::string text; // 按钮上的文字
bool click; // 是否被点击
bool hover; // 是否被悬停
@@ -45,7 +42,7 @@ class Button : public Control
COLORREF buttonTrueColor; // 按钮被点击后的颜色
COLORREF buttonFalseColor; // 按钮未被点击的颜色
COLORREF buttonHoverColor; // 按钮被鼠标悬停的颜色
COLORREF buttonBorderColor = RGB(0,0,0);// 按钮边框颜色
COLORREF buttonBorderColor = RGB(0, 0, 0);// 按钮边框颜色
StellarX::ButtonMode mode; // 按钮模式
StellarX::ControlShape shape; // 按钮形状
@@ -54,8 +51,6 @@ class Button : public Control
StellarX::FillStyle buttonFillIma = StellarX::FillStyle::BDiagonal; //按钮填充图案
IMAGE* buttonFileIMAGE = nullptr; //按钮填充图像
std::function<void()> onClickCallback; //回调函数
std::function<void()> onToggleOnCallback; //TOGGLE模式下的回调函数
std::function<void()> onToggleOffCallback; //TOGGLE模式下的回调函数
@@ -97,7 +92,7 @@ public:
StellarX::ControlShape shape = StellarX::ControlShape::RECTANGLE);
//自定义按钮颜色和悬停颜色
Button(int x, int y, int width, int height, const std::string text,
COLORREF ct, COLORREF cf,COLORREF ch,
COLORREF ct, COLORREF cf, COLORREF ch,
StellarX::ButtonMode mode = StellarX::ButtonMode::NORMAL, StellarX::ControlShape shape = StellarX::ControlShape::RECTANGLE);
//析构函数 释放图形指针内存
~Button();
@@ -176,7 +171,7 @@ public:
//设置提示框样式
void setTooltipStyle(COLORREF text, COLORREF bk, bool transparent);
//设置提示框文本
void setTooltipText(const std::string& s){ tipTextClick = s; tipUserOverride = true; }
void setTooltipText(const std::string& s) { tipTextClick = s; tipUserOverride = true; }
void setTooltipTextsForToggle(const std::string& onText, const std::string& offText);
private:
//初始化按钮
@@ -192,6 +187,4 @@ private:
void hideTooltip();
// 根据当前 click 状态选择文案
void refreshTooltipTextForState();
};

View File

@@ -31,8 +31,7 @@ protected:
int canvaslinewidth = 1; //线宽
COLORREF canvasBorderClor = RGB(0, 0, 0); //边框颜色
COLORREF canvasBkClor = RGB(255,255,255); //背景颜色
COLORREF canvasBkClor = RGB(255, 255, 255); //背景颜色
// 清除所有子控件
void clearAllControls();
@@ -71,6 +70,4 @@ public:
private:
//用来检查对话框是否模态,此控件不做实现
bool model() const override { return false; };
};

View File

@@ -36,8 +36,8 @@ class Control
{
protected:
std::string id; // 控件ID
int localx,x, localy,y; // 左上角坐标
int localWidth,width, localHeight,height; // 控件尺寸
int localx, x, localy, y; // 左上角坐标
int localWidth, width, localHeight, height; // 控件尺寸
Control* parent = nullptr; // 父控件
bool dirty = true; // 是否重绘
bool show = true; // 是否显示
@@ -66,9 +66,10 @@ protected:
Control(Control&&) = delete;
Control& operator=(Control&&) = delete;
Control() : localx(0),x(0), localy(0),y(0), localWidth(100),width(100),height(100), localHeight(100) {}
Control() : localx(0), x(0), localy(0), y(0), localWidth(100), width(100), height(100), localHeight(100) {}
Control(int x, int y, int width, int height)
: localx(x), x(x), localy(y), y(y), localWidth(width), width(width), height(height), localHeight(height){}
: localx(x), x(x), localy(y), y(y), localWidth(width), width(width), height(height), localHeight(height) {
}
public:
virtual ~Control()

View File

@@ -207,7 +207,8 @@ namespace StellarX
enum class TextBoxmode
{
INPUT_MODE, // 用户可输入模式
READONLY_MODE // 只读模式
READONLY_MODE, // 只读模式
PASSWORD_MODE// 密码模式
};
/**

View File

@@ -45,7 +45,6 @@ class Dialog : public Canvas
std::string message; //提示信息
std::vector<std::string> lines; //消息内容按行分割
bool needsInitialization = true; //是否需要初始化
bool close = false; //是否关闭
bool modal = true; //是否模态
@@ -57,7 +56,6 @@ class Dialog : public Canvas
COLORREF buttonFalseColor = RGB(215, 215, 215); //按钮未被点击颜色
COLORREF buttonHoverColor = RGB(224, 224, 224); //按钮悬浮颜色
Button* closeButton = nullptr; //关闭按钮
StellarX::MessageBoxResult result = StellarX::MessageBoxResult::Cancel; // 对话框结果
@@ -78,7 +76,6 @@ public:
//获取对话框消息,用以去重
std::string GetText() const;
public:
Dialog(Window& hWnd, std::string text, std::string message = "对话框", StellarX::MessageBoxType type = StellarX::MessageBoxType::OK, bool modal = true);
~Dialog();
@@ -109,7 +106,6 @@ public:
//初始化
void setInitialization(bool init);
private:
// 初始化按钮
void initButtons();

View File

@@ -1,7 +1,7 @@
/*******************************************************************************
* @文件: StellarX.h
* @摘要: 星垣(StellarX) GUI框架 - 主包含头文件
* @版本: v2.3.1
* @版本: v2.3.2
* @描述:
* 一个为Windows平台打造的轻量级、模块化C++ GUI框架。
* 基于EasyX图形库提供简洁易用的API和丰富的控件。
@@ -11,7 +11,7 @@
*
* @作者: 我在人间做废物
* @邮箱: [3150131407@qq.com] | [ysm3150131407@gmail.com]
* @官网地址https://stellarx-gui.top
* @官网https://stellarx-gui.top/
* @仓库: [https://github.com/Ysm-04/StellarX]
*
* @许可证: MIT License

View File

@@ -26,8 +26,10 @@
class TabControl :public Canvas
{
int tabBarHeight = BUTMINWIDTH; //页签栏高度
StellarX::TabPlacement tabPlacement = StellarX::TabPlacement::Top ; //页签排列方式
std::vector<std::pair<std::unique_ptr<Button>,std::unique_ptr<Canvas>>> controls; //页签/页列表
bool IsFirstDraw = true; //首次绘制标记
int defaultActivation = -1; //默认激活页签索引
StellarX::TabPlacement tabPlacement = StellarX::TabPlacement::Top; //页签排列方式
std::vector<std::pair<std::unique_ptr<Button>, std::unique_ptr<Canvas>>> controls; //页签/页列表
private:
using Canvas::addControl; // 禁止外部误用
@@ -37,7 +39,7 @@ private:
inline void initTabPage();
public:
TabControl();
TabControl(int x,int y,int width,int height);
TabControl(int x, int y, int width, int height);
~TabControl();
void setX(int x)override;
@@ -47,9 +49,9 @@ public:
bool handleEvent(const ExMessage& msg) override;
//添加页签+页
void add(std::pair<std::unique_ptr<Button> ,std::unique_ptr<Canvas>>&& control);
void add(std::pair<std::unique_ptr<Button>, std::unique_ptr<Canvas>>&& control);
//添加为某个页添加控件
void add(std::string tabText,std::unique_ptr<Control> control);
void add(std::string tabText, std::unique_ptr<Control> control);
//设置页签位置
void setTabPlacement(StellarX::TabPlacement placement);
//设置页签栏高度 两侧排列时为宽度
@@ -67,6 +69,4 @@ public:
int indexOf(const std::string& tabText) const;
void setDirty(bool dirty) override;
void requestRepaint(Control* parent)override;
};

View File

@@ -33,7 +33,7 @@ public:
StellarX::ControlText textStyle; //标签文本样式
public:
Label();
Label(int x, int y, std::string text = "标签",COLORREF textcolor = BLACK, COLORREF bkColor= RGB(255,255,255));
Label(int x, int y, std::string text = "标签", COLORREF textcolor = BLACK, COLORREF bkColor = RGB(255, 255, 255));
void draw() override;
void hide();
@@ -43,6 +43,4 @@ public:
void setTextBkColor(COLORREF color);
//设置标签文本
void setText(std::string text);
};

View File

@@ -49,7 +49,6 @@
#define TABLE_STR_PAGE_MID "页/共"
#define TABLE_STR_PAGE_SUFFIX "页"
class Table :public Control
{
private:
@@ -131,6 +130,12 @@ public:
void setTableLineStyle(StellarX::LineStyle style);
//设置边框宽度
void setTableBorderWidth(int width);
//清空表头
void clearHeaders();
//清空表格数据
void clearData();
//清空表头和数据
void resetTable();
//窗口变化丢快照+标脏
void onWindowResize() override;
@@ -153,7 +158,7 @@ public:
//获取线型
StellarX::LineStyle getTableLineStyle() const;
//获取表头
std::vector<std::string> getHeaders () const;
std::vector<std::string> getHeaders() const;
//获取表格数据
std::vector<std::vector<std::string>> getData() const;
//获取表格边框宽度
@@ -161,7 +166,4 @@ public:
//获取表格尺寸
int getTableWidth() const;
int getTableHeight() const;
};

View File

@@ -18,7 +18,6 @@
#pragma once
#include "Control.h"
class TextBox : public Control
{
std::string text; //文本
@@ -27,7 +26,7 @@ class TextBox : public Control
bool click = false; //是否点击
size_t maxCharLen = 10;//最大字符长度
COLORREF textBoxBkClor = RGB(255, 255, 255); //背景颜色
COLORREF textBoxBorderClor = RGB(0,0,0); //边框颜色
COLORREF textBoxBorderClor = RGB(0, 0, 0); //边框颜色
public:
StellarX::ControlText textStyle; //文本样式
@@ -55,5 +54,3 @@ private:
//用来检查对话框是否模态,此控件不做实现
bool model() const override { return false; };
};

View File

@@ -1,5 +1,4 @@
/**
/**
* Window头文件
*
* 设计目标:
@@ -101,10 +100,9 @@ public:
useComposited = on;
}
void processWindowMessage(const ExMessage & msg); // 处理 EX_WINDOW 中的 WM_SIZE 等
void processWindowMessage(const ExMessage& msg); // 处理 EX_WINDOW 中的 WM_SIZE 等
void pumpResizeIfNeeded(); // 执行一次统一收口重绘
void scheduleResizeFromModal(int w, int h);
private:
void adaptiveLayout(std::unique_ptr<Control>& c,const int finalH, const int finalW);
void adaptiveLayout(std::unique_ptr<Control>& c, const int finalH, const int finalW);
};

View File

@@ -163,7 +163,6 @@ void Button::initButton(const std::string text, StellarX::ButtonMode mode, Stell
tipLabel.textStyle = this->textStyle; // 复用按钮字体样式
}
Button::~Button()
{
if (buttonFileIMAGE)
@@ -274,7 +273,6 @@ void Button::draw()
restoreStyle();//恢复默认字体样式和颜色
dirty = false; //标记按钮不需要重绘
}
// 处理鼠标事件,检测点击和悬停状态
// 根据按钮模式和形状进行不同的处理
@@ -314,7 +312,6 @@ bool Button::handleEvent(const ExMessage& msg)
// 处理鼠标点击事件
if (msg.message == WM_LBUTTONDOWN && hover && mode != StellarX::ButtonMode::DISABLED)
{
if (mode == StellarX::ButtonMode::NORMAL)
{
click = true;
@@ -451,7 +448,6 @@ void Button::setROUND_RECTANGLEwidth(int width)
{
rouRectangleSize.ROUND_RECTANGLEwidth = width;
this->dirty = true; // 标记需要重绘
}
void Button::setROUND_RECTANGLEheight(int height)
@@ -489,7 +485,6 @@ void Button::setFillIma(std::string imaNAme)
this->dirty = true;
}
void Button::setButtonBorder(COLORREF Border)
{
buttonBorderColor = Border;
@@ -558,7 +553,6 @@ void Button::setButtonClick(BOOL click)
requestRepaint(parent);
}
std::string Button::getButtonText() const
{
return this->text;
@@ -619,8 +613,6 @@ int Button::getButtonHeight() const
return this->height;
}
bool Button::isMouseInCircle(int mouseX, int mouseY, int x, int y, int radius)
{
double dis = sqrt(pow(mouseX - x, 2) + pow(mouseY - y, 2));
@@ -666,11 +658,9 @@ void Button::cutButtonText()
else
{
cutText = ellipsize_cjk_pref(this->text, contentW, ""); // 全角省略号
}
isUseCutText = true;
needCutText = false;
}
void Button::hideTooltip()
@@ -691,6 +681,3 @@ void Button::refreshTooltipTextForState()
else if (mode == StellarX::ButtonMode::TOGGLE)
tipLabel.setText(click ? tipTextOn : tipTextOff);
}

View File

@@ -50,7 +50,7 @@ void Canvas::draw()
}
saveStyle();
setlinecolor(canvasBorderClor);//设置线色
if(StellarX::FillMode::Null != canvasFillMode)
if (StellarX::FillMode::Null != canvasFillMode)
setfillcolor(canvasBkClor);//设置填充色
setfillstyle((int)canvasFillMode);//设置填充模式
setlinestyle((int)canvasLineStyle, canvaslinewidth);
@@ -73,7 +73,7 @@ void Canvas::draw()
else
{
// 首次绘制或没有快照时直接抓取背景
saveBackground(this->x- margin, this->y- margin, this->width + margin*2, this->height + margin*2);
saveBackground(this->x - margin, this->y - margin, this->width + margin * 2, this->height + margin * 2);
}
// 再次恢复最新快照,确保绘制区域干净
restBackground();
@@ -81,7 +81,7 @@ void Canvas::draw()
switch (shape)
{
case StellarX::ControlShape::RECTANGLE:
fillrectangle(x,y,x+width,y+height);//有边框填充矩形
fillrectangle(x, y, x + width, y + height);//有边框填充矩形
break;
case StellarX::ControlShape::B_RECTANGLE:
solidrectangle(x, y, x + width, y + height);//无边框填充矩形
@@ -121,7 +121,6 @@ bool Canvas::handleEvent(const ExMessage& msg)
void Canvas::addControl(std::unique_ptr<Control> control)
{
//坐标转化
control->setX(control->getLocalX() + this->x);
control->setY(control->getLocalY() + this->y);
@@ -175,7 +174,6 @@ void Canvas::setCanvasLineStyle(StellarX::LineStyle style)
dirty = true;
}
void Canvas::setLinewidth(int width)
{
this->canvaslinewidth = width;
@@ -198,7 +196,7 @@ void Canvas::setIsVisible(bool visible)
void Canvas::setDirty(bool dirty)
{
this->dirty = dirty;
for(auto& control : controls)
for (auto& control : controls)
control->setDirty(dirty);
}
@@ -384,8 +382,3 @@ void Canvas::requestRepaint(Control* parent)
else
onRequestRepaintAsRoot();
}

View File

@@ -44,9 +44,14 @@ bool StellarX::ControlText::operator!=(const ControlText& text)
}
void Control::setIsVisible(bool show)
{
this->show = show;
dirty = true;
if (!show)
this->updateBackground();
this->show = show;
else
requestRepaint(parent);
}
void Control::onWindowResize()
{

View File

@@ -1,21 +1,19 @@
#include "Dialog.h"
Dialog::Dialog(Window& h,std::string text,std::string message, StellarX::MessageBoxType type, bool modal)
: Canvas(),message(message), type(type), modal(modal), hWnd(h), titleText(text)
Dialog::Dialog(Window& h, std::string text, std::string message, StellarX::MessageBoxType type, bool modal)
: Canvas(), message(message), type(type), modal(modal), hWnd(h), titleText(text)
{
this->id = "Dialog";
show = false;
}
Dialog::~Dialog()
{
}
void Dialog::draw()
{
if(!show)
if (!show)
{
// 如果对话框不可见且需要清理,执行清理
if (pendingCleanup && !isCleaning)
@@ -51,9 +49,8 @@ void Dialog::draw()
textStyle.nEscapement, textStyle.nOrientation, textStyle.nWeight,
textStyle.bItalic, textStyle.bUnderline, textStyle.bStrikeOut);
int ty = y + closeButtonHeight + titleToTextMargin; // 文本起始Y坐标
for (auto& line:lines)
for (auto& line : lines)
{
int tx = this->x + ((this->width - textwidth(line.c_str())) / 2); // 文本起始X坐标
outtextxy(tx, ty, LPCTSTR(line.c_str()));
@@ -67,8 +64,6 @@ void Dialog::draw()
}
}
bool Dialog::handleEvent(const ExMessage& msg)
{
bool consume = false;
@@ -134,7 +129,6 @@ void Dialog::SetModal(bool modal)
this->modal = modal;
}
void Dialog::SetResult(StellarX::MessageBoxResult result)
{
this->result = result;
@@ -238,8 +232,6 @@ void Dialog::Show()
dirty = true;
}
void Dialog::Close()
{
if (!show) return;
@@ -249,12 +241,9 @@ void Dialog::Close()
dirty = true;
pendingCleanup = true; // 只标记需要清理,不立即执行
// 工厂模式下非模态触发回调 返回结果
if (resultCallback&& !modal)
if (resultCallback && !modal)
resultCallback(this->result);
}
void Dialog::setInitialization(bool init)
@@ -267,7 +256,6 @@ void Dialog::setInitialization(bool init)
}
}
void Dialog::initButtons()
{
controls.clear();
@@ -391,7 +379,6 @@ void Dialog::initButtons()
noButton->textStyle = this->textStyle;
cancelButton->textStyle = this->textStyle;
this->addControl(std::move(yesButton));
this->addControl(std::move(noButton));
this->addControl(std::move(cancelButton));
@@ -431,7 +418,7 @@ void Dialog::initButtons()
case StellarX::MessageBoxType::AbortRetryIgnore: // 中止、重试和忽略按钮
{
auto abortButton = createDialogButton(
(this->x + (this->width - (functionButtonWidth * buttonNum + buttonMargin* (buttonNum-1))) / 2),
(this->x + (this->width - (functionButtonWidth * buttonNum + buttonMargin * (buttonNum - 1))) / 2),
((this->y + (this->height - buttonAreaHeight)) + (buttonAreaHeight - functionButtonHeight) / 2),
"中止"
);
@@ -481,7 +468,7 @@ void Dialog::initCloseButton()
//初始化关闭按钮
auto but = std::make_unique<Button>
(
(this->x + this->width - closeButtonWidth) - 3, (this->y+3), closeButtonWidth-1, closeButtonHeight,
(this->x + this->width - closeButtonWidth) - 3, (this->y + 3), closeButtonWidth - 1, closeButtonHeight,
"X", // 按钮文本
RGB(255, 0, 0), // 按钮被点击颜色
this->canvasBkClor, // 按钮背景颜色
@@ -502,7 +489,7 @@ void Dialog::initCloseButton()
void Dialog::initTitle()
{
this->title = std::make_unique<Label>(this->x+5,this->y+5,titleText,textStyle.color);
this->title = std::make_unique<Label>(this->x + 5, this->y + 5, titleText, textStyle.color);
title->setTextdisap(true);
title->textStyle = this->textStyle;
@@ -516,7 +503,7 @@ void Dialog::splitMessageLines()
std::string currentLine;
for (size_t i = 0; i < message.length(); i++) {
// 处理 换行符 \r\n \n \r
if (i + 1 < message.length() && (message[i] == '\r' || message[i] == '\n')||(message[i] == '\r' && message[i+1] == '\n'))
if (i + 1 < message.length() && (message[i] == '\r' || message[i] == '\n') || (message[i] == '\r' && message[i + 1] == '\n'))
{
if (!currentLine.empty()) {
lines.push_back(currentLine);
@@ -587,10 +574,10 @@ void Dialog::initDialogSize()
// 计算按钮区域宽度
int buttonAreaWidth = buttonNum * functionButtonWidth +
(buttonNum > 0 ? (buttonNum +1) * buttonMargin : 0);
(buttonNum > 0 ? (buttonNum + 1) * buttonMargin : 0);
// 计算文本区域宽度(包括边距)
int textAreaWidth = textWidth + textToBorderMargin * 2 ;
int textAreaWidth = textWidth + textToBorderMargin * 2;
// 对话框宽度取两者中的较大值,并确保最小宽度
this->width = buttonAreaWidth > textAreaWidth ? buttonAreaWidth : textAreaWidth;
@@ -598,7 +585,7 @@ void Dialog::initDialogSize()
// 计算对话框高度
// 高度 = 标题栏高度 + 文本区域高度 + 按钮区域高度 + 间距
int textAreaHeight = textHeight * (int)lines.size() + 5*((int)lines.size()-1); // 文本行高+行间距
int textAreaHeight = textHeight * (int)lines.size() + 5 * ((int)lines.size() - 1); // 文本行高+行间距
this->height = closeButtonHeight + // 标题栏高度
titleToTextMargin + // 标题到文本的间距
textAreaHeight + // 文本区域高度
@@ -717,7 +704,6 @@ void Dialog::requestRepaint(Control* parent)
for (auto& control : controls)
if (control->isDirty() && control->IsVisible())
control->draw();
}
else
onRequestRepaintAsRoot();

View File

@@ -2,7 +2,7 @@
namespace StellarX
{
MessageBoxResult MessageBox::showModal(Window& wnd,const std::string& text,const std::string& caption,
MessageBoxResult MessageBox::showModal(Window& wnd, const std::string& text, const std::string& caption,
MessageBoxType type)
{
Dialog dlg(wnd, caption, text, type, true); // 模态
@@ -11,7 +11,7 @@ namespace StellarX
return dlg.GetResult();
}
void MessageBox::showAsync(Window& wnd,const std::string& text,const std::string& caption,MessageBoxType type,
void MessageBox::showAsync(Window& wnd, const std::string& text, const std::string& caption, MessageBoxType type,
std::function<void(MessageBoxResult)> onResult)
{
//去重,如果窗口内已有相同的对话框被触发,则不再创建

View File

@@ -33,7 +33,7 @@ inline void TabControl::initTabBar()
for (auto& c : controls)
{
c.first->setX(this->x + i * butW);
c.first->setY(this->y+this->height - tabBarHeight);
c.first->setY(this->y + this->height - tabBarHeight);
i++;
}
break;
@@ -41,14 +41,14 @@ inline void TabControl::initTabBar()
for (auto& c : controls)
{
c.first->setX(this->x);
c.first->setY(this->y+i* butH);
c.first->setY(this->y + i * butH);
i++;
}
break;
case StellarX::TabPlacement::Right:
for (auto& c : controls)
{
c.first->setX(this->x+this->width - tabBarHeight);
c.first->setX(this->x + this->width - tabBarHeight);
c.first->setY(this->y + i * butH);
i++;
}
@@ -147,7 +147,7 @@ inline void TabControl::initTabPage()
}
}
TabControl::TabControl():Canvas()
TabControl::TabControl() :Canvas()
{
this->id = "TabControl";
}
@@ -173,7 +173,6 @@ void TabControl::setX(int x)
c.first->onWindowResize();
c.second->onWindowResize();
}
}
void TabControl::setY(int y)
@@ -192,26 +191,6 @@ void TabControl::setY(int y)
void TabControl::draw()
{
if (!dirty || !show)return;
// // 在绘制 TabControl 之前,先恢复并更新背景快照:
//int margin = canvaslinewidth > 1 ? canvaslinewidth : 1;
//if (hasSnap)
//{
// // 恢复旧快照,清除上一次绘制
// restBackground();
// // 如果位置或尺寸变了,或没有有效缓存,则重新抓取
// if (!saveBkImage || saveBkX != this->x - margin || saveBkY != this->y - margin || saveWidth != this->width + margin * 2 || saveHeight != this->height + margin * 2)
// {
// discardBackground();
// saveBackground(this->x - margin, this->y - margin, this->width + margin * 2, this->height + margin * 2);
// }
//}
//else
//{
// // 首次绘制或没有快照时直接抓取背景
// saveBackground(this->x - margin, this->y - margin, this->width + margin * 2, this->height + margin * 2);
//}
// // 再次恢复最新背景,保证绘制区域干净
// restBackground();
// 绘制画布背景和基本形状及其子画布控件
Canvas::draw();
for (auto& c : controls)
@@ -224,8 +203,17 @@ void TabControl::draw()
c.second->setDirty(true);
c.second->draw();
}
dirty = false;
// 首次绘制时处理默认激活页签
if (IsFirstDraw)
{
if (defaultActivation >= 0 && defaultActivation < (int)controls.size())
controls[defaultActivation].first->setButtonClick(true);
else if (defaultActivation >= (int)controls.size())//索引越界则激活最后一个
controls[controls.size() - 1].first->setButtonClick(true);
IsFirstDraw = false;//避免重复处理
}
dirty = false;
}
bool TabControl::handleEvent(const ExMessage& msg)
@@ -239,7 +227,7 @@ bool TabControl::handleEvent(const ExMessage& msg)
break;
}
for (auto& c : controls)
if(c.second->IsVisible())
if (c.second->IsVisible())
if (c.second->handleEvent(msg))
{
consume = true;
@@ -260,7 +248,7 @@ void TabControl::add(std::pair<std::unique_ptr<Button>, std::unique_ptr<Canvas>>
controls[idx].first->enableTooltip(true);
controls[idx].first->setbuttonMode(StellarX::ButtonMode::TOGGLE);
controls[idx].first->setOnToggleOnListener([this,idx]()
controls[idx].first->setOnToggleOnListener([this, idx]()
{
controls[idx].second->setIsVisible(true);
controls[idx].second->onWindowResize();
@@ -274,7 +262,7 @@ void TabControl::add(std::pair<std::unique_ptr<Button>, std::unique_ptr<Canvas>>
}
dirty = true;
});
controls[idx].first->setOnToggleOffListener([this,idx]()
controls[idx].first->setOnToggleOffListener([this, idx]()
{
controls[idx].second->setIsVisible(false);
@@ -293,12 +281,11 @@ void TabControl::add(std::string tabText, std::unique_ptr<Control> control)
if (tab.first->getButtonText() == tabText)
{
control->setParent(tab.second.get());
control->setIsVisible( tab.second->IsVisible());
control->setIsVisible(tab.second->IsVisible());
tab.second->addControl(std::move(control));
break;
}
}
}
void TabControl::setTabPlacement(StellarX::TabPlacement placement)
@@ -307,7 +294,6 @@ void TabControl::setTabPlacement(StellarX::TabPlacement placement)
setDirty(true);
initTabBar();
initTabPage();
}
void TabControl::setTabBarHeight(int height)
@@ -321,16 +307,25 @@ void TabControl::setTabBarHeight(int height)
void TabControl::setIsVisible(bool visible)
{
// 先让基类 Canvas 处理自己的回贴/丢快照逻辑
Canvas::setIsVisible(visible); // <--- 新增
this->show = visible;
Canvas::setIsVisible(visible);
for (auto& tab : controls)
{
if(true == visible)
{
tab.first->setIsVisible(visible);
//页也要跟着关/开,否则它们会保留旧的 saveBkImage
tab.second->setIsVisible(visible);
if (tab.first->isClicked())
tab.second->setIsVisible(true);
else
tab.second->setIsVisible(false);
tab.second->setDirty(true);
}
else
{
tab.first->setIsVisible(visible);
tab.second->setIsVisible(visible);
}
}
}
void TabControl::onWindowResize()
@@ -364,20 +359,13 @@ int TabControl::getActiveIndex() const
void TabControl::setActiveIndex(int idx)
{
if (idx < 0 || idx > controls.size() - 1) return;
if (controls[idx].first->getButtonMode() == StellarX::ButtonMode::DISABLED)return;
if (controls[idx].first->isClicked())
{
if (controls[idx].second->IsVisible())
return;
else
controls[idx].second->setIsVisible(true);
}
if (IsFirstDraw)
defaultActivation = idx;
else
{
if (idx >= 0 && idx < controls.size())
controls[idx].first->setButtonClick(true);
}
}
int TabControl::count() const
@@ -388,7 +376,7 @@ int TabControl::count() const
int TabControl::indexOf(const std::string& tabText) const
{
int idx = -1;
for(auto& c : controls)
for (auto& c : controls)
{
idx++;
if (c.first->getButtonText() == tabText)
@@ -416,7 +404,7 @@ void TabControl::requestRepaint(Control* parent)
{
if (control.first->isDirty() && control.first->IsVisible())
control.first->draw();
else if (control.second->isDirty()&&control.second->IsVisible())
else if (control.second->isDirty() && control.second->IsVisible())
control.second->draw();
}
}

View File

@@ -5,7 +5,7 @@ Label::Label()
{
this->id = "Label";
this->text = "默认标签";
textStyle.color = RGB(0,0,0);
textStyle.color = RGB(0, 0, 0);
textBkColor = RGB(255, 255, 255);; //默认白色背景
}
@@ -40,7 +40,7 @@ void Label::draw()
this->height = textheight(text.c_str());
}
if ((saveBkX != this->x) || (saveBkY != this->y) || (!hasSnap) || (saveWidth != this->width) || (saveHeight != this->height) || !saveBkImage)
saveBackground(this->x, this->y,this->width,this->height);
saveBackground(this->x, this->y, this->width, this->height);
// 恢复背景(清除旧内容)
restBackground();
outtextxy(x, y, LPCTSTR(text.c_str()));
@@ -71,5 +71,4 @@ void Label::setText(std::string text)
{
this->text = text;
this->dirty = true;
}

View File

@@ -26,12 +26,10 @@ void Table::drawTable()
dY = uY;
uY = dY + lineHeights.at(0) + TABLE_ROW_EXTRA;
}
}
void Table::drawHeader()
{
const int border = tableBorderWidth > 0 ? tableBorderWidth : 0;
// 内容区原点 = x+border, y+border
dX = x + border;
@@ -132,7 +130,6 @@ void Table::initButton()
int nextW = textwidth(LPCTSTR(TABLE_STR_NEXT)) + padH * 2;
int btnH = lblH + padV * 2;
// 基于“页码标签”的矩形来摆放:
// prev 在页码左侧 gap 处next 在右侧 gap 处Y 对齐 pY
int prevX = pX - gap - prevW;
@@ -199,7 +196,7 @@ void Table::initPageNum()
// 按理来说 x + (this->width - textW) / 2;就可以
// 但是在绘制时发现控件偏右因此减去40
int textW = textwidth(LPCTSTR(pageNumtext.c_str()));
pX = x + TABLE_PAGE_TEXT_OFFSET_X +(this->width - textW) / 2;
pX = x + TABLE_PAGE_TEXT_OFFSET_X + (this->width - textW) / 2;
if (!pageNum)
pageNum = new Label(pX, pY, pageNumtext);
@@ -216,9 +213,8 @@ void Table::initPageNum()
void Table::drawPageNum()
{
pageNumtext = "";
pageNumtext+= std::to_string(currentPage);
pageNumtext += std::to_string(currentPage);
pageNumtext += "页/共";
pageNumtext += std::to_string(totalPages);
pageNumtext += "";
@@ -229,12 +225,11 @@ void Table::drawPageNum()
if (StellarX::FillMode::Null == tableFillMode)
pageNum->setTextdisap(true);
pageNum->draw();
}
void Table::drawButton()
{
if ((nullptr == prevButton || nullptr == nextButton)|| isNeedButtonAndPageNum)
if ((nullptr == prevButton || nullptr == nextButton) || isNeedButtonAndPageNum)
initButton();
this->prevButton->textStyle = this->textStyle;
@@ -247,7 +242,6 @@ void Table::drawButton()
this->nextButton->setDirty(true);
prevButton->draw();
nextButton->draw();
}
void Table::setX(int x)
@@ -283,7 +277,8 @@ void Table::setWidth(int width)
if (remainder > 0) {
change += 1;
remainder -= 1;
} else if (remainder < 0) {
}
else if (remainder < 0) {
change -= 1;
remainder += 1;
}
@@ -399,10 +394,13 @@ void Table::draw()
restBackground();
// 绘制表头
dX = x;
dY = y;
//dX = x;
//dY = y;
if(isNeedDrawHeaders)
{
drawHeader();
this->isNeedDrawHeaders = false;
}
// 绘制当前页
drawTable();
// 绘制页码标签
@@ -412,7 +410,6 @@ void Table::draw()
if (this->isShowPageButton)
drawButton();
// 恢复绘图状态
restoreStyle();
dirty = false; // 标记不需要重绘
@@ -421,14 +418,14 @@ void Table::draw()
bool Table::handleEvent(const ExMessage& msg)
{
if(!show)return false;
if (!show)return false;
bool consume = false;
if(!this->isShowPageButton)
if (!this->isShowPageButton)
return consume;
else
{
if(prevButton)consume = prevButton->handleEvent(msg);
if (nextButton&&!consume)
if (prevButton)consume = prevButton->handleEvent(msg);
if (nextButton && !consume)
consume = nextButton->handleEvent(msg);
}
if (dirty)
@@ -446,7 +443,7 @@ void Table::setHeaders(std::initializer_list<std::string> headers)
dirty = true;
}
void Table::setData( std::vector<std::string> data)
void Table::setData(std::vector<std::string> data)
{
if (data.size() < headers.size())
for (int i = 0; data.size() <= headers.size(); i++)
@@ -459,12 +456,12 @@ void Table::setData( std::vector<std::string> data)
dirty = true;
}
void Table::setData( std::initializer_list<std::vector<std::string>> data)
void Table::setData(std::initializer_list<std::vector<std::string>> data)
{
for (auto lis : data)
if (lis.size() < headers.size())
{
for (size_t i = lis.size(); i< headers.size(); i++)
for (size_t i = lis.size(); i < headers.size(); i++)
lis.push_back("");
this->data.push_back(lis);
}
@@ -538,6 +535,31 @@ void Table::setTableBorderWidth(int width)
this->dirty = true;
}
void Table::clearHeaders()
{
this->headers.clear();
isNeedCellSize = true; // 标记需要重新计算单元格尺寸
isNeedDrawHeaders = true; // 标记需要重新绘制表头
isNeedButtonAndPageNum = true;// 标记需要重新计算翻页按钮和页码信息
dirty = true;
}
void Table::clearData()
{
this->data.clear();
this->currentPage = 1;
this->totalPages = 1;
isNeedCellSize = true; // 标记需要重新计算单元格尺寸
isNeedButtonAndPageNum = true;// 标记需要重新计算翻页按钮和页码信息
dirty = true;
}
void Table::resetTable()
{
clearHeaders();
clearData();
}
void Table::onWindowResize()
{
Control::onWindowResize(); // 先处理自己
@@ -616,5 +638,3 @@ int Table::getTableHeight() const
{
return 0;
}

View File

@@ -1,9 +1,8 @@
// TextBox.cpp
#include "TextBox.h"
TextBox::TextBox(int x, int y, int width, int height, std::string text, StellarX::TextBoxmode mode, StellarX::ControlShape shape)
:Control(x,y,width,height),text(text), mode(mode), shape(shape)
:Control(x, y, width, height), text(text), mode(mode), shape(shape)
{
this->id = "TextBox";
}
@@ -25,8 +24,22 @@ void TextBox::draw()
settextcolor(textStyle.color);
setbkmode(TRANSPARENT);
int text_width = textwidth(LPCTSTR(text.c_str()));
int text_height = textheight(LPCTSTR(text.c_str()));
int text_width = 0;
int text_height = 0;
std::string pwdText;
if (StellarX::TextBoxmode::PASSWORD_MODE == mode)
{
for (size_t i = 0; i < text.size(); ++i)
pwdText += '*';
text_width = textwidth(LPCTSTR(pwdText.c_str()));
text_height = textheight(LPCTSTR(pwdText.c_str()));
}
else
{
text_width = textwidth(LPCTSTR(text.c_str()));
text_height = textheight(LPCTSTR(text.c_str()));
}
if ((saveBkX != this->x) || (saveBkY != this->y) || (!hasSnap) || (saveWidth != this->width) || (saveHeight != this->height) || !saveBkImage)
saveBackground(this->x, this->y, this->width, this->height);
@@ -36,26 +49,29 @@ void TextBox::draw()
switch (shape)
{
case StellarX::ControlShape::RECTANGLE:
fillrectangle(x,y,x+width,y+height);//有边框填充矩形
outtextxy(x + 10, (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
fillrectangle(x, y, x + width, y + height);//有边框填充矩形
StellarX::TextBoxmode::PASSWORD_MODE == mode ? outtextxy(x + 10, (y + (height - text_height) / 2), LPCTSTR(pwdText.c_str()))
: outtextxy(x + 10, (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
break;
case StellarX::ControlShape::B_RECTANGLE:
solidrectangle(x, y, x + width, y + height);//无边框填充矩形
outtextxy(x + 10, (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
StellarX::TextBoxmode::PASSWORD_MODE == mode ? outtextxy(x + 10, (y + (height - text_height) / 2), LPCTSTR(pwdText.c_str()))
: outtextxy(x + 10, (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
break;
case StellarX::ControlShape::ROUND_RECTANGLE:
fillroundrect(x, y, x + width, y + height, rouRectangleSize.ROUND_RECTANGLEwidth, rouRectangleSize.ROUND_RECTANGLEheight);//有边框填充圆角矩形
outtextxy(x + 10, (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
StellarX::TextBoxmode::PASSWORD_MODE == mode ? outtextxy(x + 10, (y + (height - text_height) / 2), LPCTSTR(pwdText.c_str()))
:outtextxy(x + 10, (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
break;
case StellarX::ControlShape::B_ROUND_RECTANGLE:
solidroundrect(x, y, x + width, y + height, rouRectangleSize.ROUND_RECTANGLEwidth, rouRectangleSize.ROUND_RECTANGLEheight);//无边框填充圆角矩形
outtextxy(x + 10, (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
StellarX::TextBoxmode::PASSWORD_MODE == mode ? outtextxy(x + 10, (y + (height - text_height) / 2), LPCTSTR(pwdText.c_str()))
:outtextxy(x + 10, (y + (height - text_height) / 2), LPCTSTR(text.c_str()));
break;
}
restoreStyle();
dirty = false; //标记不需要重绘
}
}
bool TextBox::handleEvent(const ExMessage& msg)
@@ -77,11 +93,11 @@ bool TextBox::handleEvent(const ExMessage& msg)
if (hover && msg.message == WM_LBUTTONUP)
{
click = true;
if(StellarX::TextBoxmode::INPUT_MODE == mode)
if (StellarX::TextBoxmode::INPUT_MODE == mode)
{
char* temp = new char[maxCharLen + 1];
dirty = InputBox(temp, (int)maxCharLen, "输入框", NULL, text.c_str(), NULL, NULL, false);
if(dirty)text = temp;
dirty = InputBox(temp, (int)maxCharLen+1, "输入框", NULL, text.c_str(), NULL, NULL, false);
if (dirty)text = temp;
delete[] temp;
temp = nullptr;
consume = true;
@@ -92,6 +108,15 @@ bool TextBox::handleEvent(const ExMessage& msg)
InputBox(NULL, (int)maxCharLen, "输出框(输入无效!)", NULL, text.c_str(), NULL, NULL, false);
consume = true;
}
else if (StellarX::TextBoxmode::PASSWORD_MODE == mode)
{
char* temp = new char[maxCharLen + 1];
dirty = InputBox(temp, (int)maxCharLen+1, "输入框\n不可见输入,覆盖即可", NULL, NULL, NULL, NULL, false);
if (dirty)text = temp;
delete[] temp;
temp = nullptr;
consume = true;
}
flushmessage(EX_MOUSE | EX_KEY);
}
if (dirty)
@@ -150,7 +175,7 @@ void TextBox::setTextBoxBk(COLORREF color)
void TextBox::setText(std::string text)
{
if(text.size() > maxCharLen)
if (text.size() > maxCharLen)
text = text.substr(0, maxCharLen);
this->text = text;
this->dirty = true;
@@ -161,5 +186,3 @@ std::string TextBox::getText() const
{
return this->text;
}

View File

@@ -441,7 +441,6 @@ int Window::runEventLoop()
}
EndBatchDraw();
needredraw = false;
}
// —— 统一收口needResizeDirty 为真时执行一次性重绘)——
if (needResizeDirty)
@@ -705,7 +704,6 @@ void Window::pumpResizeIfNeeded()
{
setbkcolor(wBkcolor);
cleardevice();
}
width = rc.right - rc.left; height = rc.bottom - rc.top;
@@ -818,4 +816,3 @@ void Window::adaptiveLayout(std::unique_ptr<Control>& c, const int finalH, const
}
c->onWindowResize();
}