initial commit

This commit is contained in:
Ysm-04
2025-09-07 00:19:40 +08:00
commit d62d8a90d6
25 changed files with 2995 additions and 0 deletions

77
.gitignore vendored Normal file
View File

@@ -0,0 +1,77 @@
# 编译生成文件
*.exe
*.ilk
*.obj
*.pdb
*.o
*.a
*.lib
*.dll
*.exp
*.so
*.dylib
# 构建目录
build/
bin/
obj/
Debug/
Release/
x64/
x86/
Win32/
# Visual Studio 文件
.vs/
*.sln
*.vcxproj
*.vcxproj.filters
*.vcxproj.user
*.suo
*.ncb
*.user
*.sdf
ipch/
*.aps
*.res
*.tlog
*.lastbuildstate
*.idb
*.pch
# CMake 生成文件
CMakeFiles/
CMakeCache.txt
cmake_install.cmake
Makefile
*.cmake
*.cmake.*
CTestTestfile.cmake
Testing/
_deps/
# 文档生成
docs/html/
docs/latex/
docs/man/
docs/rtf/
docs/xml/
# 临时文件
*.tmp
*.temp
*.log
*.swp
*.swo
# EasyX 临时文件
*.jpg
*.bmp
*.png
*.tga
# 其他
.DS_Store
Thumbs.db
ehthumbs.db
Desktop.ini

28
CHANGELOG.md Normal file
View File

@@ -0,0 +1,28 @@
# 更新日志
StellarX 项目所有显著的变化都将被记录在这个文件中。
格式基于 [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
并且本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
## [1.0.0] - 2025-09-06
### 新增
- StellarX 框架的第一个稳定版本
- 完整的控件库:按钮、标签、文本框、画布、表格和窗口
- 基于 CMake 的构建系统
- 详细的文档和示例代码
- **明确声明:本框架专为 Windows 平台设计**
### 核心特性
- 模块化设计,遵循 SOLID 原则
- 统一的控件接口draw() 和 handleEvent()
- 支持多种控件形状和样式
- 自定义事件处理回调
- 轻量级设计,无外部依赖
## [0.1.0] - 2025-08-15
### 新增
- 初始项目结构和核心架构
- Control 基类和基本事件处理系统
- 基础示例和文档设置

130
CMakeLists.txt Normal file
View File

@@ -0,0 +1,130 @@
cmake_minimum_required(VERSION 3.15)
project(StellarX VERSION 1.0.0 LANGUAGES CXX)
# 设置C++标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Windows特定设置
if(WIN32)
add_definitions(-DWIN32 -D_WINDOWS)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
# 设置Windows子系统
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS")
endif()
# 设置输出目录
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# 包含目录
include_directories(include)
# Windows API库
if(WIN32)
find_library(GDI32_LIBRARY gdi32)
find_library(USER32_LIBRARY user32)
find_library(KERNEL32_LIBRARY kernel32)
set(WIN32_LIBS ${GDI32_LIBRARY} ${USER32_LIBRARY} ${KERNEL32_LIBRARY})
endif()
# 创建库
file(GLOB_RECURSE SOURCES "src/*.cpp")
add_library(StellarX STATIC ${SOURCES})
# 链接Windows库
if(WIN32)
target_link_libraries(StellarX ${WIN32_LIBS})
endif()
# 设置库属性
set_target_properties(StellarX PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION 1
PUBLIC_HEADER "include/StellarX/StellarX.h"
OUTPUT_NAME "StellarX"
)
# 安装规则
install(DIRECTORY include/StellarX DESTINATION include)
install(TARGETS StellarX
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
PUBLIC_HEADER DESTINATION include/StellarX
)
# 示例程序
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/examples)
file(GLOB EXAMPLE_SOURCES "examples/*.cpp")
foreach(example_source ${EXAMPLE_SOURCES})
get_filename_component(example_name ${example_source} NAME_WE)
add_executable(${example_name} ${example_source})
target_link_libraries(${example_name} StellarX ${WIN32_LIBS})
# 设置Windows子系统
if(WIN32)
set_target_properties(${example_name} PROPERTIES
LINK_FLAGS "/SUBSYSTEM:WINDOWS"
)
endif()
# 安装示例
install(TARGETS ${example_name} DESTINATION bin)
endforeach()
endif()
# 文档生成选项
option(BUILD_DOCS "Build documentation" OFF)
if(BUILD_DOCS)
find_package(Doxygen)
if(Doxygen_FOUND)
set(DOXYGEN_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/docs)
set(DOXYGEN_USE_MDFILE_AS_MAINPAGE ${CMAKE_CURRENT_SOURCE_DIR}/README.md)
set(DOXYGEN_PROJECT_NAME "StellarX GUI Framework")
set(DOXYGEN_PROJECT_NUMBER ${PROJECT_VERSION})
set(DOXYGEN_PROJECT_BRIEF "A lightweight, modular C++ GUI framework for Windows")
set(DOXYGEN_INPUT ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src)
set(DOXYGEN_RECURSIVE YES)
set(DOXYGEN_EXTRACT_ALL YES)
set(DOXYGEN_EXTRACT_PRIVATE YES)
set(DOXYGEN_EXTRACT_STATIC YES)
set(DOXYGEN_SOURCE_BROWSER YES)
set(DOXYGEN_GENERATE_TREEVIEW YES)
set(DOXYGEN_HAVE_DOT YES)
set(DOXYGEN_CALL_GRAPH YES)
set(DOXYGEN_CALLER_GRAPH YES)
doxygen_add_docs(
docs
${DOXYGEN_INPUT}
COMMENT "Generate HTML documentation"
)
install(DIRECTORY ${DOXYGEN_OUTPUT_DIRECTORY}/html DESTINATION docs)
endif()
endif()
# 打包配置
include(InstallRequiredSystemLibraries)
set(CPACK_PACKAGE_NAME ${PROJECT_NAME})
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
set(CPACK_PACKAGE_DESCRIPTION "A lightweight, modular C++ GUI framework for Windows")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "星垣 (StellarX) - A lightweight Windows GUI framework")
set(CPACK_PACKAGE_VENDOR "StellarX Development Team")
set(CPACK_PACKAGE_CONTACT "contact@stellarx.dev")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "StellarX")
set(CPACK_NSIS_MODIFY_PATH ON)
if(WIN32)
set(CPACK_GENERATOR "ZIP;NSIS")
else()
set(CPACK_GENERATOR "ZIP")
endif()
include(CPack)

