Window API

Window 类是 pa2d 的窗口管理系统,采用线程每窗口架构,支持多窗口、事件处理和渲染功能。窗口默认隐藏,需要显式调用 show() 和 render()。

更新: 2025年12月20日 | 作者: thss192 | 版本: 1.0.0-beta1

文档概览

此文档详细介绍了 pa2d 库中的窗口管理系统,采用线程每窗口架构,支持多窗口、事件处理和渲染功能。Window 类提供完整的用户交互界面。

重要特性说明

线程每窗口架构: 每个窗口运行在独立的消息循环线程中
多窗口支持: 可同时创建和管理多个窗口
显式渲染: 窗口默认隐藏,需要调用 show() 显示和 render() 更新内容
避免并发访问: 避免跨线程并发访问 Canvas
裁剪处理: 调整窗口尺寸可能裁剪内容,需监听 onResize 事件重新渲染

主要分为四个核心模块:
Window 窗口类: 完整的窗口管理和渲染功能
事件结构体: 键盘和鼠标事件定义
句柄类型: Windows 系统句柄包装
系统函数: 全局系统信息查询

Window 窗口类

线程每窗口架构(后台消息循环),支持多窗口。窗口默认隐藏,必须显式调用 show()render()

构造与析构

方法 说明
Window(int width = -1, int height = -1, const char* title = "PA2D") 构造指定尺寸和标题的窗口
Window(const Window& rhs) 复制构造(支持窗口管理)
Window(Window&& rhs) noexcept 移动构造
~Window() 析构函数(自动关闭窗口)
Window& operator=(const Window& rhs) 复制赋值
Window& operator=(Window&& rhs) noexcept 移动赋值

句柄访问

方法 返回类型 说明
getHandle() const HWND 获取底层窗口句柄

窗口状态

方法 返回类型 说明
width() const int 获取窗口客户区宽度
height() const int 获取窗口客户区高度
isOpen() const bool 检查窗口是否打开
isClosed() const bool 检查窗口是否已关闭
isVisible() const bool 检查窗口是否可见
isMaximized() const bool 检查窗口是否最大化
isMinimized() const bool 检查窗口是否最小化
isFullscreen() const bool 检查窗口是否全屏

窗口操作

方法 返回类型 说明
show() Window& 显示窗口(必须调用)
hide() Window& 隐藏窗口
close() Window& 关闭窗口
setVisible(bool visible) Window& 设置窗口可见性
focus() Window& 将焦点设置到窗口

阻塞等待

方法 说明
waitForClose() 阻塞当前线程直到窗口关闭

尺寸与位置

方法 返回类型 说明
setPosition(int x, int y) Window& 设置窗口位置(屏幕坐标)
getPosition() const PointInt 获取窗口位置
setClientSize(int width, int height) Window& 设置客户区尺寸
getClientSize() const Size 获取客户区尺寸
setWindowSize(int width, int height) Window& 设置窗口整体尺寸(包括边框)
getWindowSize() const Size 获取窗口整体尺寸

渲染功能

方法 说明
render(const Canvas& canvas, int destX = 0, int destY = 0, int srcX = 0, int srcY = 0, int width = -1, int height = -1, bool clearBackground = true, COLORREF bgColor = 0) 渲染 Canvas 到窗口
render(const Buffer& buffer, int destX = 0, int destY = 0, int srcX = 0, int srcY = 0, int width = -1, int height = -1, bool clearBackground = true, COLORREF bgColor = 0) 渲染 Buffer 到窗口
renderCentered(const Canvas& canvas, bool clearBackground = true, COLORREF bgColor = 0) 居中渲染 Canvas
renderCentered(const Buffer& buffer, bool clearBackground = true, COLORREF bgColor = 0) 居中渲染 Buffer
窗口渲染示例
// 创建窗口
pa2d::Window window(800, 600, "PA2D 示例窗口");

// 创建画布并绘制内容
pa2d::Canvas canvas(800, 600, pa2d::White);
canvas.circle(400, 300, 200, pa2d::Red_fill + 2.0_w)
      .textCentered(400, 300, L"Hello PA2D!", 36, pa2d::Black);

// 显示窗口(必须先显示)
window.show();

// 渲染内容到窗口
window.render(canvas);

// 更新内容并重新渲染
canvas.circle(400, 300, 150, pa2d::Blue_fill + 2.0_w);
window.render(canvas); // 需要再次调用 render() 更新显示

// 居中渲染
pa2d::Canvas smallCanvas(400, 300, pa2d::Green);
window.renderCentered(smallCanvas);

// 阻塞等待窗口关闭
window.waitForClose();

事件回调

