Files
EzUI/doc/Control_Guide.md
2026-02-20 21:58:42 +08:00

28 KiB
Raw Blame History

EzUI Control 基类权威指南

本文档是 EzUI C++ UI 框架的核心参考资料,面向初学者入门。


目录

  1. 类概述
  2. 核心属性详解
  3. 核心方法详解
  4. CSS 样式属性映射表
  5. 事件系统
  6. 最佳实践与常见陷阱
  7. 附录:速查表

1. 类概述

1.1 Control 在 UI 库架构中的定位

Control 是 EzUI 框架中所有 UI 控件的基类,位于 include/EzUI/Control.h 中。它继承了 Object 类,是构建整个 UI 界面的核心抽象。

Object (基类)
    │
    └── Control (UI控件基类)
            ├── Label (文本显示)
            │       └── Button (按钮)
            ├── TextBox (文本框)
            ├── ComboBox (下拉框)
            ├── CheckBox / RadioButton
            ├── PictureBox (图片)
            ├── ProgressBar (进度条)
            ├── HLayout / VLayout (布局容器)
            ├── HListView / VListView / TileListView / PagedListView (列表)
            ├── TreeView (树形视图)
            ├── TableView (表格)
            ├── TabLayout (标签页)
            └── ScrollBar / HScrollBar / VScrollBar (滚动条)

注意Window 类并非直接继承自 Control而是继承自 Object。它是顶级窗口与 Control 是并行的类层次结构。

1.2 Control 的核心职责

Control 类承担以下四大职责:

职责 描述
渲染 管理控件的外观绘制,包括背景、前景、边框
布局 计算控件的位置和尺寸,处理子控件的排列
事件处理 接收和响应鼠标、键盘等用户交互事件
状态管理 维护控件的可见性、启用状态、悬停/按下等状态

1.3 快速入门示例

#include <EzUI.h>

using namespace EzUI;

int main() {
    Application::Init();

    Window window;
    window.SetSize(800, 600);
    window.SetTitle("Control Demo");

    // 创建布局容器
    VLayout* layout = new VLayout();
    window.Add(layout);

    // 创建按钮
    Button* btn = new Button();
    btn->SetText("Click Me");
    btn->SetFixedSize(120, 40);
    btn->SetLocation(100, 100);

    // 绑定事件
    btn->EventHandler = [](Control* sender, EventArgs& args) {
        if (args.EventType == Event::OnMouseUp) {
            MessageBox(NULL, "Button Clicked!", "Info", MB_OK);
        }
    };

    layout->Add(btn);

    window.Show();
    return Application::Run();
}

2. 核心属性详解

2.1 几何属性

2.1.1 位置属性

属性 类型 作用
X() int 获取控件相对于父容器的 X 坐标
Y() int 获取控件相对于父容器的 Y 坐标
SetX(int) void 设置 X 坐标
SetY(int) void 设置 Y 坐标
SetLocation(const Point&) void 同时设置 X 和 Y 坐标

代码示例

// 设置位置的三种方式
control->SetX(100);
control->SetY(200);

// 或
control->SetLocation(Point(100, 200));

// 获取位置
Point pos = control->GetLocation();  // 等价于 Point(control->X(), control->Y())

2.1.2 尺寸属性

属性 类型 作用
Width() int 获取控件宽度
Height() int 获取控件高度
SetWidth(int) void 设置宽度
SetHeight(int) void 设置高度
SetSize(const Size&) void 同时设置宽高
SetFixedSize(const Size&) void 设置固定尺寸(优先级最高)
SetFixedWidth(int) void 设置固定宽度
SetFixedHeight(int) void 设置固定高度
SetRateWidth(float) void 设置宽度为父容器的百分比 (0.0-1.0)
SetRateHeight(float) void 设置高度为父容器的百分比 (0.0-1.0)
GetRect() const Rect& 获取控件矩形区域(布局计算后)

代码示例