93
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,93 @@
# 为 StellarX 做贡献
感谢您有兴趣为 StellarX 做出贡献!本文档提供了贡献的指南和步骤。
StellarX 是一个为 **Windows 平台**打造的 C++ GUI 框架,基于 EasyX 图形库。
## 开发环境设置
1. 安装 Visual Studio 2019 或更高版本
2. 安装对应版本的 EasyX 图形库
3. 安装 CMake 3.12 或更高版本
4. 克隆项目仓库
5. 使用 CMake 生成解决方案并编译
## 如何贡献
### 报告错误
1. 检查 [Issues](../../issues) 看看这个错误是否已经被报告过。
2. 如果没有,请创建一个新的 Issue。
3. 使用 "Bug 报告" 模板。
4. 提供**清晰的标题和描述**。
5. 包括相关的代码片段、截图或重现问题的步骤。
### 建议功能增强
1. 检查现有的 Issue 中是否有你的想法。
2. 使用 "功能请求" 模板创建一个新的 Issue。
3. 清晰地描述新功能,并解释它为何有用。
### 提交代码更改 (拉取请求 Pull Requests)
1. **Fork** GitHub 上的仓库。
2. **Clone** 你 fork 的仓库到本地机器。
3. 为你的功能或错误修复创建一个**新分支** (`git checkout -b my-feature-branch`)。
4. **进行你的更改**。确保你的代码遵循项目的风格(见下文)。
5. **提交你的更改**,并附上清晰描述性的提交信息。
6. **Push** 你的分支到你 fork 的 GitHub 仓库 (`git push origin my-feature-branch`)。
7. 针对原始 StellarX 仓库的 `main` 分支发起一个**拉取请求 (Pull Request)**。
## 代码风格指南
* 遵循项目中现有的代码格式和命名约定。
* 为变量、函数和类使用有意义的名称。
* 在必要时注释你的代码,特别是复杂的逻辑。
* 确保你的代码编译时没有警告。
* 彻底测试你的更改。
* 使用 **4个空格** 进行缩进(不要使用制表符)
- 类名使用 **PascalCase**(如 `ClassName`
- 函数和变量使用 **camelCase**(如 `functionName`, `variableName`
- 常量使用 **UPPER_CASE**(如 `CONSTANT_VALUE`
- 成员变量以 **m_** 前缀(如 `m_memberVariable`
- 控件属性使用有意义的名称,避免缩写
- 为所有公共接口添加详细的注释
- 遵循 RAII 原则管理资源
## 示例代码风格
```c++
// 好的示例
class MyControl : public Control {
public:
MyControl(int x, int y, int width, int height)
: Control(x, y, width, height), m_isActive(false) {}
void draw() override {
// 绘制逻辑
}
private:
bool m_isActive;
};
// 不好的示例
class my_control: public Control{
public:
my_control(int x,int y,int w,int h):Control(x,y,w,h),active(false){}
void Draw() override{
// 绘制逻辑
}
private:
bool active;
};
```
## 项目结构
请遵循项目的目录结构:
- 头文件放在 `include/StellarX/` 目录
- 实现文件放在 `src/` 目录
- 示例代码放在 `examples/` 目录
## 问题?
如果你有任何问题,可以随时开一个 Issue 或联系维护者。

219
Doxyfile Normal file
View File

@@ -0,0 +1,219 @@
# Doxyfile 1.9.1
# 项目相关配置
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "星垣 (StellarX) GUI Framework"
PROJECT_NUMBER = 1.0.0
PROJECT_BRIEF = "A lightweight, modular C++ GUI framework for Windows"
PROJECT_LOGO =
OUTPUT_DIRECTORY = docs
CREATE_SUBDIRS = NO
ALLOW_UNICODE_NAMES = YES
OUTPUT_LANGUAGE = English
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF =
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = YES
JAVADOC_BANNER = NO
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES
# 构建类型
EXTRACT_ALL = YES
EXTRACT_PRIVATE = YES
EXTRACT_PACKAGE = YES
EXTRACT_STATIC = YES
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
EXTRACT_ANON_NSPACES = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = NO
HIDE_SCOPE_NAMES = NO
HIDE_COMPOUND_REFERENCE= NO
SHOW_INCLUDE_FILES = YES
SHOW_GROUPED_MEMB_INC = NO
FORCE_LOCAL_INCLUDES = NO
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_MEMBERS_CTOR_1ST = NO
SORT_GROUP_NAMES = YES
SORT_BY_SCOPE_NAME = YES
STRICT_PROTO_MATCHING = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_FILES = YES
SHOW_NAMESPACES = YES
FILE_VERSION_FILTER =
LAYOUT_FILE =
CITE_BIB_FILES =
# 输入配置
INPUT = include src README.md
INPUT_ENCODING = UTF-8
FILE_PATTERNS = *.h *.hpp *.cpp *.c *.cc *.cxx *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.idl *.ddl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py *.f90 *.f *.for *.vhd *.vhdl *.md
RECURSIVE = YES
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXCLUDE_SYMBOLS =
EXAMPLE_PATH = examples
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE = README.md
# 源代码浏览配置
SOURCE_BROWSER = YES
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
REFERENCES_LINK_SOURCE = YES
SOURCE_TOOLTIPS = YES
USE_HTAGS = NO
VERBATIM_HEADERS = YES
# HTML输出配置
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES =
HTML_COLORSTYLE_HUE = 220
HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
HTML_TIMESTAMP = YES
HTML_DYNAMIC_SECTIONS = NO
HTML_INDEX_NUM_ENTRIES = 100
GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_BUNDLE_ID = org.doxygen.Project
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
DOCSET_PUBLISHER_NAME = Publisher
GENERATE_HTMLHELP = NO
GENERATE_CHI = NO
GENERATE_QHP = NO
GENERATE_ECLIPSEHELP = NO
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = YES
TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
USE_MATHJAX = NO
MATHJAX_FORMAT = HTML-CSS
MATHJAX_RELPATH =
MATHJAX_EXTENSIONS =
MATHJAX_CODEFILE =
SEARCHENGINE = YES
SERVER_BASED_SEARCH = NO
EXTERNAL_SEARCH = NO
SEARCHDATA_FILE = searchdata.xml
EXTERNAL_SEARCH_ID =
EXTRA_SEARCH_MAPPINGS =
# LaTeX输出配置
GENERATE_LATEX = NO
# RTF输出配置
GENERATE_RTF = NO
# Man page输出配置
GENERATE_MAN = NO
# XML输出配置
GENERATE_XML = NO
# DOCBOOK输出配置
GENERATE_DOCBOOK = NO
# 自动生成配置
GENERATE_AUTOGEN_DEF = NO
# 配置生成器
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED = WIN32=1 \
_WINDOWS=1 \
UNICODE=1 \
_UNICODE=1
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
# 外部引用
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
# 图表生成
CLASS_DIAGRAMS = YES
MSCGEN_PATH =
DIA_PATH =
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = YES
DOT_NUM_THREADS = 0
DOT_FONTNAME = Helvetica
DOT_FONTSIZE = 10
DOT_FONTPATH =
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
UML_LIMIT_NUM_FIELDS = 10
TEMPLATE_RELATIONS = YES
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = YES
CALLER_GRAPH = YES
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
INTERACTIVE_SVG = NO
DOT_PATH =
DOTFILE_DIRS =
MSCFILE_DIRS =
DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = YES
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 我在人间做废物
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

337
README.md Normal file
View File

@@ -0,0 +1,337 @@
# 星垣 (StellarX) GUI Framework
![C++](https://img.shields.io/badge/C++-17+-00599C?logo=cplusplus&logoColor=white)
![Windows](https://img.shields.io/badge/Platform-Windows-0078D6?logo=windows)
![EasyX](https://img.shields.io/badge/Based_on-EasyX-00A0EA)
![License](https://img.shields.io/badge/License-MIT-blue.svg)
![Architecture](https://img.shields.io/badge/Architecture-Modular%20OOP-brightgreen)
![CMake](https://img.shields.io/badge/Build-CMake-064F8C?logo=cmake)
> **「繁星为界,轻若尘埃」** —— 一个为Windows平台打造的、极致轻量级、高度模块化的C++原生GUI框架。
`星垣 (StellarX)` 诞生于对现代GUI框架"过度臃肿"的反抗。它拒绝动辄数百MB的依赖、漫长的编译时间和复杂的学习曲线选择回归本质用最精简的代码、最清晰的架构和最高的效率解决桌面应用开发的核心需求。
它是一个**纯粹的教学级、工具级框架**旨在让开发者深入理解GUI原理并快速构建轻量级Windows工具。
---
## 📦 项目结构与设计哲学
星垣框架采用经典的**面向对象**和**模块化**设计,项目结构清晰规范:
```
StellarX/
├── include/ # 头文件目录
│ └── StellarX/ # 框架头文件
│ ├── StellarX.h # 主包含头文件 - 一键引入整个框架
│ ├── CoreTypes.h # ★ 核心 ★ - 所有枚举、结构体的唯一定义源
│ ├── Control.h # 抽象基类 - 定义所有控件的统一接口
│ ├── Button.h # 按钮控件
│ ├── Window.h # 窗口管理
│ ├── Label.h # 标签控件
│ ├── TextBox.h # 文本框控件
│ ├── Canvas.h # 画布容器
│ └── Table.h # 表格控件
├── src/ # 源文件目录
│ ├── Control.cpp
│ ├── Button.cpp
│ ├── Window.cpp
│ ├── Label.cpp
│ ├── TextBox.cpp
│ ├── Canvas.cpp
│ └── Table.cpp
├── examples/ # 示例代码目录
│ └── demo.cpp # 基础演示
├── docs/ # 文档目录
│ └── CODE_OF_CONDUCT.md # 行为准则
├── CMakeLists.txt # CMake 构建配置
├── CONTRIBUTING.md # 贡献指南
├── CHANGELOG.md # 更新日志
├── Doxyfile # Doxygen 配置
├── LICENSE # MIT 许可证
└── README.md # 项目说明
```
**设计理念:**
1. **单一职责原则 (SRP)**: 每个类/文件只负责一件事。
2. **依赖倒置原则 (DIP)**: 高层模块(如`Window`)不依赖低层模块(如`Button`),二者都依赖其抽象(`Control`)。
3. **开闭原则 (OCP)**: 通过继承`Control`基类,可以轻松扩展新的控件,而无需修改现有代码。
4. **一致性**: 所有控件共享统一的`draw()``handleEvent()`接口。
## 🚀 核心特性
- **极致的轻量级**: 核心库编译后仅 ~1.2MB,无任何外部依赖。生成的应用程序小巧玲珑。
- **清晰的模块化架构**: 使用`CoreTypes.h`统一管理所有类型,消除重复定义,极大提升可维护性。
- **原生C++性能**: 直接基于EasyX和Win32 API提供接近原生的执行效率内存占用极低通常<10MB
- **丰富的控件库**: 提供按钮、标签、文本框、表格、画布等常用控件,满足基本桌面应用需求。
- **高度可定制化**: 从控件颜色、形状(矩形、圆角、圆形、椭圆)到填充模式、字体样式,均有详尽枚举支持,可轻松定制。
- **简洁直观的API**: 采用经典的面向对象设计,代码即文档,学习成本极低。
- **标准项目结构**: 采用标准的include/src分离结构支持CMake构建易于集成和使用。
## ⚡ 快速开始5分钟上手
### 环境要求
- **操作系统**: Windows 10 或更高版本
- **编译器**: 支持C++17的编译器 (如: **Visual Studio 2019+**)
- **图形库**: [EasyX](https://easyx.cn/) (2022版本或更高安装时请选择与您编译器匹配的版本)
- **构建工具**: CMake 3.12+ (可选,推荐使用)
### 安装 EasyX
1. 访问 [EasyX 官网](https://easyx.cn/) 下载最新版本
2. 运行安装程序,选择与您的 Visual Studio 版本匹配的版本
3. 安装完成后,无需额外配置,星垣框架会自动链接 EasyX
### 方法一使用CMake构建推荐
1. **克隆项目**:
```bash
git clone https://github.com/Ysm-04/StellarX
cd StellarX
```
2. **生成构建系统**:
```bash
mkdir build
cd build
cmake ..
```
3. **编译项目**:
```bash
cmake --build .
```
4. **运行示例**:
```bash
./examples/Demo
```
### 方法二:手动集成到现有项目
1. **将include和src目录复制**到您的项目中
2. **配置包含路径**,确保编译器可以找到`include/StellarX/`目录
3. **将所有.cpp文件**添加到您的项目中编译
### 创建你的第一个星垣应用
```cpp
// 只需包含这一个头文件即可使用所有功能
#include "StellarX/StellarX.h"
// 程序入口点请使用WinMain以获得更好的兼容性
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd) {
// 1. 创建一个640x480的窗口背景为白色标题为"我的应用"
StellarX::Window mainWindow(640, 480, 0, RGB(255, 255, 255), "我的第一个星垣应用");
// 2. 创建一个按钮 (使用智能指针管理)
auto myButton = std::make_unique<StellarX::Button>(
250, 200, 140, 40, // x, y, 宽度, 高度
"点击我", // 按钮文本
StellarX::ButtonMode::NORMAL,
StellarX::ControlShape::ROUND_RECTANGLE
);
// 3. 为按钮设置点击事件使用Lambda表达式
myButton->setOnClickListener([]() {
MessageBox(nullptr, L"Hello, 星垣!", L"问候", MB_OK | MB_ICONINFORMATION);
});
// 4. (可选)设置按钮样式
myButton->textStyle.nHeight = 20;
myButton->textStyle.color = RGB(0, 0, 128); // 深蓝色文字
myButton->setButtonBorder(RGB(0, 128, 255)); // 蓝色边框
// 5. 将按钮添加到窗口
mainWindow.addControl(std::move(myButton));
// 6. 绘制窗口
mainWindow.draw();
// 7. 进入消息循环,等待用户交互
mainWindow.runEventLoop();
return 0;
}
```
5. **编译并运行!** 您将看到一个带有蓝色圆角按钮的窗口,点击它将会弹出消息框。
## 📚 核心类型详解 (`CoreTypes.h`)
星垣框架的所有视觉和行为属性都通过`CoreTypes.h`中定义的精美枚举和结构体来控制。
### 枚举类型 (Enums)
| 枚举类型 | 描述 | 常用值 |
| :----------------- | :----------- | :----------------------------------------------------------- |
| **`ControlShape`** | 控件几何形状 | `RECTANGLE`, `B_RECTANGLE`, `ROUND_RECTANGLE`, `CIRCLE`, `ELLIPSE`等 |
| **`ButtonMode`** | 按钮行为模式 | `NORMAL`(普通), `TOGGLE`(切换), `DISABLED`(禁用) |
| **`TextBoxMode`** | 文本框模式 | `INPUT_MODE`(输入), `READONLY_MODE`(只读) |
| **`FillMode`** | 图形填充模式 | `SOLID`(实心), `NULL`(空心), `HATCHED`(图案)等 |
| **`FillStyle`** | 图案填充样式 | `HORIZONTAL`(水平线), `CROSS`(十字线)等 |
| **`LineStyle`** | 边框线型 | `SOLID`(实线), `DASH`(虚线), `DOT`(点线)等 |
### 结构体 (Structs)
| 结构体 | 描述 |
| :---------------- | :----------------------------------------------------------- |
| **`ControlText`** | 封装了所有文本样式属性,包括字体、大小、颜色、粗体、斜体、下划线、删除线等。 |
**使用示例:**
```cpp
// 创建一个复杂的文本样式
StellarX::ControlText myStyle;
myStyle.nHeight = 25; // 字体高度
myStyle.lpszFace = _T("微软雅黑"); // 字体
myStyle.color = RGB(255, 0, 0); // 红色
myStyle.nWeight = FW_BOLD; // 粗体
myStyle.bUnderline = true; // 下划线
// 应用于控件
myLabel->textStyle = myStyle;
myButton->textStyle = myStyle;
```
## 🧩 控件库大全
### 1. 基础控件
| 控件 | 头文件 | 描述 | 关键特性 |
| :---------- | :---------- | :------------ | :------------------------------------------------------ |
| **Button** | `Button.h` | 多功能按钮 | 支持多种模式/形状/状态,可设置悬停/点击颜色,自定义回调 |
| **Label** | `Label.h` | 文本标签 | 支持背景透明/不透明,自定义字体样式 |
| **TextBox** | `TextBox.h` | 输入框/显示框 | 支持输入和只读模式集成EasyX的`InputBox` |
### 2. 容器控件
| 控件 | 头文件 | 描述 |
| :--------- | :--------- | :------------------------------------------------------- |
| **Canvas** | `Canvas.h` | 容器控件,可作为其他控件的父容器,支持自定义边框和背景。 |
| **Window** | `Window.h` | 顶级窗口,所有控件的最终容器,负责消息循环和调度。 |
### 3. 高级控件
| 控件 | 头文件 | 描述 | 关键特性 |
| :-------- | :-------- | :------- | :----------------------------------------------------------- |
| **Table** | `Table.h` | 数据表格 | **框架功能亮点**,支持分页显示、自定义表头和数据、自动计算列宽、翻页按钮。 |
**表格控件示例:**
```cpp
// 创建一个表格
auto myTable = std::make_unique<StellarX::Table>(50, 50);
// 设置表头
myTable->setHeaders({ "ID", "姓名", "年龄", "职业" });
// 添加数据行
myTable->addDataRow({ "1", "张三", "25", "工程师" });
myTable->addDataRow({ "2", "李四", "30", "设计师" });
myTable->addDataRow({ "3", "王五", "28", "产品经理" });
// 设置每页显示2行
myTable->setRowsPerPage(2);
// 设置表格样式
myTable->textStyle.nHeight = 16;
myTable->setTableBorder(RGB(50, 50, 50));
myTable->setTableBackground(RGB(240, 240, 240));
// 添加到窗口
mainWindow.addControl(std::move(myTable));
```
## 🔧 高级主题与最佳实践
### 1. 自定义控件
您可以通过继承`Control`基类来创建自定义控件。只需实现`draw()`和`handleEvent()`两个纯虚函数即可。
```cpp
class MyCustomControl : public StellarX::Control {
public:
MyCustomControl(int x, int y) : Control(x, y, 100, 100) {}
void draw() override {
// 您的自定义绘制逻辑
setfillcolor(RGB(255, 100, 100));
fillrectangle(x, y, x + width, y + height);
}
void handleEvent(const ExMessage& msg) override {
// 您的自定义事件处理逻辑
if (msg.message == WM_LBUTTONDOWN && isInControl(msg.x, msg.y)) {
// 处理点击
}
}
};
```
### 2. 布局管理
当前版本星垣主要采用**绝对定位**。对于简单布局,您可以通过计算坐标来实现。对于复杂布局,可以考虑:
- 在`Canvas`中嵌套控件,实现相对定位。
- 自行实现简单的流式布局或网格布局管理器。
### 3. 性能优化
- **脏矩形渲染**: 框架内部已实现,控件状态改变时`dirty=true`,仅在需要时重绘。
- **图像资源**: 使用`IMAGE`对象加载图片后,可重复使用,避免多次加载。
- **减少循环内操作**: 在`draw()`和`handleEvent()`中避免进行重型计算。
## ⚠️ 重要限制与适用场景
**星垣框架的设计目标是轻便、清晰和教学价值,因此它明确** **不适用于** **以下场景:**
- **高性能游戏或复杂动画**: 渲染基于EasyX的CPU软件渲染性能有限。
- **需要高DPI缩放的应用**: 对高DPI显示器的支持有限界面可能显示不正确。
- **需要无障碍功能的应用**: 未提供对屏幕阅读器等辅助技术的支持。
- **跨平台应用**: 深度依赖Windows API和EasyX无法直接在Linux/macOS上运行。
- **复杂的商业软件前端**: 缺乏高级控件(如树形图、富文本框、选项卡、高级列表等)和成熟的自动布局管理器。
**如果您需要开发上述类型的应用,请考虑使用以下成熟方案:**
- **Qt**: 功能极其强大,跨平台,适合大型商业应用。
- **wxWidgets**: 原生外观,跨平台。
- **Dear ImGui**: 即时模式GUI非常适合工具和调试界面。
- **Web技术栈 (Electron/CEF)**: 适合需要Web技术的场景。
## 📜 许可证 (License)
本项目采用 **MIT 许可证**。
您可以自由地:
- 使用、复制、修改、合并、出版发行、散布、再授权及销售本框架的副本。
- 将其用于私人或商业项目。
唯一要求是:
- 请在您的项目中保留原始的版权声明。
详见项目根目录的 [LICENSE](LICENSE) 文件。
## 👥 贡献指南 (Contributing)
我们欢迎任何形式的贡献!如果您想为星垣框架添砖加瓦,请阅读以下指南:
1. **代码风格**: 请遵循现有的Google C++规范风格(使用空格缩进,大括号换行等)。
2. **新增功能**: 必须提供**示例代码**并更新本README文档的相关部分。
3. **提交PR**: 请确保您的代码在提交前已经过测试,并描述清楚您的更改内容和动机。
4. **问题反馈**: 如果您发现了Bug或有新的想法欢迎在GitHub提交Issue。
详细贡献指南请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。
## 🙏 致谢 (Acknowledgements)
- 感谢 [EasyX Graphics Library](https://easyx.cn/) 为这个项目提供了简单易用的图形基础使得用C++教学GUI编程成为可能。
- 感谢所有追求**简洁、高效、清晰**编码理念的开发者,你们是"星垣"诞生的灵感源泉。
---
**星辰大海,代码为舟。**
愿 `星垣 (StellarX)` 能成为您探索GUI世界的一颗可靠基石无论是用于学习、教学还是创造实用的工具。
## 📞 支持与反馈
如果您在使用过程中遇到问题或有任何建议:
1. 查看 [示例代码](examples/) 获取使用参考
2. 查阅 [更新日志](CHANGELOG.md) 了解最新变化
3. 在GitHub仓库提交Issue反馈问题
---
*星垣框架 - 轻若尘埃,繁星为界*

25
docs/CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,25 @@
# 贡献者公约行为准则
## 我们的承诺
为了营造一个开放和受欢迎的环境,我们作为贡献者和维护者承诺:无论年龄、体型、身体健全与否、民族、性征、性别认同与表达、经验水平、教育程度、社会地位、国籍、个人外貌、种族、宗教信仰、性取向,我们的项目和社区对每一个人都不存在歧视。
## 我们的标准
有助于为我们社区创造积极环境的行为包括但不限于:
* 对他人的体贴和尊重
* 尊重不同的观点和经历
* 优雅地接受建设性批评
* 关注对社区最有利的事情
* 对其他社区成员表现出同理心
......
## 执行
虐待、骚扰或其他不可接受行为的实例可通过项目维护团队进行报告。所有投诉都将被认真、迅速地审查和调查,并将得出被认为在情况下必要和适当的回应。
......
有关此行为准则的常见问题解答,请参阅 https://www.contributor-covenant.org/faq。翻译版本可在 https://www.contributor-covenant.org/translations 获取。

40
examples/demo.cpp Normal file
View File

@@ -0,0 +1,40 @@
/**
* @file demo.cpp
* @brief 一个简单的演示程序,展示 StellarX GUI 框架的基本用法。
* @description 创建一个带有按钮的窗口,点击按钮会改变其文本。
*/
#include <StellarX/StellarX.h>
#include <iostream>
int main()
{
// 创建一个窗口 (Windows平台)
Window mainWindow(800, 600, NULL, RGB(240, 240, 240), "StellarX 演示程序");
// 创建一个按钮
auto myButton = std::make_unique<Button>(300, 250, 200, 80, "点击我!", StellarX::ButtonMode::NORMAL, StellarX::ControlShape::ROUND_RECTANGLE);
// 为按钮点击事件设置一个回调函数
myButton->setOnClickListener([&myButton]() {
std::cout << "按钮被点击了!" << std::endl;
// 点击后改变按钮文本作为视觉反馈
static bool = false;
if () {
myButton->setButtonText("点击我!");
}
else {
myButton->setButtonText("被点过了!");
}
= !;
});
// 将按钮添加到窗口
mainWindow.addControl(std::move(myButton));
// 绘制窗口并运行事件循环 (Windows消息循环)
mainWindow.draw();
mainWindow.runEventLoop();
return 0;
}

147
include/StellarX/Button.h Normal file
View File

@@ -0,0 +1,147 @@
/*******************************************************************************
* @文件: Button.h
* @摘要: 按钮控件类
* @描述:
* 提供多种样式和行为的按钮控件,支持点击、悬停、切换等状态。
* 继承自Control基类是框架的核心交互组件之一。
*
* @所属框架: 星垣(StellarX) GUI框架
* @作者: 我在人间做废物
* @日期: September 2025
******************************************************************************/
#pragma once
#include "Control.h"
class button : public Control
{
std::string text; // 按钮上的文字
bool click; // 是否被点击
bool hover; // 是否被悬停
bool dirty = true; // 是否重绘
COLORREF buttonTrueColor; // 按钮被点击后的颜色
COLORREF buttonFalseColor; // 按钮未被点击的颜色
COLORREF buttonHoverColor; // 按钮被鼠标悬停的颜色
COLORREF buttonBorderColor = RGB(0,0,0);// 按钮边框颜色
StellarX::buttonMode mode; // 按钮模式
StellarX::controlShape shape; // 按钮形状
int buttonFillMode = BS_SOLID; //按钮填充模式
StellarX::fillStyle buttonFillIma = StellarX::fillStyle::BDiagonal; //按钮填充图案
IMAGE* buttonFileIMAGE = nullptr; //按钮填充图像
int ROUND_RECTANGLEwidth = 20; //构成圆角矩形的圆角的椭圆的宽度。
int ROUND_RECTANGLEheight = 20; //构成圆角矩形的圆角的椭圆的高度。
std::function<void()> onClickCallback; //回调函数
std::function<void()> onToggleOnCallback; //TOGGLE模式下的回调函数
std::function<void()> onToggleOffCallback; //TOGGLE模式下的回调函数
StellarX::controlText oldStyle = textStyle; // 按钮文字样式
int oldtext_width = -1;
int oldtext_height = -1;
int text_width = 0;
int text_height = 0;
public:
StellarX::controlText textStyle; // 按钮文字样式
public:
/*************************************************************************/
/********************************构造函数*********************************/
/*************************************************************************/
//默认按钮颜色
button(int x, int y, int width, int height, const std::string text,
StellarX::buttonMode mode = StellarX::buttonMode::NORMAL, StellarX::controlShape shape = StellarX::controlShape::RECTANGLE);
//自定义按钮未被点击和被点击颜色
button(int x, int y, int width, int height, const std::string text,
COLORREF ct, COLORREF cf, StellarX::buttonMode mode = StellarX::buttonMode::NORMAL,
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,
StellarX::buttonMode mode = StellarX::buttonMode::NORMAL, StellarX::controlShape shape = StellarX::controlShape::RECTANGLE);
//析构函数 释放图形指针内存
~button();
/*************************************************************************/
/********************************Set方法**********************************/
/*************************************************************************/
//绘制按钮
void draw() override;
//按钮事件处理
void handleEvent(const ExMessage& msg) override;
//设置回调函数
//************************************
// 名称: setOnClickListener | setOnToggleOnListener | setOnToggleOffListener
// 全名: button::setOnClickListener
// 访问: public
// 返回类型: void
// Parameter: const std::function<> & & callback 设置回调函数 传入回调函数名即可,不需要传入(),不需要传入参数,不需要传入返回值
// 如果要传入参数可以使用lambda表达式
//************************************
void setOnClickListener(const std::function<void()>&& callback);
//设置TOGGLE模式下被点击的回调函数
void setOnToggleOnListener(const std::function<void()>&& callback);
//设置TOGGLE模式下取消点击的回调函数
void setOnToggleOffListener(const std::function<void()>&& callback);
//设置按钮模式
void setbuttonMode(StellarX::buttonMode mode);
//设置圆角矩形椭圆宽度
int setROUND_RECTANGLEwidth(int width);
//设置圆角矩形椭圆高度
int setROUND_RECTANGLEheight(int height);
//设置按钮填充模式
void setFillMode(int mode);
//设置按钮填充图案
void setFillIma(StellarX::fillStyle ima);
//设置按钮填充图像
void setFillIma(std::string imaName);
//设置按钮边框颜色
void setbuttonBorder(COLORREF Border);
//设置按钮文本
void setbuttonText(const char* text);
void setbuttonText(std::string text);
//设置按钮形状
void setbuttonShape(StellarX::controlShape shape);
//判断按钮是否被点击
bool isClicked() const;
/*************************************************************************/
/********************************Get方法**********************************/
/*************************************************************************/
//获取按钮文字
std::string getbuttonText() const;
const char* getbuttonText_c() const;
//获取按钮模式
StellarX::buttonMode getbuttonMode() const;
//获取按钮形状
StellarX::controlShape getbuttonShape() const;
//获取按钮填充模式
int getFillMode() const;
//获取按钮填充图案
StellarX::fillStyle getFillIma() const;
//获取按钮填充图像
IMAGE* getFillImaImage() const;
//获取按钮边框颜色
COLORREF getbuttonBorder() const;
//获取按钮文字颜色
COLORREF getbuttonTxtColor() const;
//获取按钮文字样式
StellarX::controlText getbuttonTextStyle() const;
private:
//初始化按钮
void initButton(const std::string text, StellarX::buttonMode mode, StellarX::controlShape shape, COLORREF ct, COLORREF cf, COLORREF ch);
//判断鼠标是否在圆形按钮内
bool isMouseInCircle(int mouseX, int mouseY, int x, int y, int radius);
//判断鼠标是否在椭圆按钮内
bool isMouseInEllipse(int mouseX, int mouseY, int x, int y, int width, int height);
};

46
include/StellarX/Canvas.h Normal file
View File

@@ -0,0 +1,46 @@
#pragma once
#include "Control.h"
// 画布容器控件,可以作为其他控件的父容器
// 功能:
// - 包含和管理子控件
// - 将事件传递给子控件
// - 提供统一的背景和边框
// 使用场景: 用于分组相关控件或实现复杂布局
class Canvas : public Control
{
private:
std::vector<std::unique_ptr<Control>> controls;
StellarX::controlShape shape = StellarX::controlShape::RECTANGLE; //容器形状
StellarX::fillMode canvasFillMode = StellarX::fillMode::Solid; //容器填充模式
StellarX::lineStyle canvasLineStyle = StellarX::lineStyle::Solid; //线型
int canvaslinewidth = 1; //线宽
COLORREF canvasBorderClor = RGB(0, 0, 0);//边框颜色
COLORREF canvasBkClor = RGB(255,255,255); //背景颜色
public:
Canvas(int x, int y, int width, int height);
~Canvas() {}
//绘制容器及其子控件
void draw() override;
void handleEvent(const ExMessage& msg) override;
//添加控件
void addControl(std::unique_ptr<Control> control);
//设置容器样式
void setShape(StellarX::controlShape shape);
//设置容器填充模式
void setcanvasfillMode(StellarX::fillMode mode);
//设置容器边框颜色
void setBorderColor(COLORREF color);
//设置填充颜色
void setCanvasBkColor(COLORREF color);
//设置线形
void setcanvasLineStyle(StellarX::lineStyle style);
//设置线段宽度
void setlinewidth(int width);
};

View File

@@ -0,0 +1,80 @@
#pragma once
/*********************************************************************
* \文件: Control.h
* \描述: 控件基类,所有控件都继承自此类。
* 提供了控件的一些基本属性和方法。
*
* \作者: 我在人间做废物
* \日期: September 2025
*********************************************************************/
#include <vector>
#include <memory>
#include <easyx.h>
#include <iostream>
#include <string>
#include <functional>
#include <initializer_list>
#include "CoreTypes.h"
/**
* @类名称: Control
* @功能描述: 控件基类,所有控件都继承自此类。
* 提供了控件的一些基本属性和方法。
*
* @成员说明:
* int x, y, width, height; // 控件的基本属性
*
* LOGFONT currentFont; //保存当前字体样式和颜色
* COLORREF currentColor = 0;
* COLORREF currentBkColor = 0; //保存当前填充色
* COLORREF currentBorderColor = 0;//边框颜色
* LINESTYLE* currentLineStyle = new LINESTYLE; //保存当前线型
*
* Control():x(0), y(0), width(0), height(0) {}
* Control(int x, int y, int width, int height) :x(x),y(y),width(width),height(height){}
* virtual void draw() = 0; // 绘制控件
* virtual void handleEvent(const ExMessage& msg) = 0; // 处理事件
* virtual ~Control() { delete currentLineStyle; }
*
* //保存当前字体样式和颜色
* void saveStyle();
* //恢复默认字体样式和颜色
* void restoreStyle();
*
* @使用示例:
* Control* ctrl = new Button(10, 10, 100, 50, "Click Me");
* ctrl->draw();
* delete ctrl;
*
* @备注:
* 这是一个抽象基类,不能直接实例化。
* 所有具体的控件类都必须实现draw和handleEvent方法。
*/
class Control
{
protected:
int x, y, width, height; // 控件的基本属性
LOGFONT currentFont; //保存当前字体样式和颜色
COLORREF currentColor = 0;
COLORREF currentBkColor = 0; //保存当前填充色
COLORREF currentBorderColor = 0;//边框颜色
LINESTYLE* currentLineStyle = new LINESTYLE; //保存当前线型
public:
Control(const Control&) = delete; // 禁用拷贝构造
Control& operator=(const Control&) = delete; // 禁用拷贝赋值
Control(Control&&) = default; // 允许移动构造
Control& operator=(Control&&) = default; // 允许移动赋值
Control():x(0), y(0), width(100), height(100) {}
Control(int x, int y, int width, int height) :x(x),y(y),width(x + width),height(y + height){}
virtual void draw() = 0; // 绘制控件
virtual void handleEvent(const ExMessage& msg) = 0; // 处理事件
virtual ~Control() {
delete currentLineStyle; currentLineStyle = nullptr; }
protected:
//保存当前样式和颜色
void saveStyle();
//恢复默认样式和颜色
void restoreStyle();
};

View File

@@ -0,0 +1,243 @@
#pragma once
/*******************************************************************************
* @文件: CoreTypes.h
* @摘要: 星垣框架核心类型定义文件
* @描述:
* 集中定义框架中使用的所有枚举类型和结构体,确保类型一致性。
* 这是框架的类型系统基础,所有控件都依赖于此文件中定义的类型。
*
* @作者: 我在人间做废物
* @日期: September 2025
******************************************************************************/
#include"easyX.h"
namespace StellarX
{
/**
* @枚举类名称: hatchStyle
* @功能描述: 用来定义控件填充图案的枚举类
*
* @详细说明:
* 根据此枚举类可以自定义控件填充图案
* 可以在控件初始化时设置填充图案
* 根据具体情况选择不同的填充图案
* 默认填充图案为水平线
*
* @取值说明:
* Horizontal - 水平线
* Vertical - 垂直线
* FDiagonal - 反斜线
* BDiagonal - 正斜线
* Cross - 十字
* DiagCross - 网格
*
* @使用示例:
* // 示例代码展示如何使用此枚举类
* hatchStyle var = hatchStyle::Horizontal;
*
* @备注:
* 此枚举类仅支持图案填充模式
* 枚举类在使用时,需要使用::进行调用,还要注意大小写
*/
enum class fillStyle {
Horizontal = HS_HORIZONTAL, // 水平线
Vertical = HS_VERTICAL, // 垂直线
FDiagonal = HS_FDIAGONAL, // 反斜线
BDiagonal = HS_BDIAGONAL, // 正斜线
Cross = HS_CROSS, // 十字
DiagCross = HS_DIAGCROSS // 网格
};
/**
* @枚举类名称: fillMode
* @功能描述: 用来定义控件填充模式的枚举类
*
* @详细说明:
* 根据此枚举类可以自定义控件填充模式
* 可以在控件初始化时设置填充模式
* 根据具体情况选择不同的填充模式
* 默认填充模式为固实填充
*
* @取值说明:
* Solid - 固实填充
* Null - 不填充
* Hatched - 图案填充
* Pattern - 自定义图案填充
* DibPattern - 自定义图像填充
*
* @使用示例:
* // 示例代码展示如何使用此枚举类
* fillMode var = fillMode::Solid;
*
* @备注:
* 枚举类在使用时,需要使用::进行调用,还要注意大小写
*/
enum class fillMode
{
Solid = BS_SOLID, //固实填充
Null = BS_NULL, // 不填充
Hatched = BS_HATCHED, // 图案填充
Pattern = BS_PATTERN, // 自定义图案填充
DibPattern = BS_DIBPATTERN // 自定义图像填充
};
/**
* @枚举类名称: linStyle
* @功能描述: 此枚举类用来定义控件边框线型
*
* @详细说明:
* 根据此枚举类可以自定义控件边框线型
* 可以在控件初始化时设置边框线型
* 根据具体情况选择不同的线型
* 默认线型为实线
*
* @取值说明:
* Solid // 实线
* Dash // 虚线
* Dot // 点线
* DashDot // 点划线
* DashDotDot // 双点划线
* Null // 无线
*
* @使用示例:
* // 示例代码展示如何使用此枚举类
* lineStyle var = lineStyle::Solid;
*
* @备注:
* 枚举类在使用时,需要使用::进行调用,还要注意大小写
*/
enum class lineStyle {
Solid = PS_SOLID, // 实线
Dash = PS_DASH, // 虚线
Dot = PS_DOT, // 点线
DashDot = PS_DASHDOT, // 点划线
DashDotDot = PS_DASHDOTDOT, // 双点划线
Null = PS_NULL // 无线
};
/**
* @结构体名称: controlText
* @功能描述: 控件字体样式 可以自定义不同的样式
*
* @详细说明:
* 主要使用的场景为:需要修改或想自定义控件字体大小,字体样式,颜色等
*
* @成员说明:
* int nHeight = 0; - 字体高度
* int nWidth = 0; - 字体宽度 如果为0则自适应
* LPCTSTR lpszFace = "宋体"; - 字体名称
* COLORREF color = RGB(0, 0, 0); - 字体颜色
* int nEscapement = 0; - 字符串旋转角度
* int nOrientation = 0; - 字符旋转角度
* int nWeight = 0; - 字体粗细 范围0~1000 0表示默认
* bool bItalic = false; - 是否斜体
* bool bUnderline = false; - 是否下划线
* bool bStrikeOut = false; - 是否删除线
* bool operator!=(const controlText& text);
* controlText& operator=(const controlText& text
*/
struct controlText
{
int nHeight = 0; //- 字体高度
int nWidth = 0; //- 字体宽度 如果为0则自适应
LPCTSTR lpszFace = "宋体"; //- 字体名称
COLORREF color = RGB(0, 0, 0); //- 字体颜色
int nEscapement = 0; //- 字符串旋转角度
int nOrientation = 0; //- 字符旋转角度
int nWeight = 0; //- 字体粗细 范围0~1000 0表示默认
bool bItalic = false; //- 是否斜体
bool bUnderline = false; //- 是否下划线
bool bStrikeOut = false; //- 是否删除线
bool operator!=(const controlText& text);
controlText& operator=(const controlText& text);
};
/**
* @枚举名称: controlShape
* @功能描述: 枚举控件的不同几何样式
*
* @详细说明:
* 定义了四种(有无边框算一种)不同的几何样式,可以根据具体需求
* 自定义控件的形状。
*
* @取值说明:
* RECTANGLE = 1, //有边框矩形
* B_RECTANGLE, //无边框矩形
* ROUND_RECTANGLE, //有边框圆角矩形
* B_ROUND_RECTANGLE, //无边框圆角矩形
* CIRCLE, //有边框圆形
* B_CIRCLE, //无边框圆形
* ELLIPSE, //有边框椭圆
* B_ELLIPSE //无边框椭圆
*
* @使用示例:
* controlShape shape = ELLIPSE;
*
* @备注:
* 按钮类支持所有形状,部分控件只支持部分形状,具体请参考控件类。
*/
enum class controlShape
{
RECTANGLE = 1, //有边框矩形
B_RECTANGLE, //无边框矩形
ROUND_RECTANGLE, //有边框圆角矩形
B_ROUND_RECTANGLE, //无边框圆角矩形
CIRCLE, //有边框圆形
B_CIRCLE, //无边框圆形
ELLIPSE, //有边框椭圆
B_ELLIPSE //无边框椭圆
};
/**
* @枚举类名称: textBoxmode
* @功能描述: 定义了文本框的两种模式
*
* @详细说明:
* 需要限制文本框是否接受用户输入时使用
*
* @取值说明:
* INPUT_MODE, // 用户可输入模式
* READONLY_MODE // 只读模式
*
* @使用示例:
* // 示例代码展示如何使用此枚举类
* StellarX::textBoxmode var = EnumClassName::VALUE1;
*
* @备注:
* 枚举类的特性、与普通枚举的区别
*/
enum class textBoxmode
{
INPUT_MODE, // 用户可输入模式
READONLY_MODE // 只读模式
};
/**
* @枚举名称: buttonMode
* @功能描述: brief
*
* @详细说明:
* 根据按钮的工作模式,按钮可以有不同的行为。
* 用户可以在具体情况下设置按钮的工作模式。
*
* @取值说明:
* NORMAL = 1, - 普通模式,点击后触发回调,但不会保持状态。
* TOGGLE, - 切换模式,点击后会在选中和未选中之间切换,触发不同的回调函数。
* DISABLED - 禁用模式,按钮不可点击,显示为灰色,文本显示删除线。
*
* @使用示例:
* button b1(100, 100, 120, 120, "测试按钮", RGB(128, 0, 0), RGB(255, 9, 9));
*
*/
enum class buttonMode
{
NORMAL = 1,
TOGGLE,
DISABLED
};
};

View File

@@ -0,0 +1,37 @@
/*******************************************************************************
* @文件: StellarX.h
* @摘要: 星垣(StellarX) GUI框架 - 主包含头文件
* @版本: v1.0.0
* @描述:
* 一个为Windows平台打造的轻量级、模块化C++ GUI框架。
* 基于EasyX图形库提供简洁易用的API和丰富的控件。
*
* 通过包含此单一头文件,即可使用框架的所有功能。
* 内部包含顺序经过精心设计,确保所有依赖关系正确解析。
*
* @作者: 我在人间做废物
* @邮箱: [您的邮箱或联系方式]
* @仓库: https://github.com/yourusername/stellarx
*
* @许可证: MIT License
* @版权: Copyright (c) 2025 我在人间做废物
*
* @使用说明:
* 只需包含此文件即可使用框架所有功能。
* 示例: #include "StellarX.h"
* @包含顺序:
* 1. CoreTypes.h - 基础类型定义
* 2. Control.h - 控件基类
* 3. 其他具体控件头文件
******************************************************************************/
#pragma once
#include "CoreTypes.h"
#include "Control.h"
#include"Button.h"
#include"window.h"
#include"label.h"
#include"textBox.h"
#include"Canvas.h"
#include"table.h"

35
include/StellarX/label.h Normal file
View File

@@ -0,0 +1,35 @@
#pragma once
#include "Control.h"
// 标签控件,用于显示文本
// 特点:
// - 支持背景透明/不透明模式
// - 不支持用户交互(无事件处理)
// - 自动适应文本内容大小
class label : public Control
{
std::string text; //标签文本
COLORREF textColor; //标签文本颜色
COLORREF textBkColor; //标签背景颜色
bool textBkDisap = false; //标签背景是否透明
//标签事件处理(标签无事件)不实现具体代码
void handleEvent(const ExMessage& msg) override {}
public:
StellarX::controlText textStyle; //标签文本样式
public:
label();
label(int x, int y, std::string text = "标签",COLORREF textcolor = BLACK, COLORREF bkColor= RGB(255,255,255));
//绘标签
void draw() override;
//设置标签背景是否透明
void setTxtdisap(bool key);
//设置标签文本颜色
void setTxtColor(COLORREF color);
//设置标签背景颜色
void setTxtBkColor(COLORREF color);
//设置标签文本
void setText(std::string text);
};

131
include/StellarX/table.h Normal file
View File

@@ -0,0 +1,131 @@
/*******************************************************************************
* @文件: table.h
* @摘要: 高级表格控件,支持分页显示
* @描述:
* 提供完整的数据表格功能,包括表头、数据行、分页和导航按钮。
* 自动计算列宽和行高,支持自定义样式
*
* @实现机制:
* 1. 使用二维向量存储数据
* 2. 通过分页算法计算显示范围
* 3. 使用内部按钮和标签实现分页UI
* 4. 通过背景缓存优化渲染性能
*
* @所属框架: 星垣(StellarX) GUI框架
* @作者: 我在人间做废物
* @日期: September 2025
******************************************************************************/
#pragma once
#include "Control.h"
#include "Button.h"
#include "label.h"
class table :public Control
{
private:
std::vector<std::vector<std::string>> data; // 表格数据
std::vector<std::string> headers; // 表格表头
std::string pageNumtext = "页码标签"; // 页码标签文本
int tableBorderWidth = 1; // 边框宽度
std::vector<int> colWidths; // 每列的宽度
std::vector<int> lineHeights; // 每行的高度
IMAGE* saveBkImage = nullptr;
int rowsPerPage = 5; // 每页显示的行数
int currentPage = 1; // 当前页码
int totalPages = 1; // 总页数
bool isShowPageButton = true; // 是否显示翻页按钮
bool dirty = true; // 是否需要重绘
bool isNeedDrawHeaders = true; // 是否需要绘制表头
bool isNeedCellSize = true; // 是否需要计算单元格尺寸
button* prevButton = nullptr; // 上一页按钮
button* nextButton = nullptr; // 下一页按钮
label* pageNum = nullptr; //页码文本
int dX = x, dY = y; // 单元格的开始坐标
int uX = x, uY = y; // 单元格的结束坐标
int pX = 0; //标签左上角坐标
int pY = 0; //标签左上角坐标
StellarX::fillMode tableFillMode = StellarX::fillMode::Solid; //填充模式
StellarX::lineStyle tableLineStyle = StellarX::lineStyle::Solid; // 线型
COLORREF tableBorderClor = RGB(0, 0, 0); // 表格边框颜色
COLORREF tableBkClor = RGB(255, 255, 255); // 表格背景颜色
void initTextWaH(); //初始化文本像素宽度和高度
void initButton(); //初始化翻页按钮
void initPageNum(); //初始化页码标签
void drawTable(); //绘制当前页
void drawHeader(); //绘制表头
void drawPageNum(); //绘制页码信息
void drawButton(); //绘制翻页按钮
public:
StellarX::controlText textStyle; // 文本样式
public:
table(int x, int y);
~table();
// 绘制表格
void draw() override;
//事件处理
void handleEvent(const ExMessage& msg) override;
//************************** 设置属性 *****************************/
//设置表头
void setHeaders(std::initializer_list<std::string> headers);
//设置表格数据
void setData(const std::vector<std::string>& data);
void setData(const std::initializer_list<std::vector<std::string>>& data);
//设置每页显示的行数
void setRowsPerPage(int rows);
//设置是否显示翻页按钮
void showPageButton(bool isShow);
//设置表格边框颜色
void settableBorder(COLORREF color);
//设置表格背景颜色
void settableBk(COLORREF color);
//设置填充模式
void settableFillMode(StellarX::fillMode mode);
//设置线型
void settableLineStyle(StellarX::lineStyle style);
//设置边框宽度
void settableBorderWidth(int width);
//************************** 获取属性 *****************************/
//获取当前页码
int getCurrentPage() const;
//获取总页数
int getTotalPages() const;
//获取每页显示的行数
int getRowsPerPage() const;
//获取是否显示翻页按钮
bool getShowPageButton() const;
//获取表格边框颜色
COLORREF gettableBorder() const;
//获取表格背景颜色
COLORREF gettableBk() const;
//获取填充模式
StellarX::fillMode gettableFillMode() const;
//获取线型
StellarX::lineStyle gettableLineStyle() const;
//获取表头
std::vector<std::string> getHeaders () const;
//获取表格数据
std::vector<std::vector<std::string>> getData() const;
//获取表格边框宽度
int gettableBorderWidth() const;
};

View File

@@ -0,0 +1,43 @@
#pragma once
#include "Control.h"
// 文本框控件,支持输入和只读两种模式
// 特殊说明:
// - 在INPUT_MODE下点击会调用EasyX的InputBox
// - 在READONLY_MODE下点击会显示信息对话框
// - 最大字符长度受maxCharLen限制
class textBox : public Control
{
std::string text; //文本
StellarX::textBoxmode mode; //模式
StellarX::controlShape shape; //形状
bool dirty = true; //是否重绘
bool click = false; //是否点击
int maxCharLen = 10;//最大字符长度
COLORREF textBoxBkClor = RGB(255, 255, 255); //背景颜色
COLORREF textBoxBorderClor = RGB(0,0,0); //边框颜色
public:
StellarX::controlText textStyle; //文本样式
textBox(int x, int y, int width, int height, std::string text = "", StellarX::textBoxmode mode = StellarX::textBoxmode::INPUT_MODE, StellarX::controlShape shape = StellarX::controlShape::RECTANGLE);
void draw() override;
void handleEvent(const ExMessage& msg) override;
//设置模式
void setMode(StellarX::textBoxmode mode);
//设置可输入最大字符长度
void setmaxCharLen(int len);
//设置形状
void settextBoxshape(StellarX::controlShape shape);
//设置边框颜色
void settextBoxBorder(COLORREF color);
//设置背景颜色
void settextBoxBk(COLORREF color);
//获取文本
std::string gettext();
};

53
include/StellarX/window.h Normal file
View File

@@ -0,0 +1,53 @@
#pragma once
#include "Control.h"
//窗口模式
//#define EX_DBLCLKS 1 - 在绘图窗口中支持鼠标双击事件。
//#define EX_NOCLOSE 2 - 禁用绘图窗口的关闭按钮。
//#define EX_NOMINIMIZE 3 - 禁用绘图窗口的最小化按钮。
//#define EX_SHOWCONSOLE 4 - 显示控制台窗口。
/*******************************************************************************
* @类: window
* @摘要: 应用程序主窗口类
* @描述:
* 负责创建和管理应用程序的主窗口,是所有控件的根容器。
* 处理消息循环、事件分发和窗口生命周期管理。
*
* @重要说明:
* - 使用 initgraph() 创建窗口
* - 使用 BeginBatchDraw()/EndBatchDraw() 实现双缓冲
* - 使用 getmessage() 处理消息循环
******************************************************************************/
class window
{
int width; //窗口宽度
int height; //窗口高度
int windowMode = NULL; //窗口模式
HWND hWnd = NULL; //窗口句柄
std::string headline; //窗口标题
COLORREF wBkcolor = BLACK; //窗口背景
IMAGE* background = nullptr; //窗口背景图片
std::vector<std::unique_ptr<Control>> controls; //控件管理
public:
window(int width, int height, int mode);
window(int width, int height, int mode, COLORREF bkcloc);
window(int width, int height, int mode , COLORREF bkcloc, std::string headline = "窗口");
~window();
//绘制窗口
void draw();
void draw(std::string pImgFile);
//事件循环
void runEventLoop();
//设置窗口背景图片
void setBkImage(std::string pImgFile);
//设置窗口背景颜色
void setBkcolor(COLORREF c);
//设置窗口标题
void setHeadline(std::string headline);
//添加控件
void addControl(std::unique_ptr<Control> control);
};

344
src/Button.cpp Normal file
View File

@@ -0,0 +1,344 @@
#include "button.h"
button::button(int x, int y, int width, int height, const std::string text, StellarX::buttonMode mode, StellarX::controlShape shape)
: Control(x, y, width, height)
{
initButton(text, mode, shape, RGB(202, 255, 255), RGB(171, 196, 220), RGB(255, 255, 0));
}
button::button(int x, int y, int width, int height, const std::string text, COLORREF ct, COLORREF cf, StellarX::buttonMode mode, StellarX::controlShape shape)
: Control(x, y, width, height)
{
initButton(text, mode, shape, ct, cf, RGB(255, 255, 0));
}
button::button(int x, int y, int width, int height, const std::string text, COLORREF ct, COLORREF cf, COLORREF ch, StellarX::buttonMode mode, StellarX::controlShape shape)
: Control(x, y, width, height)
{
initButton(text, mode, shape, ct, cf, ch);
}
void button::initButton(const std::string text, StellarX::buttonMode mode, StellarX::controlShape shape, COLORREF ct, COLORREF cf, COLORREF ch)
{
this->text = text;
this->mode = mode;
this->shape = shape;
this->buttonTrueColor = ct;
this->buttonFalseColor = cf;
this->buttonHoverColor = ch;
this->click = false;
this->hover = false;
}
button::~button()
{
if (buttonFileIMAGE)
delete buttonFileIMAGE;
buttonFileIMAGE = nullptr;
}
void button::draw()
{
if (dirty)
{
//保存当前样式和颜色
saveStyle();
if (StellarX::buttonMode::DISABLED == mode) //设置禁用按钮色
{
setfillcolor(RGB(96, 96, 96));
textStyle.bStrikeOut = 1;
}
else
{
if (hover)
setfillcolor(buttonHoverColor);
else
setfillcolor(click ? buttonTrueColor : buttonFalseColor);
}
//设置字体背景色透明
setbkmode(TRANSPARENT);
//边框颜色
setlinecolor(buttonBorderColor);
if(this->textStyle !=oldStyle)
{
//设置字体颜色
settextcolor(textStyle.color);
//设置字体样式
settextstyle(textStyle.nHeight, textStyle.nWidth, textStyle.lpszFace,
textStyle.nEscapement, textStyle.nOrientation, textStyle.nWeight,
textStyle.bItalic, textStyle.bUnderline, textStyle.bStrikeOut); //设置字体样式
}
//设置按钮填充模式
setfillstyle(buttonFillMode, (int)buttonFillIma, buttonFileIMAGE);
//获取字符串像素高度和宽度
if((this->oldtext_width!= this->text_width|| this->oldtext_height!= this->text_height)
||(-1 == oldtext_width &&oldtext_height == -1))
{
this->oldtext_width = this->text_width = textwidth(LPCTSTR(this->text.c_str()));;
this->oldtext_height = this->text_height = textheight(LPCTSTR(this->text.c_str()));;
}
//根据按钮形状绘制
switch (shape)
{
case StellarX::controlShape::RECTANGLE:
fillrectangle(x, y, width, height);//有边框填充矩形
outtextxy((x + (width - x - text_width) / 2), (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
break;
case StellarX::controlShape::B_RECTANGLE:
solidrectangle(x, y, width, height);//无边框填充矩形
outtextxy((x + (width - x - text_width) / 2), (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
break;
case StellarX::controlShape::ROUND_RECTANGLE:
fillroundrect(x, y, width, height, ROUND_RECTANGLEwidth, ROUND_RECTANGLEheight);//有边框填充圆角矩形
outtextxy((x + (width - x - text_width) / 2), (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
break;
case StellarX::controlShape::B_ROUND_RECTANGLE:
solidroundrect(x, y, width, height, ROUND_RECTANGLEwidth, ROUND_RECTANGLEheight);//无边框填充圆角矩形
outtextxy((x + (width - x - text_width) / 2), (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
break;
case StellarX::controlShape::CIRCLE:
fillcircle(x, y, (width - x) / 2);//有边框填充圆形
outtextxy(x - text_width / 2, y - text_height / 2, LPCTSTR(text.c_str()));
break;
case StellarX::controlShape::B_CIRCLE:
solidcircle(x, y, (width - x) / 2);//无边框填充圆形
outtextxy(x - text_width / 2, y - text_height / 2, LPCTSTR(text.c_str()));
break;
case StellarX::controlShape::ELLIPSE:
fillellipse(x, y, width, height);//有边框填充椭圆
outtextxy((x + (width - x - text_width) / 2), (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
break;
case StellarX::controlShape::B_ELLIPSE:
solidellipse(x, y, width, height);//无边框填充椭圆
outtextxy((x + (width - x - text_width) / 2), (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
break;
}
restoreStyle();//恢复默认字体样式和颜色
dirty = false; //标记按钮不需要重绘
}
}
// 处理鼠标事件,检测点击和悬停状态
// 根据按钮模式和形状进行不同的处理
void button::handleEvent(const ExMessage& msg)
{
bool oldHover = hover;
bool oldClick = click;
// 检测悬停状态(根据不同形状)
switch (shape)
{
case StellarX::controlShape::RECTANGLE:
case StellarX::controlShape::B_RECTANGLE:
case StellarX::controlShape::ROUND_RECTANGLE:
case StellarX::controlShape::B_ROUND_RECTANGLE:
hover = (msg.x > x && msg.x < width && msg.y > y && msg.y < height);//判断鼠标是否在矩形按钮内
break;
case StellarX::controlShape::CIRCLE:
case StellarX::controlShape::B_CIRCLE:
hover = isMouseInCircle(msg.x, msg.y, x, y, (width - x) / 2);//判断鼠标是否在圆形按钮内
break;
case StellarX::controlShape::ELLIPSE:
case StellarX::controlShape::B_ELLIPSE:
hover = isMouseInEllipse(msg.x, msg.y, x, y, width, height);//判断鼠标是否在椭圆按钮内
break;
}
if (hover && msg.message == WM_LBUTTONUP)
{
if (mode == StellarX::buttonMode::NORMAL) // 普通按钮 NORMAL
{
click = true;
if (onClickCallback) onClickCallback();
// 刷新消息队列,避免重复处理
flushmessage(EX_MOUSE | EX_KEY);
}
else if (mode == StellarX::buttonMode::TOGGLE) // 切换状态 Toggle
{
click = !click;
if (click && onToggleOnCallback) onToggleOnCallback();
else if (!click && onToggleOffCallback) onToggleOffCallback();
flushmessage(EX_MOUSE | EX_KEY);
}
else if (mode == StellarX::buttonMode::DISABLED) // 禁用状态 Disabled
flushmessage(EX_MOUSE | EX_KEY);
}
if (hover != oldHover || click != oldClick)
dirty = true; // 标记按钮需要重绘
if (dirty)
draw();
if (StellarX::buttonMode::NORMAL == mode)
if (isClicked())
click = false;
}
void button::setOnClickListener(const std::function<void()>&& callback)
{
this->onClickCallback = callback;
}
void button::setOnToggleOnListener(const std::function<void()>&& callback)
{
this->onToggleOnCallback = callback;
}
void button::setOnToggleOffListener(const std::function<void()>&& callback)
{
this->onToggleOffCallback = callback;
}
void button::setbuttonMode(StellarX::buttonMode mode)
{
//取值范围参考 buttMode的枚举注释
this->mode = mode;
}
int button::setROUND_RECTANGLEwidth(int width)
{
return ROUND_RECTANGLEwidth = width;
}
int button::setROUND_RECTANGLEheight(int height)
{
return ROUND_RECTANGLEheight = height;
}
bool button::isClicked() const
{
return this->click;
}
void button::setFillMode(int mode)
{
buttonFillMode = mode;
}
void button::setFillIma(StellarX::fillStyle ima)
{
buttonFillIma = ima;
}
void button::setFillIma(std::string imaNAme)
{
buttonFileIMAGE = new IMAGE;
loadimage(buttonFileIMAGE, imaNAme.c_str(),width-x,height-y);
}
void button::setbuttonBorder(COLORREF Border)
{
buttonBorderColor = Border;
}
void button::setbuttonText(const char* text)
{
this->text = std::string(text);
this->text_width = textwidth(LPCTSTR(this->text.c_str()));
this->text_height = textheight(LPCTSTR(this->text.c_str()));
}
void button::setbuttonText(std::string text)
{
this->text = text;
this->text_width = textwidth(LPCTSTR(this->text.c_str()));
this->text_height = textheight(LPCTSTR(this->text.c_str()));
this->dirty = true; // 标记需要重绘
}
void button::setbuttonShape(StellarX::controlShape shape)
{
this->shape = shape;
}
std::string button::getbuttonText() const
{
return this->text;
}
const char* button::getbuttonText_c() const
{
return this->text.c_str();
}
StellarX::buttonMode button::getbuttonMode() const
{
return this->mode;
}
StellarX::controlShape button::getbuttonShape() const
{
return this->shape;
}
int button::getFillMode() const
{
return this->buttonFillMode;
}
StellarX::fillStyle button::getFillIma() const
{
return this->buttonFillIma;
}
IMAGE* button::getFillImaImage() const
{
return this->buttonFileIMAGE;
}
COLORREF button::getbuttonBorder() const
{
return this->buttonBorderColor;
}
COLORREF button::getbuttonTxtColor() const
{
return this->textStyle.color;
}
StellarX::controlText button::getbuttonTextStyle() const
{
return this->textStyle;
}
bool button::isMouseInCircle(int mouseX, int mouseY, int x, int y, int radius)
{
double dis = sqrt(pow(mouseX - x, 2) + pow(mouseY - y, 2));
if (dis <= radius)
return true;
else
return false;
}
bool button::isMouseInEllipse(int mouseX, int mouseY, int x, int y, int width, int height)
{
int centerX = (x + width) / 2;
int centerY = (y + height) / 2;
int majorAxis = (width - x) / 2;
int minorAxis = (height - y) / 2;
double dx = mouseX - centerX;
double dy = mouseY - centerY;
double normalizedDistance = (dx * dx) / (majorAxis * majorAxis) + (dy * dy) / (minorAxis * minorAxis);
// 判断鼠标是否在椭圆内
if (normalizedDistance <= 1.0)
return true;
else
return false;
}

95
src/Canvas.cpp Normal file
View File

@@ -0,0 +1,95 @@
#include "Canvas.h"
Canvas::Canvas(int x, int y, int width, int height)
:Control(x, y, width, height) {}
void Canvas::draw()
{
saveStyle();
setlinecolor(canvasBorderClor);//设置线色
setfillcolor(canvasBkClor);//设置填充色
setfillstyle((int)canvasFillMode);//设置填充模式
setlinestyle((int)canvasLineStyle, canvaslinewidth);
//根据画布形状绘制
switch (shape)
{
case StellarX::controlShape::RECTANGLE:
fillrectangle(x, y, width, height);//有边框填充矩形
break;
case StellarX::controlShape::B_RECTANGLE:
solidrectangle(x, y, width, height);//无边框填充矩形
break;
case StellarX::controlShape::ROUND_RECTANGLE:
fillroundrect(x, y, width, height, 20, 20);//有边框填充圆角矩形
break;
case StellarX::controlShape::B_ROUND_RECTANGLE:
solidroundrect(x, y, width, height, 20, 20);//无边框填充圆角矩形
break;
}
// 绘制所有子控件
for (auto& control : controls)
control->draw();
restoreStyle();
}
void Canvas::handleEvent(const ExMessage& msg)
{
for (auto& control : controls) {
control->handleEvent(msg);
}
}
void Canvas::addControl(std::unique_ptr<Control> control)
{
controls.push_back(std::move(control));
}
void Canvas::setShape(StellarX::controlShape shape)
{
switch (shape)
{
case StellarX::controlShape::RECTANGLE:
case StellarX::controlShape::B_RECTANGLE:
case StellarX::controlShape::ROUND_RECTANGLE:
case StellarX::controlShape::B_ROUND_RECTANGLE:
this->shape = shape;
break;
case StellarX::controlShape::CIRCLE:
case StellarX::controlShape::B_CIRCLE:
case StellarX::controlShape::ELLIPSE:
case StellarX::controlShape::B_ELLIPSE:
this->shape = StellarX::controlShape::RECTANGLE;
break;
}
}
void Canvas::setcanvasfillMode(StellarX::fillMode mode)
{
this->canvasFillMode = mode;
}
void Canvas::setBorderColor(COLORREF color)
{
this->canvasBorderClor = color;
}
void Canvas::setCanvasBkColor(COLORREF color)
{
this->canvasBkClor = color;
}
void Canvas::setcanvasLineStyle(StellarX::lineStyle style)
{
this->canvasLineStyle = style;
}
void Canvas::setlinewidth(int width)
{
this->canvaslinewidth = width;
}

64
src/Control.cpp Normal file
View File

@@ -0,0 +1,64 @@
#include "Control.h"
StellarX::controlText& StellarX::controlText::operator=(const controlText& text)
{
{
nHeight = text.nHeight;
nWidth = text.nWidth;
lpszFace = text.lpszFace;
color = text.color;
nEscapement = text.nEscapement;
nOrientation = text.nOrientation;
nWeight = text.nWeight;
bItalic = text.bItalic;
bUnderline = text.bUnderline;
bStrikeOut = text.bStrikeOut;
return *this;
}
}
bool StellarX::controlText::operator!=(const controlText& text)
{
if(nHeight != text.nHeight)
return true;
else if (nWidth != text.nWidth)
return true;
else if (lpszFace != text.lpszFace)
return true;
else if (color != text.color)
return true;
else if (nEscapement != text.nEscapement)
return true;
else if (nOrientation != text.nOrientation)
return true;
else if (nWeight != text.nWeight)
return true;
else if (bItalic != text.bItalic)
return true;
else if (bUnderline != text.bUnderline)
return true;
else if (bStrikeOut != text.bStrikeOut)
return true;
return false;
}
// 保存当前的绘图状态(字体、颜色、线型等)
// 在控件绘制前调用,确保不会影响全局绘图状态
void Control::saveStyle()
{
gettextstyle(&currentFont); // 获取当前字体样式
currentColor = gettextcolor(); // 获取当前字体颜色
currentBorderColor = getlinecolor(); //保存当前边框颜色
getlinestyle(currentLineStyle); //保存当前线型
currentBkColor = getfillcolor(); //保存当前填充色
}
// 恢复之前保存的绘图状态
// 在控件绘制完成后调用,恢复全局绘图状态
void Control::restoreStyle()
{
settextstyle(&currentFont); // 恢复默认字体样式
settextcolor(currentColor); // 恢复默认字体颜色
setfillcolor(currentBkColor);
setlinestyle(currentLineStyle);
setlinecolor(currentBorderColor);
setfillstyle(BS_SOLID);//恢复填充
}

55
src/label.cpp Normal file
View File

@@ -0,0 +1,55 @@
#include "label.h"
label::label()
:Control(0, 0, 0, 0)
{
this->text = "默认标签";
textColor = RGB(0,0,0);
textBkColor = RGB(255, 255, 255);; //默认白色背景
}
label::label(int x, int y, std::string text, COLORREF textcolor, COLORREF bkColor)
:Control(x, y, 0, 0)
{
this->text = text;
textColor = textcolor;
textBkColor = bkColor; //默认白色背景
}
void label::draw()
{
saveStyle();
if (textBkDisap)
setbkmode(TRANSPARENT); //设置背景透明
else
{
setbkmode(OPAQUE); //设置背景不透明
setbkcolor(textBkColor); //设置背景颜色
}
settextcolor(textColor);
settextstyle(textStyle.nHeight, textStyle.nWidth, textStyle.lpszFace,
textStyle.nEscapement, textStyle.nOrientation, textStyle.nWeight,
textStyle.bItalic, textStyle.bUnderline, textStyle.bStrikeOut); //设置字体样式
outtextxy(x,y, LPCTSTR(text.c_str()));
restoreStyle();
}
void label::setTxtdisap(bool key)
{
textBkDisap = key;
}
void label::setTxtColor(COLORREF color)
{
textColor = color;
}
void label::setTxtBkColor(COLORREF color)
{
textBkColor = color;
}
void label::setText(std::string text)
{
this->text = text;
}

403
src/table.cpp Normal file
View File

@@ -0,0 +1,403 @@
#include "table.h"
// 绘制表格的当前页
// 使用双循环绘制行和列,考虑分页偏移
void table::drawTable()
{
dX = x;
dY = uY;
uY = dY + lineHeights.at(0) + 10;
for (int i = (currentPage * rowsPerPage - rowsPerPage); i < (currentPage*rowsPerPage) && i < data.size(); i++)
{
for (int j = 0; j < data[i].size(); j++)
{
uX = dX + colWidths.at(j) + 20;
fillrectangle(dX, dY, uX, uY);
outtextxy(dX + 10, dY + 5, LPCTSTR(data[i][j].c_str()));
dX += this->colWidths.at(j) + 20;
}
dX = x;
dY = uY;
uY = dY + lineHeights.at(0) + 10;
}
uY = y + lineHeights.at(0) + 10;
}
void table::drawHeader()
{
uY = dY + lineHeights.at(0) + 10;
for(int i = 0; i < headers.size(); i++)
{
uX = dX + colWidths.at(i) + 20;
fillrectangle(dX, dY, uX, uY);
outtextxy(dX + 10, dY + 5, LPCTSTR(headers[i].c_str()));
dX += this->colWidths.at(i) + 20;
}
}
// 初始化文本宽度和高度计算
// 遍历所有数据和表头,计算每列的最大宽度和行高
// 此方法在数据变更时自动调用
void table::initTextWaH()
{
this->colWidths.resize(this->headers.size());
this->lineHeights.resize(this->headers.size());
int width = 0;
int height = 0;
//计算数据尺寸
for (int i = 0; i < data.size(); i++)
{
for (int j = 0; j < data[i].size(); j++)
{
width = textwidth(LPCTSTR(data[i][j].c_str()));
height = textheight(LPCTSTR(data[i][j].c_str()));
if (width > this->colWidths.at(j))
this->colWidths.at(j) = width;
if (height > this->lineHeights[j])
this->lineHeights.at(j) = height;
}
}
for (int i = 0; i < this->headers.size(); i++)
{
width = textwidth(LPCTSTR(headers[i].c_str()));
height = textheight(LPCTSTR(headers[i].c_str()));
if (width > this->colWidths.at(i))
this->colWidths.at(i) = width;
if (height > this->lineHeights[i])
this->lineHeights.at(i) = height;
}
// 计算表格总宽度和高度
this->width = 0;
for (int i = 0; i < colWidths.size(); i++)
this->width += colWidths.at(i) + 20;
LINESTYLE currentStyle;
this->width += tableBorderWidth;
this->height = lineHeights.at(0) * (rowsPerPage + 1) + rowsPerPage * 10+20 ; // 表头+数据行+页码区域
// 如果背景图像不存在或尺寸不匹配,创建或重新创建
if (saveBkImage == nullptr) {
saveBkImage = new IMAGE(width, height);
}
else if (saveBkImage->getwidth() != width || saveBkImage->getheight() != height) {
delete saveBkImage;
saveBkImage = new IMAGE(width, height);
}
}
void table::initButton()
{
int x1, x2;
int y1, y2;
x1 = pX - 70;
x2 = pX + textwidth(LPCTSTR(pageNumtext.c_str())) + 10;
y1 = y2 = pY;
this->prevButton = new button(x1, y1, 60, textheight(LPCTSTR(pageNumtext.c_str())), "上一页", RGB(0, 0, 0), RGB(255, 255, 255));
this->nextButton = new button(x2, y2, 60, textheight(LPCTSTR(pageNumtext.c_str())), "下一页", RGB(0, 0, 0), RGB(255, 255, 255));
prevButton->setOnClickListener([this]()
{if (this->currentPage > 1)
{
this->currentPage--;
this->dirty = true;
this->draw();
} });
nextButton->setOnClickListener([this]()
{if (this->currentPage < (this->totalPages))
{
this->currentPage++;
this->dirty = true;
this->draw();
}});
}
void table::initPageNum()
{
if (0 == pY)
pY = uY + lineHeights.at(0) * rowsPerPage + rowsPerPage * 10+10;
for (int i = 0; i < colWidths.size(); i++)
this->pX += colWidths.at(i) + 20;
this->pX -= textwidth(LPCTSTR(pageNumtext.c_str()));
this->pX /= 2;
this->pX += x;
this->pageNum = new label(this->pX, pY, pageNumtext);
//pageNum->setTxtdisap(true);
pageNum->textStyle = this->textStyle;
}
void table::drawPageNum()
{
if (nullptr == pageNum)
initPageNum();
pageNumtext = std::to_string(currentPage);
pageNumtext += "页/第";
pageNumtext += std::to_string(totalPages);
pageNumtext += "";
pageNum->setText(pageNumtext);
pageNum->draw();
}
void table::drawButton()
{
if (nullptr == prevButton || nullptr == nextButton)
initButton();
prevButton->draw();
nextButton->draw();
}
table::table(int x, int y)
:Control(x, y, 0,0)
{
//this->saveBkImage = new IMAGE(this->width,this->height);
}
table::~table()
{
if (this->prevButton)
delete this->prevButton;
if (this->nextButton)
delete this->nextButton;
if (this->pageNum)
delete this->pageNum;
if (this->saveBkImage)
delete this->saveBkImage;
this->prevButton = nullptr;
this->nextButton = nullptr;
this->pageNum = nullptr;
this->saveBkImage = nullptr;
}
void table::draw()
{
if (this->dirty)
{
// 先保存当前绘图状态
saveStyle();
// 设置表格样式
setfillcolor(tableBkClor);
setlinecolor(tableBorderClor);
settextstyle(textStyle.nHeight, textStyle.nWidth, textStyle.lpszFace,
textStyle.nEscapement, textStyle.nOrientation, textStyle.nWeight,
textStyle.bItalic, textStyle.bUnderline, textStyle.bStrikeOut);
settextcolor(textStyle.color);
setlinestyle((int)tableLineStyle, tableBorderWidth);
setfillstyle((int)tableFillMode);
setbkmode(TRANSPARENT);
// 是否需要计算单元格尺寸
if (isNeedCellSize)
{
initTextWaH();
isNeedCellSize = false;
}
// 在绘制表格之前捕获背景
// 只有在第一次绘制或者尺寸变化时才需要重新捕获背景
static bool firstDraw = true;
if (firstDraw || isNeedDrawHeaders) {
// 确保在绘制任何表格内容之前捕获背景
if (saveBkImage) {
// 临时恢复样式,确保捕获正确的背景
restoreStyle();
if(tableBorderWidth>1)
getimage(saveBkImage, this->x- tableBorderWidth, this->y- tableBorderWidth, this->width+ tableBorderWidth, this->height+ tableBorderWidth);
else
getimage(saveBkImage, this->x, this->y, this->width, this->height);
saveStyle(); // 重新保存样式
// 重新设置表格样式
setfillcolor(tableBkClor);
setlinecolor(tableBorderClor);
settextstyle(textStyle.nHeight, textStyle.nWidth, textStyle.lpszFace,
textStyle.nEscapement, textStyle.nOrientation, textStyle.nWeight,
textStyle.bItalic, textStyle.bUnderline, textStyle.bStrikeOut);
settextcolor(textStyle.color);
setlinestyle((int)tableLineStyle, tableBorderWidth);
setfillstyle((int)tableFillMode);
setbkmode(TRANSPARENT);
}
firstDraw = false;
}
// 恢复背景(清除旧内容)
if (saveBkImage) {
if (tableBorderWidth > 1)
putimage(this->x - tableBorderWidth, this->y - tableBorderWidth, saveBkImage);
else
putimage(this->x,this->y,this->saveBkImage);
}
// 绘制表头
dX = x;
dY = y;
drawHeader();
this->isNeedDrawHeaders = false;
// 绘制当前页
drawTable();
// 绘制页码标签
drawPageNum();
// 绘制翻页按钮
if (this->isShowPageButton)
drawButton();
// 恢复绘图状态
restoreStyle();
dirty = false; // 标记不需要重绘
}
}
void table::handleEvent(const ExMessage& msg)
{
if(!this->isShowPageButton)
return;
else
{
prevButton->handleEvent(msg);
nextButton->handleEvent(msg);
}
}
void table::setHeaders(std::initializer_list<std::string> headers)
{
this->headers.clear();
for (auto lis : headers)
this->headers.push_back(lis);
isNeedCellSize = true; // 标记需要重新计算单元格尺寸
isNeedDrawHeaders = true; // 标记需要重新绘制表头
dirty = true;
}
void table::setData(const std::vector<std::string>& data)
{
this->data.push_back(data);
totalPages = (this->data.size() + rowsPerPage - 1) / rowsPerPage;
if (totalPages < 1)
totalPages = 1;
isNeedCellSize = true; // 标记需要重新计算单元格尺寸
dirty = true;
}
void table::setData(const std::initializer_list<std::vector<std::string>>& data)
{
for (auto lis : data)
this->data.push_back(lis);
totalPages = (this->data.size() + rowsPerPage - 1) / rowsPerPage;
if (totalPages < 1)
totalPages = 1;
isNeedCellSize = true; // 标记需要重新计算单元格尺寸
dirty = true;
}
void table::setRowsPerPage(int rows)
{
this->rowsPerPage = rows;
totalPages = (data.size() + rowsPerPage - 1) / rowsPerPage;
if (totalPages < 1)
totalPages = 1;
isNeedCellSize = true; // 标记需要重新计算单元格尺寸
dirty = true;
}
void table::showPageButton(bool isShow)
{
this->isShowPageButton = isShow;
}
void table::settableBorder(COLORREF color)
{
this->tableBorderClor = color;
}
void table::settableBk(COLORREF color)
{
this->tableBkClor = color;
}
void table::settableFillMode(StellarX::fillMode mode)
{
if (StellarX::fillMode::Solid == mode || StellarX::fillMode::Null == mode)
this->tableFillMode = mode;
else
this->tableFillMode = StellarX::fillMode::Solid;
}
void table::settableLineStyle(StellarX::lineStyle style)
{
this->tableLineStyle = style;
}
void table::settableBorderWidth(int width)
{
this->tableBorderWidth = width;
}
int table::getCurrentPage() const
{
return this->currentPage;
}
int table::getTotalPages() const
{
return this->totalPages;;
}
int table::getRowsPerPage() const
{
return this->rowsPerPage;
}
bool table::getShowPageButton() const
{
return this->isShowPageButton;
}
COLORREF table::gettableBorder() const
{
return this->tableBorderClor;
}
COLORREF table::gettableBk() const
{
return this->tableBkClor;
}
StellarX::fillMode table::gettableFillMode() const
{
return this->tableFillMode;
}
StellarX::lineStyle table::gettableLineStyle() const
{
return this->tableLineStyle;
}
std::vector<std::string> table::getHeaders() const
{
return this->headers;
}
std::vector<std::vector<std::string>> table::getData() const
{
return this->data;
}
int table::gettableBorderWidth() const
{
return this->tableBorderWidth;
}

135
src/textBox.cpp Normal file
View File

@@ -0,0 +1,135 @@
// TxtBox.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)
{
}
void textBox::draw()
{
if(dirty)
{
saveStyle();
setfillcolor(textBoxBkClor);
setlinecolor(textBoxBorderClor);
if (textStyle.nHeight > height - y)
textStyle.nHeight = height;
if (textStyle.nWidth > width - x)
textStyle.nWidth = width;
settextstyle(textStyle.nHeight, textStyle.nWidth, textStyle.lpszFace,
textStyle.nEscapement, textStyle.nOrientation, textStyle.nWeight,
textStyle.bItalic, textStyle.bUnderline, textStyle.bStrikeOut);
settextcolor(textStyle.color);
setbkmode(TRANSPARENT);
int text_width = textwidth(LPCTSTR(text.c_str()));
int text_height = textheight(LPCTSTR(text.c_str()));
//根据形状绘制
switch (shape)
{
case StellarX::controlShape::RECTANGLE:
fillrectangle(x, y, width, height);//有边框填充矩形
outtextxy(x + 10, (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
break;
case StellarX::controlShape::B_RECTANGLE:
solidrectangle(x, y, width, height);//无边框填充矩形
outtextxy(x + 10, (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
break;
case StellarX::controlShape::ROUND_RECTANGLE:
fillroundrect(x, y, width, height, 20, 20);//有边框填充圆角矩形
outtextxy(x + 10, (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
break;
case StellarX::controlShape::B_ROUND_RECTANGLE:
solidroundrect(x, y, width, height, 20, 20);//无边框填充圆角矩形
outtextxy(x + 10, (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
break;
}
}
restoreStyle();
dirty = false; //标记不需要重绘
}
void textBox::handleEvent(const ExMessage& msg)
{
bool hover = false;
bool oldClick = click;
switch (shape)
{
case StellarX::controlShape::RECTANGLE:
case StellarX::controlShape::B_RECTANGLE:
case StellarX::controlShape::ROUND_RECTANGLE:
case StellarX::controlShape::B_ROUND_RECTANGLE:
hover = (msg.x > x && msg.x < width && msg.y > y && msg.y < height);//判断鼠标是否在矩形按钮内
break;
}
if (hover && msg.message == WM_LBUTTONUP)
{
click = true;
if(StellarX::textBoxmode::INPUT_MODE == mode)
dirty = InputBox(LPTSTR(text.c_str()), maxCharLen,"输入框",NULL,text.c_str(), NULL ,NULL,false);
else if (StellarX::textBoxmode::READONLY_MODE == mode)
{
dirty = false;
InputBox(NULL, maxCharLen, "输出框(输入无效!)", NULL, text.c_str(), NULL, NULL, false);
}
flushmessage(EX_MOUSE | EX_KEY);
}
if (dirty)
draw();
if (click)
click = false;
}
void textBox::setMode(StellarX::textBoxmode mode)
{
this->mode = mode;
}
void textBox::setmaxCharLen(int len)
{
if (len > 0)
maxCharLen = len;
}
void textBox::settextBoxshape(StellarX::controlShape shape)
{
switch (shape)
{
case StellarX::controlShape::RECTANGLE:
case StellarX::controlShape::B_RECTANGLE:
case StellarX::controlShape::ROUND_RECTANGLE:
case StellarX::controlShape::B_ROUND_RECTANGLE:
this->shape = shape;
break;
case StellarX::controlShape::CIRCLE:
case StellarX::controlShape::B_CIRCLE:
case StellarX::controlShape::ELLIPSE:
case StellarX::controlShape::B_ELLIPSE:
this->shape = StellarX::controlShape::RECTANGLE;
break;
}
}
void textBox::settextBoxBorder(COLORREF color)
{
textBoxBorderClor = color;
}
void textBox::settextBoxBk(COLORREF color)
{
textBoxBkClor = color;
}
std::string textBox::gettext()
{
return this->text;
}

114
src/window.cpp Normal file
View File

@@ -0,0 +1,114 @@
#include "window.h"
window::window(int width, int height, int mode)
{
this->width = width;
this->height = height;
this->windowMode = mode;
}
window::window(int width, int height, int mode, COLORREF bkcloc)
{
this->width = width;
this->height = height;
this->windowMode = mode;
this->wBkcolor = bkcloc;
}
window::window(int width, int height, int mode, COLORREF bkcloc, std::string headline)
{
this->width = width;
this->height = height;
this->windowMode = mode;
this->wBkcolor = bkcloc;
this->headline = headline;
}
window::~window()
{
if (background)
delete background;
background = nullptr;
closegraph(); // 确保关闭图形上下文
}
void window::draw()
{
hWnd = initgraph(width, height, windowMode);
SetWindowText(hWnd,headline.c_str());
setbkcolor(wBkcolor);
cleardevice();
BeginBatchDraw(); // 开始批量绘制
// 绘制所有子控件
for (auto& control : controls)
control->draw();
EndBatchDraw(); // 结束批量绘制
}
// 使用背景图片绘制窗口
// @参数 pImgFile: 图片文件路径,支持常见图片格式
// @备注: 会拉伸图片以适应窗口尺寸
void window::draw(std::string pImgFile)
{
this->background = new IMAGE;
hWnd = initgraph(width, height, windowMode);
SetWindowText(hWnd, headline.c_str());
loadimage(background, pImgFile.c_str(), width, height, true);
putimage(0,0, background);
// 绘制所有子控件
BeginBatchDraw(); // 开始批量绘制
for (auto& control : controls)
control->draw();
EndBatchDraw(); // 结束批量绘制
}
// 运行主事件循环,处理用户输入和窗口消息
// 此方法会阻塞直到窗口关闭
void window::runEventLoop()
{
ExMessage msg;
bool running = true;
while (running) {
msg = getmessage(EX_MOUSE | EX_KEY);
if (msg.message == WM_CLOSE) {
running = false;
continue;
}
for (auto& c : controls)
c->handleEvent(msg);
flushmessage(EX_MOUSE |EX_KEY |EX_CHAR|EX_WINDOW);
Sleep(10);
}
}
void window::setBkImage(std::string pImgFile)
{
if(nullptr == background)
this->background = new IMAGE;
else
delete background;
this->background = new IMAGE;
loadimage(background, pImgFile.c_str(), width, height, true);
putimage(0, 0, background);
}
void window::setBkcolor(COLORREF c)
{
wBkcolor = c;
}
void window::setHeadline(std::string headline)
{
this->headline = headline;
SetWindowText(this->hWnd, headline.c_str());
}
void window::addControl(std::unique_ptr<Control> control)
{
this->controls.push_back(std::move(control));
}