方法 说明
onKey(KeyCallback cb) 设置键盘事件回调
onMouse(MouseCallback cb) 设置鼠标事件回调
onResize(ResizeCallback cb) 设置窗口尺寸改变回调
onClose(CloseCallback cb) 设置窗口关闭回调(返回 false 可阻止关闭)
onChar(CharCallback cb) 设置字符输入回调
onFocus(FocusCallback cb) 设置焦点变化回调
onMenu(MenuCallback cb) 设置菜单项点击回调
onFileDrop(FileListCallback cb) 设置文件拖放回调
onClipboardFiles(FileListCallback cb) 设置剪贴板文件变化回调
disableClipboardFiles() 禁用剪贴板文件监听
事件处理示例
pa2d::Window window(800, 600, "事件处理示例");

// 键盘事件处理
window.onKey([](const pa2d::KeyEvent& event) {
    if (event.pressed) {
        std::cout << "按键按下: " << event.key << std::endl;
        if (event.key == VK_ESCAPE) {
            std::cout << "ESC 键被按下" << std::endl;
        }
    } else {
        std::cout << "按键释放: " << event.key << std::endl;
    }
});

// 鼠标事件处理
window.onMouse([](const pa2d::MouseEvent& event) {
    if (event.button == -2) { // 鼠标移动
        std::cout << "鼠标移动到: (" << event.x << ", " << event.y << ")" << std::endl;
    } else if (event.button == 0) { // 左键
        if (event.pressed) {
            std::cout << "左键按下 at (" << event.x << ", " << event.y << ")" << std::endl;
        } else {
            std::cout << "左键释放 at (" << event.x << ", " << event.y << ")" << std::endl;
        }
    } else if (event.button == -1) { // 滚轮
        std::cout << "滚轮滚动: " << event.wheelDelta << std::endl;
    }
});

// 窗口尺寸变化处理
window.onResize([](int width, int height) {
    std::cout << "窗口尺寸改变: " << width << " x " << height << std::endl;
    // 需要重新渲染内容以适应新尺寸
});

// 窗口关闭确认
window.onClose([]() {
    std::cout << "确认关闭窗口吗?" << std::endl;
    // 返回 false 可阻止窗口关闭
    return true; // 允许关闭
});

// 字符输入
window.onChar([](wchar_t ch) {
    std::wcout << L"输入字符: " << ch << std::endl;
});

// 文件拖放支持
window.enableFileDrop();
window.onFileDrop([](const std::vector& files) {
    std::cout << "拖放了 " << files.size() << " 个文件:" << std::endl;
    for (const auto& file : files) {
        std::cout << "  - " << file << std::endl;
    }
});

window.show();
window.waitForClose();

输入状态

方法 返回类型 说明
getMousePosition() const Point 获取鼠标在窗口内的位置
isMouseInWindow() const bool 检查鼠标是否在窗口内
isMouseButtonPressed(int button) const bool 检查鼠标按钮是否按下(0=左键,1=右键,2=中键)
isKeyPressed(int vkCode) const bool 检查指定虚拟键码是否按下
isShiftPressed() const bool 检查 Shift 键是否按下
isCtrlPressed() const bool 检查 Ctrl 键是否按下
isAltPressed() const bool 检查 Alt 键是否按下

窗口控制

方法 返回类型 说明
maximize() Window& 最大化窗口
minimize() Window& 最小化窗口
restore() Window& 恢复窗口正常状态
flash(bool flashTitleBar = true) Window& 闪烁窗口标题栏或任务栏图标
setResizable(bool resizable) Window& 设置窗口是否可调整大小
setAlwaysOnTop(bool onTop) Window& 设置窗口是否始终置顶
setBorderless(bool borderless) Window& 设置窗口无边框
setTitlebarless(bool titlebarless) Window& 设置窗口无标题栏
setFullscreen(bool fullscreen) Window& 设置全屏模式
setMinSize(int minWidth, int minHeight) Window& 设置窗口最小尺寸
setMaxSize(int maxWidth, int maxHeight) Window& 设置窗口最大尺寸
setMinimizeButton(bool show) Window& 显示/隐藏最小化按钮
setMaximizeButton(bool show) Window& 显示/隐藏最大化按钮
setCloseButton(bool show) Window& 显示/隐藏关闭按钮

外观设置

方法 返回类型 说明
setTitle(const char* title) Window& 设置窗口标题(多字节)
setTitle(const wchar_t* title) Window& 设置窗口标题(宽字符)
getTitle() const std::string 获取窗口标题
setCursor(HCURSOR cursor) Window& 设置自定义光标
setCursorDefault() Window& 设置默认箭头光标
setCursorWait() Window& 设置等待(沙漏)光标
setCursorCross() Window& 设置十字光标
setCursorHand() Window& 设置手形光标
setCursorText() Window& 设置文本输入(I-beam)光标
setCursorVisibility(bool visible) Window& 设置光标可见性
setCursorPosition(int x, int y) Window& 设置光标位置(窗口坐标)
setIcon(HICON icon) Window& 设置窗口图标
setIconFromResource(int resourceId) Window& 从资源设置窗口图标