// 固定尺寸
control->SetFixedSize(Size(200, 100));
control->SetFixedWidth(200);
control->SetFixedHeight(100);

// 百分比尺寸(响应式布局)
control->SetRateWidth(0.5f);   // 宽度为父容器的50%
control->SetRateHeight(0.25f); // 高度为父容器的25%

// 自动尺寸
control->SetAutoWidth(true);
control->SetAutoHeight(true);
control->SetAutoSize(true);    // 同时设置自动宽高

2.1.3 外边距 (Margin)

属性 类型 作用
Margin Distance 设置控件外边距,影响在父容器中的布局

代码示例

// 设置外边距
control->Margin.Left = 10;
control->Margin.Top = 20;
control->Margin.Right = 10;
control->Margin.Bottom = 20;

// 或使用 Distance 构造函数
control->Margin = Distance(10, 20); // 左+右=10, 上+下=20

2.1.4 停靠样式 (Dock)

属性 类型 作用
GetDockStyle() DockStyle 获取停靠样式
SetDockStyle(const DockStyle&) void 设置停靠样式

DockStyle 枚举值

描述
DockStyle::None 不停靠,使用绝对定位
DockStyle::Horizontal 水平停靠,从左到右排列
DockStyle::Vertical 垂直停靠,从上到下排列
DockStyle::Fill 填满剩余空间

代码示例

// 填满父容器
control->SetDockStyle(DockStyle::Fill);

// 垂直停靠(类似 StackPanel
layout->SetDockStyle(DockStyle::Vertical);

2.2 视觉属性

2.2.1 可见性

