Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 53dc237e46 | |||
| 46febdb973 | |||
| f05962954f |
@@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
[中文文档](CHANGELOG.md)
|
||||
|
||||
## [v2.3.1] - 2025-11-30
|
||||
|
||||
## 🙏 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.
|
||||
- Sincere thanks to every user who reports bugs—your feedback makes StellarX more stable and robust.
|
||||
|
||||
### ⚙️ Changes
|
||||
|
||||
- **Dialog Background Snapshot Mechanism:** `Dialog` no longer captures and destroys its own snapshot. The methods for capturing and restoring snapshots have been **removed** from `Dialog`, and the base class `Canvas` now handles all snapshot management. The `draw` method in `Dialog` no longer deals with snapshots.
|
||||
- **Timing Adjustment for Window and Control Redrawing on Size Change:** In the main event loop, when the window size changes, control sizes are processed first. Old snapshots are discarded, followed by the redrawing of the window with the new size, and finally, the controls are redrawn.
|
||||
|
||||
### ✅ Fixes
|
||||
|
||||
- **Child Control Coordinate Transformation in Nested Containers:** `Canvas` overrides the base class's `setX/Y` methods to synchronize the global coordinates of child controls when the parent container's global coordinates change. This prevents child controls in nested containers from incorrectly treating the container's relative coordinates as global coordinates.
|
||||
- **Solid Background Window Title Not Applied:** In the `Window`'s `draw()` method, the window title is forcibly set to ensure that the title passed when creating the window is applied correctly, preventing the issue where the window title doesn't take effect.
|
||||
- **Tab Control Background Residue when Changing Coordinates:** In the overridden `setX/Y` methods of `TabControl`, all tabs and their child controls are forced to discard snapshots when the tab's coordinates change. This prevents background residue caused by incorrect snapshot restoration order after modifying coordinates.
|
||||
- **Table Page Number Label and Pagination Button Misalignment when Changing Coordinates:** In `Table`'s `setX/Y`, the `isNeedButtonAndPageNum` state is reset to `true`, ensuring that the pagination button and page number label are recalculated and remain centered directly beneath the table when redrawn.
|
||||
|
||||
## [v2.3.0] - 2025-11-18
|
||||
|
||||
### ✨ Added
|
||||
|
||||
24
CHANGELOG.md
24
CHANGELOG.md
@@ -7,6 +7,30 @@ StellarX 项目所有显著的变化都将被记录在这个文件中。
|
||||
|
||||
[English document](CHANGELOG.en.md)
|
||||
|
||||
## [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或者分享自己用星垣做的界面,我们将认真阅读并收录鸣谢
|
||||
- 真诚的感谢每一位反馈BUG的用户,你们的反馈将使星垣更加稳定和健壮
|
||||
|
||||
### ✨ 新增
|
||||
|
||||
新增一个登录界面Demo在主仓库**examples/**目录下
|
||||
|
||||
### ⚙️ 变更
|
||||
|
||||
- **Dialog背景快照机制:**`Dialog`不在自己抓取和销毁快照,**删除**重载的抓取和恢复快照的方法,完全交由基类`Canvas`处理,`Dialog`的`draw`方法中不在处理快照
|
||||
- **窗口变化重绘时控件和窗口重绘的时机调整:**主事件循环中窗口大小发生变化时先处理控件尺寸,并回贴和释放旧快照,然后再重绘新尺寸窗口,最后绘制控件
|
||||
|
||||
### ✅ 修复
|
||||
|
||||
- **容器嵌套时子控件坐标转化:**`Canvas`重写了基类的`setX/Y`方法,在容器全局坐标发生变化时同步修改子控件的全局坐标,防止在容器嵌套时,容器的相对坐标被子控件当成全局坐标处理
|
||||
- **纯色背景窗口标题不生效:**在`Window`的`draw()`方法中强制设置窗口标题,以防止,创建窗口时传递的窗口标题不生效
|
||||
- **选项卡控件页签打开时动态改变坐标背景残留:**在`TabControl`重写的`setX/Y`方法中,当选项卡的坐标发生变化时强制让所有页签以及页和子控件丢一次快照,防止,在修改坐标后因,快照恢复顺序引起的选项卡激活页残留
|
||||
- **Table动态改变坐标页码标签和翻页按钮错乱:**在`Table`控件的`setX/Y`中重置`isNeedButtonAndPageNum`状态为真,在绘制时重新计算翻页按钮和页码标签的位置以保持在表格正下方居中位置显示
|
||||
|
||||
## [v2.3.0] - 2025 - 11 - 18
|
||||
|
||||
### ✨ 新增
|
||||
|
||||
27
README.md
27
README.md
@@ -12,8 +12,8 @@
|
||||

|
||||
[](https://github.com/Ysm-04/StellarX)
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
@@ -30,25 +30,28 @@
|
||||
|
||||
---
|
||||
|
||||
## 🆕V2.3.0——重要更新
|
||||
## ==公告==
|
||||
|
||||
**本版本是一次重大更新,增加了响应式布局系统,由静态布局转变为动态布局,并且彻底修复了之前存在的由重入重绘导致的概率出现的渲染错乱问题**
|
||||
## 🙏 鸣谢
|
||||
|
||||
- **优化窗口尺寸调节机制**:重构 `WndProcThunk`、`runEventLoop` 和 `pumpResizeIfNeeded`,统一记录尺寸变化并在事件循环末尾集中重绘,避免重复重绘导致的抖动和顺序错乱。
|
||||
- 感谢用户 [@To-KongBai](https://github.com/To-KongBai) 提供稳定复现步骤与关键现象对比(容器嵌套孙控件坐标转换问题),帮助我们快速确认多容器嵌套时的控件坐标转换问题并修复。([Issues#6](https://github.com/Ysm-04/StellarX/issues/6))
|
||||
- 在即将上线的官网中(ICP备案中)我们计划加入一个贡献者鸣谢墙,欢迎各位用户反馈BUG或者分享自己用星垣做的界面,我们将认真阅读并收录鸣谢
|
||||
- 真诚的感谢每一位反馈BUG的用户,你们的反馈将使星垣更加稳定和健壮
|
||||
|
||||
- **新增对话框尺寸调度接口**:引入 `Window::scheduleResizeFromModal()` 与 `pumpResizeIfNeeded()` 的组合,模态对话框在拉伸期间也可通知父窗口更新尺寸。底层控件将在统一收口时重新布局,而对话框自身保持尺寸不变。
|
||||
---
|
||||
|
||||
- **自适应布局改进**:内部新增 `adaptiveLayout()` 函数,按照锚点重新计算控件位置和尺寸,使双锚定(左右或上下)控件随窗口变化自适应伸缩。
|
||||
## 🆕V2.3.1——重要更新
|
||||
|
||||
- **修复模态对话框拉伸问题**:解决模态对话框打开时,窗口拉伸导致底层控件无法根据锚点更新的位置和尺寸的问题;同时避免对话框反复重绘导致的残影。
|
||||
### ✨ 新增
|
||||
|
||||
- **进一步解决绘制顺序错乱**:拉伸过程中采用 `ValidateRect` 替代 `InvalidateRect`,确保窗口仅在一次统一收口绘制后标记为有效,杜绝系统再次触发 `WM_PAINT` 造成重入。
|
||||
新增一个登录界面Demo在主仓库**examples/**目录下
|
||||
|
||||
- 其他修复:修正表格和对话框背景快照某些边界情况下的更新不及时问题。
|
||||
### ⚙️ 变更
|
||||
|
||||

|
||||
- **Dialog背景快照机制:**`Dialog`不在自己抓取和销毁快照,**删除**重载的抓取和恢复快照的方法,完全交由基类`Canvas`处理,`Dialog`的`draw`方法中不在处理快照
|
||||
- **窗口变化重绘时控件和窗口重绘的时机调整:**主事件循环中窗口大小发生变化时先处理控件尺寸,并回贴和释放旧快照,然后再重绘新尺寸窗口,最后绘制控件
|
||||
|
||||

|
||||
本次针对用户反馈和已知内容进行了一些修复……
|
||||
|
||||
详细变更请参阅[更新日志](CHANGELOG.md)
|
||||
|
||||
|
||||
127
examples/登录界面/LoginInterface.cpp
Normal file
127
examples/登录界面/LoginInterface.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
// 本Demo基于 StellarX 构建,轻量级的 Windows GUI 框架。
|
||||
#include"StellarX.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
Window win(1300, 800, NULL, RGB(255, 255, 0), "记账管理系统");
|
||||
|
||||
/*********登录界面***********/
|
||||
//标签
|
||||
std::unique_ptr<Label> logIn_label[3];
|
||||
Label* p[3];
|
||||
logIn_label[0] = std::make_unique<Label>(90, 150, "欢迎使用餐馆记账管理系统");
|
||||
logIn_label[1] = std::make_unique<Label>(400, 300, "账号");
|
||||
logIn_label[2] = std::make_unique<Label>(400, 400, "密码");
|
||||
p[0] = logIn_label[0].get();
|
||||
for (auto& log : logIn_label)
|
||||
{
|
||||
log->setTextdisap(true);
|
||||
log->setLayoutMode(StellarX::LayoutMode::AnchorToEdges);
|
||||
log->textStyle.lpszFace = "华文行楷";
|
||||
}
|
||||
logIn_label[0]->textStyle.nHeight = 100;
|
||||
logIn_label[0]->setAnchor(StellarX::Anchor::Top, StellarX::Anchor::NoAnchor);
|
||||
logIn_label[1]->textStyle.nHeight = 50;
|
||||
logIn_label[1]->setAnchor(StellarX::Anchor::Bottom, StellarX::Anchor::NoAnchor);
|
||||
logIn_label[2]->textStyle.nHeight = 50;
|
||||
logIn_label[2]->setAnchor(StellarX::Anchor::Bottom, StellarX::Anchor::NoAnchor);
|
||||
|
||||
//输入框
|
||||
std::unique_ptr<TextBox> logIn_textBox[2];
|
||||
TextBox* logIn_textBox_ptr[2];
|
||||
logIn_textBox[0] = std::make_unique<TextBox>(500, 295, 450, 50);
|
||||
logIn_textBox[1] = std::make_unique<TextBox>(500, 395, 450, 50);
|
||||
logIn_textBox_ptr[0] = logIn_textBox[0].get();
|
||||
logIn_textBox_ptr[1] = logIn_textBox[1].get();
|
||||
for (auto& tb : logIn_textBox)
|
||||
{
|
||||
tb->setLayoutMode(StellarX::LayoutMode::AnchorToEdges);
|
||||
tb->setAnchor(StellarX::Anchor::Bottom, StellarX::Anchor::NoAnchor);
|
||||
tb->setMaxCharLen(15);
|
||||
}
|
||||
//按钮
|
||||
std::unique_ptr<Button> logIn_Button[2];
|
||||
Button* logIn_Button_ptr[2];
|
||||
logIn_Button[0] = std::make_unique<Button>(350, 500, 300, 50, "管理员登录");
|
||||
logIn_Button[1] = std::make_unique<Button>(750, 500, 300, 50, "操作员登录");
|
||||
logIn_Button_ptr[0] = logIn_Button[0].get();
|
||||
logIn_Button_ptr[1] = logIn_Button[1].get();
|
||||
for (auto& b : logIn_Button)
|
||||
{
|
||||
b->setLayoutMode(StellarX::LayoutMode::AnchorToEdges);
|
||||
b->setAnchor(StellarX::Anchor::Bottom, StellarX::Anchor::NoAnchor);
|
||||
}
|
||||
//log画布
|
||||
auto log_Canvas = std::make_unique<Canvas>(0, 0, 1300, 800);
|
||||
Canvas* log_Canvas_ptr = log_Canvas.get();
|
||||
log_Canvas_ptr->setCanvasfillMode(StellarX::FillMode::Null);
|
||||
log_Canvas_ptr->setShape(StellarX::ControlShape::B_RECTANGLE);
|
||||
log_Canvas_ptr->setLayoutMode(StellarX::LayoutMode::AnchorToEdges);
|
||||
log_Canvas_ptr->setAnchor(StellarX::Anchor::Bottom, StellarX::Anchor::Top);
|
||||
|
||||
//将log界面控价加入logCanvas统一管理
|
||||
for (auto& b : logIn_Button)
|
||||
log_Canvas_ptr->addControl(std::move(b));
|
||||
for (auto& tb : logIn_textBox)
|
||||
log_Canvas_ptr->addControl(std::move(tb));
|
||||
for (auto& la : logIn_label)
|
||||
log_Canvas_ptr->addControl(std::move(la));
|
||||
|
||||
/**************业务UI****************/
|
||||
|
||||
auto tabControl = std::make_unique<TabControl>(10, 10, 1280, 780);
|
||||
auto tabControl_ptr = tabControl.get();
|
||||
tabControl_ptr->setIsVisible(false);
|
||||
tabControl_ptr->setCanvasfillMode(StellarX::FillMode::Null);
|
||||
tabControl_ptr->setShape(StellarX::ControlShape::ROUND_RECTANGLE);
|
||||
tabControl_ptr->setTabPlacement(StellarX::TabPlacement::Left);
|
||||
tabControl_ptr->setTabBarHeight(100);
|
||||
//添加页签及页
|
||||
auto tabP = std::make_pair(std::make_unique<Button>(0, 0, 100, 100, "点餐"), std::make_unique<Canvas>(0, 0, 1290, 790));
|
||||
tabP.second->setCanvasfillMode(StellarX::FillMode::Null);
|
||||
tabP.second->setShape(StellarX::ControlShape::ROUND_RECTANGLE);
|
||||
|
||||
tabControl_ptr->add(std::move(tabP));
|
||||
|
||||
/*------------login事件-------------*/
|
||||
//管理员登录按钮事件
|
||||
logIn_Button_ptr[0]->setOnClickListener([&p, &tabControl_ptr, &log_Canvas_ptr, &logIn_textBox_ptr, &win]()
|
||||
{
|
||||
if ("\0" == logIn_textBox_ptr[0]->getText() || "\0" == logIn_textBox_ptr[1]->getText())
|
||||
{
|
||||
if ("\0" == logIn_textBox_ptr[0]->getText())logIn_textBox_ptr[0]->setTextBoxBk(RGB(255, 0, 0));
|
||||
if ("\0" == logIn_textBox_ptr[1]->getText())logIn_textBox_ptr[1]->setTextBoxBk(RGB(255, 0, 0));
|
||||
std::cout << "\a";
|
||||
StellarX::MessageBox::showModal(win, "账号或密码不能为空!", "提示");
|
||||
}
|
||||
else
|
||||
{
|
||||
log_Canvas_ptr->setIsVisible(false);
|
||||
tabControl_ptr->setIsVisible(true);
|
||||
win.draw("image\\bk1.jpg");
|
||||
}
|
||||
});
|
||||
//操作员登录按钮事件
|
||||
logIn_Button_ptr[1]->setOnClickListener([&tabControl_ptr, &log_Canvas_ptr, &logIn_textBox_ptr, &win]()
|
||||
{
|
||||
if ("\0" == logIn_textBox_ptr[0]->getText() || "\0" == logIn_textBox_ptr[1]->getText())
|
||||
{
|
||||
if ("\0" == logIn_textBox_ptr[0]->getText())logIn_textBox_ptr[0]->setTextBoxBk(RGB(255, 0, 0));
|
||||
if ("\0" == logIn_textBox_ptr[1]->getText())logIn_textBox_ptr[1]->setTextBoxBk(RGB(255, 0, 0));
|
||||
std::cout << "\a";
|
||||
StellarX::MessageBox::showModal(win, "账号或密码不能为空!", "提示");
|
||||
}
|
||||
else
|
||||
{
|
||||
log_Canvas_ptr->setIsVisible(false);
|
||||
tabControl_ptr->setIsVisible(true);
|
||||
win.draw("image\\bk1.jpg");
|
||||
}
|
||||
});
|
||||
|
||||
win.addControl(std::move(log_Canvas));
|
||||
win.addControl(std::move(tabControl));
|
||||
win.draw("image\\bk1.jpg");
|
||||
|
||||
return win.runEventLoop();
|
||||
}
|
||||
BIN
examples/登录界面/image/bk1.jpg
Normal file
BIN
examples/登录界面/image/bk1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 MiB |
BIN
examples/登录界面/image/lo_bk2.jpg
Normal file
BIN
examples/登录界面/image/lo_bk2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.0 KiB |
BIN
examples/登录界面/image/星垣logo.png
Normal file
BIN
examples/登录界面/image/星垣logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
@@ -25,6 +25,9 @@
|
||||
#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
|
||||
{
|
||||
|
||||
@@ -41,6 +41,9 @@ public:
|
||||
Canvas(int x, int y, int width, int height);
|
||||
~Canvas() {}
|
||||
|
||||
void setX(int x)override;
|
||||
void setY(int y)override;
|
||||
|
||||
//绘制容器及其子控件
|
||||
void draw() override;
|
||||
bool handleEvent(const ExMessage& msg) override;
|
||||
@@ -68,5 +71,6 @@ public:
|
||||
private:
|
||||
//用来检查对话框是否模态,此控件不做实现
|
||||
bool model() const override { return false; };
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ protected:
|
||||
/* == 布局模式 == */
|
||||
StellarX::LayoutMode layoutMode = StellarX::LayoutMode::Fixed; // 布局模式
|
||||
StellarX::Anchor anchor_1 = StellarX::Anchor::Top; // 锚点
|
||||
StellarX::Anchor anchor_2 = StellarX::Anchor::Left; // 锚点
|
||||
StellarX::Anchor anchor_2 = StellarX::Anchor::Right; // 锚点
|
||||
|
||||
/* == 背景快照 == */
|
||||
IMAGE* saveBkImage = nullptr;
|
||||
@@ -118,8 +118,8 @@ public:
|
||||
int getLocalRight() const { return localx + localWidth; }
|
||||
int getLocalBottom() const { return localy + localHeight; }
|
||||
|
||||
void setX(int x) { this->x = x; dirty = true; }
|
||||
void setY(int y) { this->y = y; dirty = true; }
|
||||
virtual void setX(int x) { this->x = x; dirty = true; }
|
||||
virtual void setY(int y) { this->y = y; dirty = true; }
|
||||
virtual void setWidth(int width) { this->width = width; dirty = true; }
|
||||
virtual void setHeight(int height) { this->height = height; dirty = true; }
|
||||
public:
|
||||
@@ -142,7 +142,7 @@ public:
|
||||
virtual bool model()const = 0;
|
||||
//布局
|
||||
void setLayoutMode(StellarX::LayoutMode layoutMode_);
|
||||
void steAnchor(StellarX::Anchor anchor_1, StellarX::Anchor anchor_2);
|
||||
void setAnchor(StellarX::Anchor anchor_1, StellarX::Anchor anchor_2);
|
||||
StellarX::Anchor getAnchor_1() const;
|
||||
StellarX::Anchor getAnchor_2() const;
|
||||
StellarX::LayoutMode getLayoutMode() const;
|
||||
|
||||
@@ -123,9 +123,6 @@ private:
|
||||
void getTextSize();
|
||||
//初始化对话框尺寸
|
||||
void initDialogSize();
|
||||
void saveBackground(int x, int y, int w, int h)override;
|
||||
|
||||
void restBackground()override;
|
||||
void addControl(std::unique_ptr<Control> control);
|
||||
|
||||
// 清除所有控件
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*******************************************************************************
|
||||
* @文件: StellarX.h
|
||||
* @摘要: 星垣(StellarX) GUI框架 - 主包含头文件
|
||||
* @版本: v2.3.0
|
||||
* @版本: v2.3.1
|
||||
* @描述:
|
||||
* 一个为Windows平台打造的轻量级、模块化C++ GUI框架。
|
||||
* 基于EasyX图形库,提供简洁易用的API和丰富的控件。
|
||||
@@ -12,6 +12,7 @@
|
||||
* @作者: 我在人间做废物
|
||||
* @邮箱: [3150131407@qq.com] | [ysm3150131407@gmail.com]
|
||||
* @仓库: [https://github.com/Ysm-04/StellarX]
|
||||
* @官网:即将上线,敬请期待
|
||||
*
|
||||
* @许可证: MIT License
|
||||
* @版权: Copyright (c) 2025 我在人间做废物
|
||||
|
||||
@@ -40,6 +40,9 @@ public:
|
||||
TabControl(int x,int y,int width,int height);
|
||||
~TabControl();
|
||||
|
||||
void setX(int x)override;
|
||||
void setY(int y)override;
|
||||
|
||||
void draw() override;
|
||||
bool handleEvent(const ExMessage& msg) override;
|
||||
|
||||
|
||||
@@ -99,6 +99,8 @@ private:
|
||||
bool model() const override { return false; };
|
||||
public:
|
||||
StellarX::ControlText textStyle; // 文本样式
|
||||
void setX(int x) override;
|
||||
void setY(int y) override;
|
||||
void setWidth(int width) override;
|
||||
void setHeight(int height) override;
|
||||
public:
|
||||
|
||||
@@ -224,7 +224,7 @@ void Button::draw()
|
||||
//设置按钮填充模式
|
||||
setfillstyle((int)buttonFillMode, (int)buttonFillIma, buttonFileIMAGE);
|
||||
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 + bordWith), (this->height + bordHeight));
|
||||
// 恢复背景(清除旧内容)
|
||||
restBackground();
|
||||
//根据按钮形状绘制
|
||||
|
||||
@@ -12,6 +12,28 @@ Canvas::Canvas(int x, int y, int width, int height)
|
||||
this->id = "Canvas";
|
||||
}
|
||||
|
||||
void Canvas::setX(int x)
|
||||
{
|
||||
this->x = x;
|
||||
for (auto& c : controls)
|
||||
{
|
||||
c->onWindowResize();
|
||||
c->setX(c->getLocalX() + this->x);
|
||||
}
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void Canvas::setY(int y)
|
||||
{
|
||||
this->y = y;
|
||||
for (auto& c : controls)
|
||||
{
|
||||
c->onWindowResize();
|
||||
c->setY(c->getLocalY() + this->y);
|
||||
}
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void Canvas::clearAllControls()
|
||||
{
|
||||
controls.clear();
|
||||
@@ -36,21 +58,22 @@ void Canvas::draw()
|
||||
// 在绘制画布之前,先恢复并更新背景快照:
|
||||
// 1. 如果已有快照,则先回贴旧快照以清除之前的内容。
|
||||
// 2. 当坐标或尺寸变化,或缓存图像无效时,丢弃旧快照并重新抓取新的背景。
|
||||
int margin = canvaslinewidth > 1 ? canvaslinewidth : 1;
|
||||
if (hasSnap)
|
||||
{
|
||||
// 恢复旧快照,清除上一次绘制
|
||||
restBackground();
|
||||
// 如果位置或尺寸变了,或没有有效缓存,则重新抓取
|
||||
if (!saveBkImage || saveBkX != this->x || saveBkY != this->y || saveWidth != this->width || saveHeight != this->height)
|
||||
if (!saveBkImage || saveBkX != this->x - margin || saveBkY != this->y - margin || saveWidth != this->width + margin * 2 || saveHeight != this->height + margin * 2)
|
||||
{
|
||||
discardBackground();
|
||||
saveBackground(this->x, this->y, this->width, this->height);
|
||||
saveBackground(this->x - margin, this->y - margin, this->width + margin * 2, this->height + margin * 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 首次绘制或没有快照时直接抓取背景
|
||||
saveBackground(this->x, this->y, this->width, this->height);
|
||||
saveBackground(this->x- margin, this->y- margin, this->width + margin*2, this->height + margin*2);
|
||||
}
|
||||
// 再次恢复最新快照,确保绘制区域干净
|
||||
restBackground();
|
||||
@@ -98,6 +121,7 @@ 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);
|
||||
@@ -363,3 +387,5 @@ void Canvas::requestRepaint(Control* parent)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ void Control::setLayoutMode(StellarX::LayoutMode layoutMode_)
|
||||
{
|
||||
this->layoutMode = layoutMode_;
|
||||
}
|
||||
void Control::steAnchor(StellarX::Anchor anchor_1, StellarX::Anchor anchor_2)
|
||||
void Control::setAnchor(StellarX::Anchor anchor_1, StellarX::Anchor anchor_2)
|
||||
{
|
||||
this->anchor_1 = anchor_1;
|
||||
this->anchor_2 = anchor_2;
|
||||
@@ -144,6 +144,7 @@ void Control::discardBackground()
|
||||
{
|
||||
if (saveBkImage)
|
||||
{
|
||||
restBackground();
|
||||
delete saveBkImage;
|
||||
saveBkImage = nullptr;
|
||||
}
|
||||
|
||||
@@ -41,12 +41,6 @@ void Dialog::draw()
|
||||
Canvas::setCanvasBkColor(this->backgroundColor);
|
||||
Canvas::setShape(StellarX::ControlShape::ROUND_RECTANGLE);
|
||||
|
||||
if ((saveBkX != this->x) || (saveBkY != this->y) || (!hasSnap) || (saveWidth != this->width) || (saveHeight != this->height) || !saveBkImage)
|
||||
saveBackground(this->x, this->y, this->width, this->height);
|
||||
//设置所有控件为脏状态
|
||||
/*for(auto& c :this->controls)
|
||||
c->setDirty(true);*/
|
||||
restBackground();
|
||||
Canvas::draw();
|
||||
|
||||
//绘制消息文本
|
||||
@@ -269,6 +263,7 @@ void Dialog::setInitialization(bool init)
|
||||
{
|
||||
initDialogSize();
|
||||
saveBackground((x - BorderWidth), (y - BorderWidth), (width + 2 * BorderWidth), (height + 2 * BorderWidth));
|
||||
this->dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -621,32 +616,6 @@ void Dialog::initDialogSize()
|
||||
initCloseButton(); // 初始化关闭按钮
|
||||
}
|
||||
|
||||
void Dialog::saveBackground(int x, int y, int w, int h)
|
||||
{
|
||||
if (w <= 0 || h <= 0) return;
|
||||
saveBkX = x; saveBkY = y; saveWidth = w; saveHeight = h;
|
||||
if (saveBkImage)
|
||||
{
|
||||
//尺寸变了才重建,避免反复 new/delete
|
||||
if (saveBkImage->getwidth() != w || saveBkImage->getheight() != h)
|
||||
{
|
||||
delete saveBkImage; saveBkImage = nullptr;
|
||||
}
|
||||
}
|
||||
if (!saveBkImage) saveBkImage = new IMAGE(w + BorderWidth*2, h + BorderWidth*2);
|
||||
|
||||
SetWorkingImage(nullptr); // ★抓屏幕
|
||||
getimage(saveBkImage, x - BorderWidth, y - BorderWidth, w + BorderWidth*2, h+ BorderWidth*2);
|
||||
hasSnap = true;
|
||||
}
|
||||
void Dialog::restBackground()
|
||||
{
|
||||
if (!hasSnap || !saveBkImage) return;
|
||||
// 直接回贴屏幕(与抓取一致)
|
||||
SetWorkingImage(nullptr);
|
||||
putimage(saveBkX - BorderWidth, saveBkY - BorderWidth,saveBkImage);
|
||||
}
|
||||
|
||||
void Dialog::addControl(std::unique_ptr<Control> control)
|
||||
{
|
||||
control->setParent(this);
|
||||
|
||||
@@ -162,28 +162,56 @@ TabControl::~TabControl()
|
||||
{
|
||||
}
|
||||
|
||||
void TabControl::setX(int x)
|
||||
{
|
||||
this->x = x;
|
||||
initTabBar();
|
||||
initTabPage();
|
||||
dirty = true;
|
||||
for (auto& c : controls)
|
||||
{
|
||||
c.first->onWindowResize();
|
||||
c.second->onWindowResize();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TabControl::setY(int y)
|
||||
{
|
||||
this->y = y;
|
||||
initTabBar();
|
||||
initTabPage();
|
||||
dirty = true;
|
||||
for (auto& c : controls)
|
||||
{
|
||||
c.first->onWindowResize();
|
||||
c.second->onWindowResize();
|
||||
}
|
||||
}
|
||||
|
||||
void TabControl::draw()
|
||||
{
|
||||
if (!dirty || !show)return;
|
||||
// 在绘制 TabControl 之前,先恢复并更新背景快照:
|
||||
if (hasSnap)
|
||||
{
|
||||
// 先回贴旧快照,清除之前的绘制
|
||||
restBackground();
|
||||
// 如位置或尺寸变化,丢弃旧快照并重新抓取
|
||||
if (!saveBkImage || saveBkX != this->x || saveBkY != this->y || saveWidth != this->width || saveHeight != this->height)
|
||||
{
|
||||
discardBackground();
|
||||
saveBackground(this->x, this->y, this->width, this->height);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 首次绘制时抓取背景
|
||||
saveBackground(this->x, this->y, this->width, this->height);
|
||||
}
|
||||
// 再次恢复最新背景,保证绘制区域干净
|
||||
restBackground();
|
||||
// // 在绘制 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)
|
||||
|
||||
@@ -250,6 +250,20 @@ void Table::drawButton()
|
||||
|
||||
}
|
||||
|
||||
void Table::setX(int x)
|
||||
{
|
||||
this->x = x;
|
||||
isNeedButtonAndPageNum = true;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void Table::setY(int y)
|
||||
{
|
||||
this->y = y;
|
||||
isNeedButtonAndPageNum = true;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void Table::setWidth(int width)
|
||||
{
|
||||
// 调整列宽以匹配新的表格总宽度。不修改 localWidth,避免累计误差。
|
||||
@@ -285,6 +299,7 @@ void Table::setWidth(int width)
|
||||
|
||||
void Table::setHeight(int height)
|
||||
{
|
||||
//高度不变
|
||||
}
|
||||
|
||||
Table::Table(int x, int y)
|
||||
|
||||
@@ -79,8 +79,12 @@ bool TextBox::handleEvent(const ExMessage& msg)
|
||||
click = true;
|
||||
if(StellarX::TextBoxmode::INPUT_MODE == mode)
|
||||
{
|
||||
dirty = InputBox(LPTSTR(text.c_str()), (int)maxCharLen, "输入框", NULL, text.c_str(), NULL, NULL, false);
|
||||
consume = true;
|
||||
char* temp = new char[maxCharLen + 1];
|
||||
dirty = InputBox(temp, (int)maxCharLen, "输入框", NULL, text.c_str(), NULL, NULL, false);
|
||||
if(dirty)text = temp;
|
||||
delete[] temp;
|
||||
temp = nullptr;
|
||||
consume = true;
|
||||
}
|
||||
else if (StellarX::TextBoxmode::READONLY_MODE == mode)
|
||||
{
|
||||
|
||||
@@ -243,7 +243,10 @@ void Window::draw()
|
||||
oldWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)&Window::WndProcThunk);
|
||||
procHooked = (oldWndProc != nullptr);
|
||||
}
|
||||
|
||||
if (!headline.empty())
|
||||
{
|
||||
SetWindowText(hWnd, headline.c_str());
|
||||
}
|
||||
ApplyResizableStyle(hWnd, useComposited);
|
||||
|
||||
// 关闭类样式的整窗重绘标志(减少尺寸变化时的整窗 redraw)
|
||||
@@ -470,6 +473,18 @@ int Window::runEventLoop()
|
||||
// 调整底层画布尺寸
|
||||
if (finalW != width || finalH != height)
|
||||
{
|
||||
// 批量通知控件“窗口尺寸变化”,并标记重绘
|
||||
for (auto& c : controls)
|
||||
adaptiveLayout(c, finalH, finalW);
|
||||
for (auto& d : dialogs)
|
||||
{
|
||||
if (auto dd = dynamic_cast<Dialog*>(d.get()))
|
||||
{
|
||||
dd->setDirty(true);
|
||||
dd->setInitialization(true);
|
||||
}
|
||||
}
|
||||
//重绘窗口
|
||||
Resize(nullptr, finalW, finalH);
|
||||
|
||||
// 重取一次实际客户区尺寸做确认
|
||||
@@ -499,21 +514,6 @@ int Window::runEventLoop()
|
||||
height = renderHeight;
|
||||
}
|
||||
|
||||
// 批量通知控件“窗口尺寸变化”,并标记重绘
|
||||
for (auto& c : controls)
|
||||
{
|
||||
adaptiveLayout(c,finalH,finalW);
|
||||
c->onWindowResize();
|
||||
}
|
||||
for (auto& d : dialogs)
|
||||
{
|
||||
if (auto dd = dynamic_cast<Dialog*>(d.get()))
|
||||
{
|
||||
dd->setDirty(true);
|
||||
dd->setInitialization(true);
|
||||
}
|
||||
}
|
||||
|
||||
// 统一批量绘制
|
||||
for (auto& c : controls) c->draw();
|
||||
for (auto& d : dialogs) d->draw();
|
||||
@@ -809,11 +809,13 @@ void Window::adaptiveLayout(std::unique_ptr<Control>& c, const int finalH, const
|
||||
c->setHeight(c->getLocalHeight());
|
||||
c->setY(finalH - origBottomDist - c->getHeight());
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
// 垂直无锚点:默认为顶部定位,高度固定
|
||||
c->setY(c->getLocalY());
|
||||
c->setHeight(c->getLocalHeight());
|
||||
}
|
||||
}
|
||||
c->onWindowResize();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user