输入控制

方法 返回类型 说明
setMouseCapture(bool capture) Window& 设置鼠标捕获(锁定鼠标到窗口)

剪贴板

方法 返回类型 说明
setClipboardText(const std::string& text) bool 设置剪贴板文本(多字节)
getClipboardText() std::string 获取剪贴板文本(多字节)
setClipboardText(const std::wstring& text) bool 设置剪贴板文本(宽字符)
getClipboardTextW() std::wstring 获取剪贴板文本(宽字符)
hasClipboardText() const bool 检查剪贴板是否有文本
getClipboardFiles() std::vector<std::string> 获取剪贴板中的文件列表
hasClipboardFiles() const bool 检查剪贴板是否有文件
enableFileDrop(bool enable = true) Window& 启用文件拖放支持

菜单系统

方法 返回类型 说明
setMenu(HMENU menu) Window& 设置窗口菜单
createMenu() HMENU 创建菜单
createPopupMenu() HMENU 创建弹出菜单
appendMenuItem(HMENU menu, const char* text, int id, bool enabled = true) Window& 向菜单添加菜单项
appendMenuSeparator(HMENU menu) Window& 向菜单添加分隔符
appendMenuPopup(HMENU menu, const char* text, HMENU popupMenu) Window& 向菜单添加子菜单
destroyMenu(HMENU menu) Window& 销毁菜单
菜单系统示例
pa2d::Window window(800, 600, "菜单示例");

// 创建主菜单
pa2d::Window::HMENU mainMenu = window.createMenu();

// 创建文件子菜单
pa2d::Window::HMENU fileMenu = window.createPopupMenu();
window.appendMenuItem(fileMenu, "新建(&N)", 1001)
      .appendMenuItem(fileMenu, "打开(&O)", 1002)
      .appendMenuSeparator(fileMenu)
      .appendMenuItem(fileMenu, "保存(&S)", 1003)
      .appendMenuItem(fileMenu, "另存为(&A)", 1004)
      .appendMenuSeparator(fileMenu)
      .appendMenuItem(fileMenu, "退出(&X)", 1005);

// 创建编辑子菜单
pa2d::Window::HMENU editMenu = window.createPopupMenu();
window.appendMenuItem(editMenu, "撤销(&U)", 2001)
      .appendMenuItem(editMenu, "重做(&R)", 2002)
      .appendMenuSeparator(editMenu)
      .appendMenuItem(editMenu, "剪切(&T)", 2003)
      .appendMenuItem(editMenu, "复制(&C)", 2004)
      .appendMenuItem(editMenu, "粘贴(&P)", 2005);

// 将子菜单添加到主菜单
window.appendMenuPopup(mainMenu, "文件(&F)", fileMenu)
      .appendMenuPopup(mainMenu, "编辑(&E)", editMenu);

// 设置窗口菜单
window.setMenu(mainMenu);

// 菜单项点击处理
window.onMenu([](int menuId) {
    switch (menuId) {
        case 1001: std::cout << "新建文件" << std::endl; break;
        case 1002: std::cout << "打开文件" << std::endl; break;
        case 1003: std::cout << "保存文件" << std::endl; break;
        case 1005: std::cout << "退出程序" << std::endl; break;
        case 2003: std::cout << "剪切" << std::endl; break;
        case 2004: std::cout << "复制" << std::endl; break;
        case 2005: std::cout << "粘贴" << std::endl; break;
    }
});

window.show();
window.waitForClose();

// 清理菜单
window.destroyMenu(mainMenu);

事件结构体

定义键盘和鼠标事件的数据结构,用于事件回调函数。

KeyEvent 键盘事件