属性 类型 作用
IsVisible() bool 获取控件是否可见
SetVisible(bool) void 设置控件可见性
Show() void 显示控件(等价于 SetVisible(true)
Hide() void 隐藏控件(等价于 SetVisible(false)

代码示例

// 显示/隐藏控件
control->SetVisible(true);
control->Show();

control->SetVisible(false);
control->Hide();

// 判断可见性
if (control->IsVisible()) {
    // 控件可见
}

2.2.2 启用状态

属性 类型 作用
IsEnabled() bool 获取控件是否启用
SetEnabled(bool) void 设置控件启用/禁用
SetDisabled(bool) void 设置控件禁用/启用

代码示例

// 禁用控件(变灰,不可交互)
control->SetEnabled(false);
control->SetDisabled(true); // 等价

// 启用控件
control->SetEnabled(true);
control->SetDisabled(false);

2.2.3 样式状态

Control 支持多套样式,分别对应不同的交互状态:

属性 类型 作用
Style ControlStyle 静态/默认状态样式
HoverStyle ControlStyle 鼠标悬停状态样式
ActiveStyle ControlStyle 鼠标按下状态样式
DisabledStyle ControlStyle 禁用状态样式

ControlStyle 结构

struct ControlStyle {
    ezui::Border Border;        // 边框
    Color BackColor = 0;         // 背景颜色
    Image* BackImage = NULL;    // 背景图片
    Image* ForeImage = NULL;    // 前景图片
    std::wstring FontFamily;    // 字体名称
    int FontSize = 0;            // 字体大小
    Color ForeColor;             // 前景颜色(文字颜色)
    HCURSOR Cursor = NULL;       // 鼠标光标
    float Angle = 0;             // 旋转角度 (0-360)
};

代码示例

// 编程方式设置样式
control->Style.BackColor = Color(255, 255, 255);  // 白色背景
control->Style.Border.Left = 1;                    // 左边框宽度
control->Style.Border.LeftColor = Color(200, 200, 200);
control->Style.FontSize = 14;

// 使用 CSS 字符串设置样式(更方便)
control->SetStyleSheet(ControlState::Static,
    "background-color:#FFFFFF;border:1px solid #CCCCCC;font-size:14px");

control->SetStyleSheet(ControlState::Hover,
    "background-color:#E0E0E0");

2.3 层级属性

2.3.1 父子关系

属性 类型 作用
Parent Control* 获取父控件指针(公共属性)
SetParent(Control*) void 设置父控件

代码示例

// 设置父控件(推荐方式)
parentLayout->Add(childControl);

// 或
childControl->SetParent(parentLayout);

// 获取父控件
Control* parent = childControl->Parent;
if (parent) {
    // 父控件存在
}

2.3.2 子控件集合

方法 作用
GetControls() 获取所有子控件集合
GetViewControls() 获取可见的子控件集合
Add(Control*) 添加子控件到末尾
Insert(int, Control*) 在指定位置插入子控件
Remove(Control*, bool freeCtrl = false) 移除子控件
Clear(bool freeChilds = false) 清除所有子控件
GetControl(int pos) 按索引获取子控件(跳过占位符)
IndexOf(Control*) 获取子控件索引

代码示例

// 添加子控件
VLayout* layout = new VLayout();
layout->Add(new Button());
layout->Add(new Label());

// 插入到指定位置
layout->Insert(0, new Control()); // 插入到开头

// 移除子控件
Control* child = layout->GetControl(0);
layout->Remove(child);            // 移除但不删除
layout->Remove(child, true);      // 移除并删除

// 遍历子控件
for (Control* ctl : layout->GetControls()) {
    ctl->SetVisible(false);
}

// 清空子控件
layout->Clear();           // 移除但不删除子控件对象
layout->Clear(true);      // 移除并删除子控件对象

2.4 标识属性

属性 类型 作用
Name UIString 控件名称(用于查找)

代码示例

// 设置名称
control->Name = "submitButton";

// 通过名称查找控件
Control* found = window.FindControl("submitButton");

// 查找具有特定属性值的控件
Controls results = window.FindControl("type", "button");

2.5 状态属性

2.5.1 控件状态枚举

enum class ControlState : int {
    None = 1,      // 无状态
    Static = 2,   // 静态/默认
    Disabled = 4, // 禁用
    Checked = 8,  // 选中(复选框/单选按钮)
    Hover = 16,   // 鼠标悬停
    Active = 32   // 鼠标按下/激活
};

2.5.2 获取状态

方法 作用
State 获取当前控件状态
GetLayoutState() 获取当前布局状态

代码示例

// 判断当前状态
if (control->State == ControlState::Hover) {
    // 鼠标正在控件上
}

if (control->State == ControlState::Active) {
    // 控件正在被按下
}

// 布局状态
LayoutState layoutState = control->GetLayoutState();
if (layoutState == LayoutState::Pend) {
    // 布局已挂起,需要重新布局
}

3. 核心方法详解

3.1 构造函数与析构函数

// 构造函数
Control(Object* parentObject = NULL);

// 析构函数
virtual ~Control();

行为说明

  • 构造函数接受一个可选的父对象指针
  • 如果传入父控件,子控件会被自动添加到父控件的子集合中
  • 析构函数会自动销毁所有子控件(递归)

代码示例

// 方式1创建后手动添加
Control* child = new Control();
parent->Add(child);

// 方式2创建时指定父控件推荐
Control* child = new Control(parent); // 自动添加到 parent 的子控件集合

3.2 布局相关方法

布局是 EzUI 的核心特性之一,采用了延迟布局机制以提高性能。

3.2.1 布局状态机

┌─────────────┐
│    None     │ ←─── 布局完成状态
└──────┬──────┘
       │ TryPendLayout()
       ▼
┌─────────────┐
│    Pend     │ ←─── 布局已挂起,等待下次布局
└──────┬──────┘
       │ OnLayout()
       ▼
┌─────────────┐
│ Layouting   │ ←─── 正在布局中
└──────┬──────┘
       │ EndLayout()
       ▼
       None

3.2.2 核心布局方法

方法 作用
TryPendLayout() 挂起布局,请求重新布局
RefreshLayout() 强制立即刷新布局
GetLayoutState() 获取当前布局状态
IsPendLayout() 检查是否挂起了布局
EndLayout() 结束当前布局
OnLayout() 虚函数,子类可重写实现自定义布局逻辑

代码示例

// 修改尺寸后,布局会自动挂起
control->SetFixedSize(Size(200, 100));

// 手动触发布局刷新
control->RefreshLayout();

// 检查布局状态
if (control->IsPendLayout()) {
    // 需要重新布局
}

3.3 渲染相关方法

3.3.1 渲染流程

┌────────────────────────────────────┐
│         OnPaintBefore()            │  ← 绘制前处理(可重写)
└──────────────┬─────────────────────┘
               ▼
┌────────────────────────────────────┐
│       OnBackgroundPaint()          │  ← 绘制背景(可重写)
└──────────────┬─────────────────────┘
               ▼
┌────────────────────────────────────┐
│         OnForePaint()              │  ← 绘制前景内容(可重写)
└──────────────┬─────────────────────┘
               ▼
┌────────────────────────────────────┐
│        OnBorderPaint()             │  ← 绘制边框(可重写)
└──────────────┬─────────────────────┘
               ▼
┌────────────────────────────────────┐
│         OnChildPaint()             │  ← 绘制子控件
└────────────────────────────────────┘

3.3.2 渲染方法列表

方法 作用
OnPaintBefore(PaintEventArgs&) 绘制前回调,可重写
OnBackgroundPaint(PaintEventArgs&) 绘制背景回调,可重写
OnForePaint(PaintEventArgs&) 绘制前景回调,可重写
OnBorderPaint(PaintEventArgs&, const Border&) 绘制边框回调,可重写
OnChildPaint(PaintEventArgs&) 绘制子控件回调,可重写
Refresh() 立即重绘
Invalidate() 延迟重绘(更高效)

代码示例

// 方式1立即重绘
control->Refresh();

// 方式2延迟重绘推荐多次修改只重绘一次
control->Invalidate();
control->Invalidate(); // 多次调用只重绘一次

// 自定义绘制
class MyControl : public Control {
protected:
    virtual void OnForePaint(PaintEventArgs& e) override {
        // 获取绘图上下文
        Graphics& g = e.Graphics;

        // 绘制自定义内容
        Rect rect = GetRect();
        g.DrawString(L"Hello", rect);

        // 调用基类
        Control::OnForePaint(e);
    }
};

3.4 事件处理方法

3.4.1 事件分发机制

用户操作
    │
    ▼
Window 消息循环
    │
    ▼
Control::SendEvent(EventArgs)
    │
    ├── ▼ 控件禁用? → 拦截鼠标/键盘事件
    │
    ▼
Control::OnEvent(EventArgs)
    │
    ├── OnMouseEvent() / OnKeyBoardEvent()
    │       │
    │       ▼
    │       具体事件处理 (OnMouseDown, OnMouseUp...)
    │
    ▼
EventHandler 回调(如果有)
    │
    ▼
Frame::OnNotify()(如果在 NotifyFlags 中)

3.4.2 事件处理方法列表

鼠标事件

方法 作用
OnMouseEvent(const MouseEventArgs&) 鼠标事件总入口
OnMouseEnter(const MouseEventArgs&) 鼠标进入
OnMouseLeave(const MouseEventArgs&) 鼠标离开
OnMouseMove(const MouseEventArgs&) 鼠标移动
OnMouseDown(const MouseEventArgs&) 鼠标按下
OnMouseUp(const MouseEventArgs&) 鼠标释放
OnMouseWheel(const MouseEventArgs&) 鼠标滚轮
OnMouseDoubleClick(const MouseEventArgs&) 鼠标双击

键盘事件

方法 作用
OnKeyBoardEvent(const KeyboardEventArgs&) 键盘事件总入口
OnKeyDown(const KeyboardEventArgs&) 键盘按下
OnKeyUp(const KeyboardEventArgs&) 键盘释放
OnKeyChar(const KeyboardEventArgs&) 字符输入

焦点事件

方法 作用
OnFocus(const FocusEventArgs&) 获得焦点
OnKillFocus(const KillFocusEventArgs&) 失去焦点

其他事件

方法 作用
OnMove(const MoveEventArgs&) 位置改变
OnSize(const SizeEventArgs&) 尺寸改变
OnDpiChange(const DpiChangeEventArgs&) DPI 改变

代码示例

// 方式1使用 EventHandler 回调
button->EventHandler = [](Control* sender, EventArgs& args) {
    switch (args.EventType) {
        case Event::OnMouseUp:
            // 处理点击
            break;
        case Event::OnMouseEnter:
            // 处理鼠标进入
            break;
    }
};

// 方式2重写虚函数需要继承
class MyButton : public Button {
protected:
    virtual void OnMouseUp(const MouseEventArgs& arg) override {
        // 自定义处理逻辑
        Button::OnMouseUp(arg); // 可选:调用基类
    }
};

3.5 生命周期方法

方法 作用 调用时机
OnRemove() 移除回调 控件从父容器移除时
GetCursor(ControlState) 获取光标 需要显示特定光标时

4. CSS 样式属性映射表

EzUI 支持使用 CSS 字符串设置控件样式。以下是完整的属性映射:

CSS 属性 C++ 属性/方法 值类型 示例
背景
background-color Style.BackColor Color background-color:#FFFFFF
background-image Style.BackImage Image* background-image:res.png
background-position - - (暂不支持)
background-size - - (暂不支持)
前景
fore-color / color Style.ForeColor Color color:#000000
fore-image Style.ForeImage Image* fore-image:icon.png
fore-image-size - - (暂不支持)
边框
border Style.Border Border border:1px solid #000000
border-width Style.Border.Left/Top/Right/Bottom int border-width:1
border-style Style.Border.LeftStyle BorderStyle border-style:solid
border-color Style.Border.LeftColor Color border-color:#000000
border-radius Style.Border.LeftRadius int border-radius:5
border-top-left-radius Style.Border.LeftTopRadius int border-top-left-radius:5
border-top-right-radius Style.Border.RightTopRadius int border-top-right-radius:5
border-bottom-left-radius Style.Border.LeftBottomRadius int border-bottom-left-radius:5
border-bottom-right-radius Style.Border.RightBottomRadius int border-bottom-right-radius:5
border-left Style.Border.Left BorderItem border-left:1px solid #000
border-top Style.Border.Top BorderItem border-top:1px solid #000
border-right Style.Border.Right BorderItem border-right:1px solid #000
border-bottom Style.Border.Bottom BorderItem border-bottom:1px solid #000
字体
font-size Style.FontSize int font-size:14
font-family Style.FontFamily wstring font-family:Microsoft YaHei
光标
cursor Style.Cursor HCURSOR cursor:pointer
交互
pointer-events m_hitTestEnabled bool pointer-events:none
定位
x SetX() int x:100
y SetY() int y:200
width SetFixedWidth() int width:200
height SetFixedHeight() int height:100
外边距
margin Margin Distance margin:10
margin-left Margin.Left int margin-left:10
margin-top Margin.Top int margin-top:10
margin-right Margin.Right int margin-right:10
margin-bottom Margin.Bottom int margin-bottom:10

代码示例

// 设置静态样式
control->SetStyleSheet(ControlState::Static,
    "background-color:#FFFFFF;"
    "border:1px solid #CCCCCC;"
    "font-size:14px;"
    "font-family:Microsoft YaHei;"
    "cursor:pointer");

// 设置悬停样式
control->SetStyleSheet(ControlState::Hover,
    "background-color:#E8E8E8");

// 设置按下样式
control->SetStyleSheet(ControlState::Active,
    "background-color:#D0D0D0");

// 设置禁用样式
control->SetStyleSheet(ControlState::Disabled,
    "background-color:#F0F0F0;"
    "fore-color:#999999");

5. 事件系统

5.1 支持的事件类型

事件类型定义在 EzUI.h 中:

enum Event : long long {
    None = 1,
    OnMouseWheel = 2,
    OnMouseEnter = 4,
    OnMouseMove = 8,
    OnMouseLeave = 16,
    OnMouseDoubleClick = 32,
    OnMouseDown = 64,
    OnMouseUp = 128,
    OnKeyDown = 256,
    OnKeyUp = 512,
    OnPaint = 1024,
    OnFocus = 2048,
    OnKillFocus = 4096,
    OnKeyChar = 8192,
    OnMove = 16384,
    OnSize = 32768,
    OnRect = 65536,
    OnDpiChange = 131072,
};

复合事件

OnActive = OnMouseDown | OnMouseUp,      // 点击
OnHover = OnMouseEnter | OnMouseLeave,   // 悬停
OnMouseDrag = OnMouseDown | OnMouseMove, // 拖拽
OnMouseEvent = ...,                        // 所有鼠标事件
OnKeyBoardEvent = ...                      // 所有键盘事件

5.2 事件参数类

类名 包含信息
EventArgs Event EventType - 事件类型
MouseEventArgs MouseButton Button, int ZDelta, Point Location
KeyboardEventArgs WPARAM wParam, LPARAM lParam
FocusEventArgs Control* Ctl - 获得焦点的控件
KillFocusEventArgs Control* Ctl - 失去焦点的控件
MoveEventArgs Point Location - 新位置
SizeEventArgs Size NewSize - 新尺寸
PaintEventArgs Graphics& Graphics, HWND, Rect, etc.

5.3 事件订阅与取消订阅

5.3.1 使用 EventHandler 回调

// 订阅事件
control->EventHandler = [](Control* sender, EventArgs& args) {
    // sender: 事件发送者
    // args: 事件参数

    if (args.EventType == Event::OnMouseUp) {
        // 处理点击
    }
};

// 取消订阅(设为空即可)
control->EventHandler = nullptr;

5.3.2 使用 NotifyFlags 转发事件

// 设置事件转发到 Window 的 NotifyHandler
control->NotifyFlags = Event::OnMouseEvent | Event::OnKeyBoardEvent;

// 在 Window 中处理
window.NotifyHandler = [](Control* sender, EventArgs& args) {
    // 处理所有子控件转发的事件
};

5.3.3 重写虚函数

class MyControl : public Control {
protected:
    virtual void OnMouseDown(const MouseEventArgs& arg) override {
        // 自定义处理

        // 调用基类实现
        Control::OnMouseDown(arg);
    }

    virtual void OnKeyDown(const KeyboardEventArgs& arg) override {
        // 处理键盘按下
    }
};

5.4 自定义事件扩展指南

EzUI 使用 EventArgs 作为基础事件参数,可以扩展自定义事件:

// 自定义事件参数
class MyEventArgs : public EventArgs {
public:
    int CustomData;
    UIString Message;
};

// 触发自定义事件
void MyControl::DoSomething() {
    MyEventArgs args;
    args.EventType = (Event)0x10000; // 使用未定义的事件类型
    args.CustomData = 42;
    args.Message = L"Custom Event";

    SendEvent(args);
}

6. 最佳实践与常见陷阱

6.1 内存管理

6.1.1 父子控件生命周期

最佳实践

// 方式1创建时指定父控件推荐
VLayout* layout = new VLayout(&window); // window 会负责销毁 layout
Button* btn = new Button(layout);       // layout 会负责销毁 btn

// 方式2使用 Add 方法
Control* parent = new Control();
Control* child = new Control();
parent->Add(child);
// parent 销毁时自动销毁 child

陷阱

// 错误:父控件销毁后,子指针变成悬空指针
Control* child = new Control();
parent->Add(child);
delete parent; // child 已被销毁
child->SetVisible(false); // 崩溃!

// 错误重复添加导致ouble free
parent->Add(child);
parent->Add(child); // 崩溃!

6.1.2 Detach 与 Attach

// Attach附加图片资源控件销毁时自动释放图片
Image* img = Image::LoadFromFile(L"test.png");
control->Attach(img);

// Detach分离图片资源控件销毁时不释放图片
control->Detach(img);
// 注意Detach 后需要手动 delete img

6.2 线程安全

6.2.1 UI 线程访问规则

关键原则:所有 UI 操作必须在主线程中执行。

// 错误:跨线程修改 UI
std::thread t([&]() {
    control->SetText(L"Hello"); // 可能崩溃!
});
t.join();

// 正确:使用 Invoke 同步派发到主线程
std::thread t([&]() {
    Application::Invoke([&]() {
        control->SetText(L"Hello"); // 安全
    });
});
t.join();

// 正确:使用 BeginInvoke 异步派发
std::thread t([&]() {
    Application::BeginInvoke([&]() {
        control->SetText(L"Hello"); // 安全
    });
});
t.join();

6.3 性能优化

6.3.1 减少重绘

// 差:每次修改都立即重绘
control->SetWidth(100);
control->Refresh();
control->SetHeight(50);
control->Refresh();

// 好:使用 Invalidate 延迟重绘(推荐)
control->SetWidth(100);
control->SetHeight(50);
control->Invalidate(); // 一次重绘

6.3.2 批量更新布局

// 差:每次修改都触发布局
layout->SetDockStyle(DockStyle::Vertical);
layout->RefreshLayout();
layout->Add(child1);
layout->RefreshLayout();
layout->Add(child2);
layout->RefreshLayout();

// 好:使用 Invalidate 批量更新
layout->SetDockStyle(DockStyle::Vertical);
layout->Add(child1);
layout->Add(child2);
layout->Invalidate(); // 一次布局

6.3.3 隐藏控件不参与渲染

// 设置为不可见后,控件不会参与渲染计算
control->SetVisible(false);
control->Hide();

6.4 常见编译错误和运行时错误排查

错误 原因 解决方案
unresolved external symbol 链接库缺失 确保链接 EzUI 库
error C2027: use of undefined type 头文件包含顺序错误 检查 include 顺序
控件不显示 未添加到父容器 使用 Add() 方法
控件不响应事件 不可见或禁用 检查 SetVisible/SetEnabled
布局不正确 未设置尺寸 使用 SetFixedSize/SetAutoSize
样式不生效 样式状态优先级 检查 ControlState 设置
内存泄漏 未正确管理父子关系 使用智能指针或正确配对 new/delete

7. 附录:速查表

7.1 常用方法速查

操作 方法
创建控件 new Control(parent)
添加子控件 parent->Add(child)
设置尺寸 SetFixedSize(Size(w, h))
设置位置 SetLocation(Point(x, y))
设置样式 SetStyleSheet(ControlState::Static, "css")
绑定事件 ctrl->EventHandler = [](...){}
显示/隐藏 Show() / Hide()
启用/禁用 SetEnabled(true/false)
刷新绘制 Invalidate()
刷新布局 RefreshLayout()

7.2 CSS 速查

/* 按钮样式示例 */
Button {
    background-color: #0078D4;
    border: 1px solid #005A9E;
    border-radius: 4px;
    color: #FFFFFF;
    font-size: 14px;
    font-family: Microsoft YaHei;
    cursor: pointer;
}

/* 悬停状态 */
Button:Hover {
    background-color: #106EBE;
}

/* 按下状态 */
Button:Active {
    background-color: #005A9E;
}

/* 禁用状态 */
Button:Disabled {
    background-color: #CCCCCC;
    color: #999999;
    cursor: not-allowed;
}

文档版本1.0 最后更新2026-02-20