Flutter Windows端如何通过按钮点击唤起第二个应用窗口
Flutter Windows 端唤起独立子窗口实现方案
直接用维护成熟的desktop_multi_window库实现即可,不需要编写大量原生Win32代码,全流程实操步骤如下:
- 第一步:添加项目依赖
在项目根目录的pubspec.yaml中添加依赖,版本可按需替换为pub仓库上的最新稳定版:
dependencies: flutter: sdk: flutter desktop_multi_window: ^0.2.0
添加完成后执行flutter pub get拉取依赖。
- 第二步:配置Windows原生入口
打开项目路径下的windows/runner/main.cpp文件,替换原有入口逻辑,增加多窗口分发判断,否则子窗口无法正常拉起:
#include "flutter_window.h" #include "utils.h" #include <desktop_multi_window/desktop_multi_window_plugin.h> int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, _In_ wchar_t* command_line, _In_ int show_command) { // 拦截子窗口启动请求,走子窗口独立渲染逻辑 if (desktop_multi_window::HandleWindowStart(instance, show_command)) { return EXIT_SUCCESS; } // 保留原有主窗口初始化逻辑即可 if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { CreateAndAttachConsole(); } INITCOMMONCONTROLSEX iccex = {.dwSize = sizeof(iccex), .dwICC = ICC_STANDARD_CLASSES}; ::InitCommonControlsEx(&iccex); flutter::DartProject project(L"data"); std::vector<std::string> command_line_arguments = GetCommandLineArguments(); project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); FlutterWindow window(project); Win32Window::Point origin(10, 10); Win32Window::Size size(1280, 720); if (!window.Create(L"相册主窗口", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); ::MSG msg; while (::GetMessage(&msg, nullptr, 0, 0)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } ::CoUninitialize(); return EXIT_SUCCESS; }
- 第三步:编写Dart层多窗口分发逻辑
修改lib/main.dart入口文件,启动时先判断当前实例属于主窗口还是子窗口,分别加载对应页面:
import 'dart:convert'; import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:flutter/material.dart'; // 以下两个页面替换为你自己业务中的实际文件路径即可 import 'pages/slideshow_page.dart'; import 'pages/home_page.dart'; void main(List<String> args) async { WidgetsFlutterBinding.ensureInitialized(); // 识别子窗口启动请求 if (args.isNotEmpty) { try { final params = jsonDecode(args.first); if (params['type'] == 'slideshow') { final windowId = params['windowId']; final controller = WindowController.fromWindowId(windowId); // 配置幻灯片窗口属性,可按需调整为全屏、置顶等模式 controller ..setTitle("幻灯片放映") ..setFullscreen(true) ..show(); // 子窗口直接加载幻灯片页面,传入照片列表、起始索引等业务参数 runApp(MaterialApp( debugShowCheckedModeBanner: false, home: SlideshowPage( photoPaths: List<String>.from(params['photoList']), startIndex: params['startIndex'] as int, ), )); return; } } catch (_) {} } // 主窗口加载正常相册首页 runApp(const MaterialApp( debugShowCheckedModeBanner: false, home: HomePage(), )); }
- 第四步:主窗口按钮点击唤起幻灯片窗口
在主页面的幻灯片放映按钮点击回调中,调用窗口创建接口,传入需要的业务参数即可拉起独立子窗口:
// 幻灯片按钮点击逻辑 void _handleStartSlideshow() async { // 组装传给子窗口的参数 final windowParams = { 'type': 'slideshow', 'photoList': photoPathList, // 待放映的所有照片本地路径列表 'startIndex': currentPhotoIndex, // 从当前选中的照片开始播放 }; // 创建并展示独立窗口 final window = await DesktopMultiWindow.createWindow(jsonEncode(windowParams)); window.show(); }
- 补充说明
- 主、子窗口是独立的Flutter渲染实例,互不阻塞,跨窗口通信可以用
DesktopMultiWindow.invokeMethod实现,比如主窗口控制幻灯片切页、幻灯片播放结束通知主窗口都可以用这个接口 - 子窗口关闭不会影响主窗口运行,主窗口退出时会自动回收所有子窗口,符合桌面应用的常规交互逻辑
- 如果需要自定义窗口样式(比如无边框、透明、置顶),直接通过
WindowController的对应接口设置即可,不需要额外编写原生代码
- 主、子窗口是独立的Flutter渲染实例,互不阻塞,跨窗口通信可以用
实现效果参考:
内容的提问来源于stack exchange,提问作者Polla A. Fattah
相关产品推荐
相关产品推荐