成员 类型 说明
key int 虚拟键码(如 VK_ESCAPE, VK_SPACE 等)
pressed bool 按键状态:true=按下,false=释放
常用虚拟键码
// Windows 虚拟键码(部分常用)
#include <windows.h>    // 或包含 Windows 头文件以获取 VK_ 常量
#define VK_LBUTTON    0x01    // 鼠标左键
#define VK_RBUTTON    0x02    // 鼠标右键
#define VK_MBUTTON    0x04    // 鼠标中键
#define VK_BACK       0x08    // Backspace 键
#define VK_TAB        0x09    // Tab 键
#define VK_RETURN     0x0D    // Enter 键
#define VK_SHIFT      0x10    // Shift 键
#define VK_CONTROL    0x11    // Ctrl 键
#define VK_MENU       0x12    // Alt 键
#define VK_ESCAPE     0x1B    // Esc 键
#define VK_SPACE      0x20    // 空格键
#define VK_PRIOR      0x21    // Page Up
#define VK_NEXT       0x22    // Page Down
#define VK_END        0x23    // End 键
#define VK_HOME       0x24    // Home 键
#define VK_LEFT       0x25    // 左箭头
#define VK_UP         0x26    // 上箭头
#define VK_RIGHT      0x27    // 右箭头
#define VK_DOWN       0x28    // 下箭头
#define VK_INSERT     0x2D    // Insert 键
#define VK_DELETE     0x2E    // Delete 键

// 字母键 'A' - 'Z' 对应 0x41 - 0x5A
// 数字键 '0' - '9' 对应 0x30 - 0x39
// 功能键 F1 - F24 对应 0x70 - 0x87

MouseEvent 鼠标事件

成员 类型 说明
x, y int 鼠标位置(窗口坐标)
button int 按钮标识符:0=左键, 1=右键, 2=中键, -1=滚轮, -2=移动, -3=离开
pressed bool 按钮按下/释放状态(对滚轮和移动事件无效)
wheelDelta int 滚轮增量(正值向前,负值向后)

事件回调类型

回调类型 函数签名 说明
KeyCallback std::function<void(const KeyEvent&)> 键盘事件回调
MouseCallback std::function<void(const MouseEvent&)> 鼠标事件回调
ResizeCallback std::function<void(int, int)> 窗口尺寸改变回调
CloseCallback std::function<bool()> 窗口关闭回调(返回 false 阻止关闭)
CharCallback std::function<void(wchar_t)> 字符输入回调
FocusCallback std::function<void(bool)> 焦点变化回调(true=获得焦点,false=失去焦点)
MenuCallback std::function<void(int)> 菜单项点击回调
FileListCallback std::function<void(const std::vector<std::string>&)> 文件列表回调(用于拖放和剪贴板)

句柄类型

Windows 系统句柄的包装类型,避免与 windows.h 头文件冲突。

窗口句柄类型

类型别名 底层类型 说明
HWND void* 窗口句柄
HMENU void* 菜单句柄
HICON void* 图标句柄
HCURSOR void* 光标句柄
COLORREF unsigned long 颜色引用(RGB 值)
句柄类型使用示例
// 获取窗口句柄
pa2d::Window window(800, 600);
pa2d::Window::HWND hwnd = window.getHandle();

// 使用系统函数时需要类型转换
#ifdef _WIN32
#include <windows.h>

// 将 pa2d::Window::HWND 转换为 Windows HWND
HWND winHwnd = static_cast<HWND>(hwnd);

// 使用 Windows API
SetWindowTextW(winHwnd, L"新的窗口标题");

// 将 Windows COLORREF 转换为 pa2d::Window::COLORREF
pa2d::Window::COLORREF bgColor = RGB(255, 0, 0); // 红色背景

// 渲染时使用颜色
window.render(canvas, 0, 0, 0, 0, -1, -1, true, bgColor);
#endif

系统函数

全局系统信息查询函数。

函数 返回类型 说明
getGlobalMousePosition() Point 获取全局鼠标位置(屏幕坐标)
getScreenSize() Point 获取屏幕尺寸(像素)
getWorkAreaSize() Point 获取工作区尺寸(排除任务栏)
getDpiScale() double 获取 DPI 缩放比例
系统函数使用示例
// 获取系统信息
pa2d::Point mousePos = pa2d::getGlobalMousePosition();
std::cout << "全局鼠标位置: (" << mousePos.x << ", " << mousePos.y << ")" << std::endl;

pa2d::Point screenSize = pa2d::getScreenSize();
std::cout << "屏幕尺寸: " << screenSize.x << " x " << screenSize.y << std::endl;

pa2d::Point workArea = pa2d::getWorkAreaSize();
std::cout << "工作区尺寸: " << workArea.x << " x " << workArea.y << std::endl;

double dpiScale = pa2d::getDpiScale();
std::cout << "DPI 缩放比例: " << dpiScale << std::endl;

// 根据屏幕尺寸创建窗口
int windowWidth = static_cast(screenSize.x * 0.8);
int windowHeight = static_cast(screenSize.y * 0.8);
pa2d::Window window(windowWidth, windowHeight, "自适应窗口");

// 将窗口居中
int centerX = static_cast((screenSize.x - windowWidth) / 2);
int centerY = static_cast((screenSize.y - windowHeight) / 2);
window.setPosition(centerX, centerY);

window.show();
window.waitForClose();