C++ Saucer 编写Windows桌面应用
文章目录
- 一、背景
- 二、Saucer 简介
- 核心特性
- 典型应用场景
- 三、生成自己的项目
- 四、以Win32项目方式构建
- Win32项目
- 禁用最大化按钮
- 五、总结
一、背景
使用Saucer框架,开发Windows桌面应用,把一个html页面作为GUI设计放到Saucer里,隐藏掉运行时弹出的控制台窗口(当cmake项目非Win32时,在Windows环境下会弹出控制台),同时禁用最大化按钮。
二、Saucer 简介
Saucer 是一个现代化的C++库,专为使用Web技术构建跨平台桌面应用而设计。它允许开发者利用熟悉的Web前端技术(HTML/CSS/JavaScript)结合C++后端能力,为Windows、macOS和Linux等主流桌面操作系统创建高性能应用程序。
核心特性
1. 跨平台支持
一套代码即可编译并运行在三大桌面操作系统上,无需为不同平台单独实现。
2. Web技术集成
前端界面完全基于Web技术(HTML/CSS/JavaScript),可直接嵌入现有前端框架(如React、Vue),同时通过C++处理底层逻辑。
3. 灵活的前后端交互
支持C++与JavaScript的双向通信,允许前端调用后端功能,或后端主动更新界面,适用于复杂交互场景。
4. TypeScript支持
提供官方TypeScript类型定义包(@saucerjs/types),增强前端开发的类型安全性和开发体验。
5. 模块化构建
通过CMake配置项目,支持自定义编译选项(如渲染引擎选择、调试模式开关),适应不同项目需求。
6. 轻量级依赖
仅需系统级基础依赖(如Web渲染引擎),无需引入臃肿的运行时环境。
典型应用场景
- 需原生性能但要求快速迭代UI的应用(如数据可视化工具)。
- 将现有Web应用迁移为桌面端应用。
- 混合开发:Web界面 + C++计算/文件操作等底层功能。
三、生成自己的项目
考虑比较简单的使用,我直接在saucer目录里新增projects文件夹,在里面新建自己的cmake项目。
cmake_minimum_required(VERSION 3.16)
project(calendar LANGUAGES CXX VERSION 1.0)# --------------------------------------------------------------------------------------------------------
# Create executable
# --------------------------------------------------------------------------------------------------------add_executable(${PROJECT_NAME} "main.cpp")
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_23)
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 23 CXX_EXTENSIONS OFF CXX_STANDARD_REQUIRED ON)# --------------------------------------------------------------------------------------------------------
# Copy The HTML file
# --------------------------------------------------------------------------------------------------------file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/index.htmlDESTINATION ${CMAKE_CURRENT_BINARY_DIR})# --------------------------------------------------------------------------------------------------------
# Link libraries
# --------------------------------------------------------------------------------------------------------target_link_libraries(${PROJECT_NAME} PRIVATE saucer)
把项目作为子目录添加到整体的CMakeLists.txt
文件中:
# --------------------------------------------------------------------------------------------------------
# My Projects
# --------------------------------------------------------------------------------------------------------add_subdirectory("projects/calendar")
该项目的main.cpp
文件如下:
#include <saucer/smartview.hpp>int main()
{auto app = saucer::application::init({.id = "calendar"});saucer::smartview webview{{.application = app}};// 设置webview尺寸及标题webview.set_size(360, 600);webview.set_title("日历");// 指定页面文件webview.set_file("index.html");webview.show();app->run();return 0;
}
我的开发环境是VS2022,切换到cmake目标视图,可以看到这个项目:
生成并运行该项目,效果如下:
可以看到,项目会先启动一个控制台窗口,然后再打开桌面应用。
四、以Win32项目方式构建
考虑程序是在Windows平台上运行,带着控制台窗口显然不太合理,于是,需要考虑把这个控制台窗口去掉。
Win32项目
采用Win32类型项目构建,可以避免这个问题,我们可以在CMakeLists.txt文件中作如下设置(add_executable
指令中,加入WIN32
关键字):
cmake_minimum_required(VERSION 3.16)
project(calendar-win LANGUAGES CXX VERSION 1.0)# --------------------------------------------------------------------------------------------------------
# Create executable
# --------------------------------------------------------------------------------------------------------add_executable(${PROJECT_NAME} WIN32 "main.cpp")
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_23)
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 23 CXX_EXTENSIONS OFF CXX_STANDARD_REQUIRED ON)# --------------------------------------------------------------------------------------------------------
# Copy The HTML file
# --------------------------------------------------------------------------------------------------------file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/index.htmlDESTINATION ${CMAKE_CURRENT_BINARY_DIR})# --------------------------------------------------------------------------------------------------------
# Link libraries
# --------------------------------------------------------------------------------------------------------target_link_libraries(${PROJECT_NAME} PRIVATE saucer)
同时,我们修改main.cpp文件,使之支持Win32项目:
#include <saucer/smartview.hpp>#ifdef WIN32
#include <Windows.h>
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
#else
int main()
#endif
{auto app = saucer::application::init({.id = "calendar"});saucer::smartview webview{{.application = app}};// 设置webview尺寸及标题webview.set_size(360, 600);webview.set_title("日程提醒");// 指定页面文件webview.set_file("index.html");webview.show();app->run(); return 0;
}
这时候重新构建,刚才出现的控制台将消失,直接打开Windows窗口。
禁用最大化按钮
在开发过程中,我尝试禁用最大化按钮,例如,加入如下C++代码:
auto hwnd = GetActiveWindow();DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);dwStyle ^= WS_MAXIMIZEBOX; // 设置窗体取消最大化按钮SetWindowLong(hwnd, GWL_STYLE, dwStyle);
一开始,我把上述代码放在程序开头,如下:
#include <saucer/smartview.hpp>#ifdef WIN32
#include <Windows.h>
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
#else
int main()
#endif
{auto hwnd = GetActiveWindow();DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);dwStyle ^= WS_MAXIMIZEBOX; // 设置窗体取消最大化按钮SetWindowLong(hwnd, GWL_STYLE, dwStyle);auto app = saucer::application::init({.id = "calendar"});saucer::smartview webview{{.application = app}};// 设置webview尺寸及标题webview.set_size(360, 600);webview.set_title("日程提醒");// 指定页面文件webview.set_file("index.html");webview.show();app->run(); return 0;
}
然后并不生效,后来通过F5代码调试和实际试验,这段控制代码应该放在webview.show()
和app->run()
之间,从而保证能找到活动窗口,并且不离开主线程,修改后的main.cpp代码如下:
#include <saucer/smartview.hpp>#ifdef WIN32
#include <Windows.h>
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
#else
int main()
#endif
{auto app = saucer::application::init({.id = "calendar"});saucer::smartview webview{{.application = app}};// 设置webview尺寸及标题webview.set_size(360, 600);webview.set_title("日程提醒");// 指定页面文件webview.set_file("index.html");webview.show();// 在webview.show()之后,app->run()之前加入窗体按钮控制代码段// 实现对窗体按钮的控制auto hwnd = GetActiveWindow();DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);dwStyle ^= WS_MAXIMIZEBOX; // 设置窗体取消最大化按钮SetWindowLong(hwnd, GWL_STYLE, dwStyle);app->run(); return 0;
}
生成并运行,禁用了窗体最大化按钮:
五、总结
以上是我一次使用Saucer的体验,通过Saucer,开发者既能发挥C++的硬件级性能优势,又能享受Web技术的高效界面开发能力,实现真正的"一次编写,多平台运行"。