You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Windows桌面Flutter应用创建双独立引擎窗口并实现跨窗口通信与双屏分显功能

Windows Flutter双屏双窗口实现方案及疑问解答

我来帮你一步步解决双屏窗口的问题,顺便解答你提到的三个技术疑问:


一、先解决修改C++后仅显示一个窗口的问题

你之前修改代码后只出现一个窗口,大概率是因为没有正确枚举系统中的所有显示器,或者窗口创建参数有误。核心要做的是遍历所有外接显示器,为每个显示器单独创建全屏窗口。

在windows/runner/main.cpp中,你可以用Windows API的EnumDisplayMonitors函数枚举所有显示器,然后为每个显示器的区域创建对应的Flutter窗口。这里给你一段关键代码示例:

// 定义窗口数据结构体,用于传递给枚举回调
struct WindowData {
  HINSTANCE instance;
  FlutterEngine engine;
  const wchar_t* window_class;
};

// 枚举显示器的回调函数
BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
  auto window_data = reinterpret_cast<WindowData*>(dwData);
  
  // 创建全屏窗口(使用WS_POPUP去掉标题栏,直接铺满显示器)
  HWND hwnd = CreateWindowEx(
      0,
      window_data->window_class,
      L"Flutter Dual Screen",
      WS_POPUP | WS_VISIBLE,
      lprcMonitor->left,
      lprcMonitor->top,
      lprcMonitor->right - lprcMonitor->left,
      lprcMonitor->bottom - lprcMonitor->top,
      nullptr,
      nullptr,
      window_data->instance,
      window_data
  );

  if (!hwnd) {
    return FALSE;
  }

  // 初始化当前窗口的Flutter视图
  InitializeFlutterView(hwnd, window_data->engine);
  
  return TRUE;
}

// 在main函数中调用枚举
int APIENTRY wWinMain(_In_ HINSTANCE instance,
                     _In_opt_ HINSTANCE prev_instance,
                     _In_ wchar_t* cmd_line,
                     _In_ int cmd_show) {
  // ... 其他初始化代码 ...

  WindowData window_data = {
    .instance = instance,
    .engine = engine,
    .window_class = kWindowClass,
  };

  // 枚举所有显示器并创建窗口
  EnumDisplayMonitors(nullptr, nullptr, MonitorEnumProc, reinterpret_cast<LPARAM>(&window_data));

  // ... 消息循环代码 ...
}

这段代码会遍历所有显示器,为每个显示器创建一个全屏的Flutter窗口,解决你之前只显示一个窗口的问题。


二、你的三个技术疑问解答

1. 如何为副屏窗口指定不同的Widget?

有两种简单可靠的方式:

  • 通过初始路由区分:在C++创建Flutter视图时,为不同窗口设置不同的初始路由。比如主窗口用"/main",副屏窗口用"/preview"。然后在Dart层通过路由加载对应的Widget:

    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        final initialRoute = WidgetsBinding.instance.window.defaultRouteName;
        return MaterialApp(
          title: '双屏演示',
          initialRoute: initialRoute.isNotEmpty ? initialRoute : '/main',
          routes: {
            '/main': (context) => const MainScreen(), // 主屏界面
            '/preview': (context) => const PreviewScreen(), // 副屏预览界面
          },
        );
      }
    }
    

    在C++的InitializeFlutterView函数中,给不同窗口设置路由:

    // 主窗口设置路由
    FlutterViewSetInitialRoute(view, "/main");
    // 副窗口设置路由
    FlutterViewSetInitialRoute(view, "/preview");
    
  • 通过MethodChannel传递窗口标识:在窗口创建完成后,通过MethodChannel告诉Dart层当前窗口是主窗口还是副窗口,Dart根据这个标识渲染对应的Widget。

2. 如何实现两个视图间的通信?

因为两个窗口共享同一个Flutter Engine,所以通信非常方便,推荐两种方案:

  • 全局状态管理:用ChangeNotifier、Provider或Riverpod等状态管理工具,全局维护状态,两个窗口监听状态变化即可同步数据。比如:

    // 全局状态类
    class ScreenSyncState extends ChangeNotifier {
      String _previewContent = "";
    
      String get previewContent => _previewContent;
    
      void updatePreview(String content) {
        _previewContent = content;
        notifyListeners(); // 通知所有监听者更新
      }
    }
    
    // 初始化全局实例
    final screenSyncState = ScreenSyncState();
    
    // 主窗口更新状态
    screenSyncState.updatePreview("主窗口的操控内容");
    
    // 副窗口监听状态并展示
    Consumer<ScreenSyncState>(
      builder: (context, state, child) {
        return Center(child: Text(state.previewContent));
      },
    )
    
  • MethodChannel通信:通过MethodChannel在两个窗口间发送消息,比如主窗口调用方法更新副屏内容,副屏监听方法调用并更新界面。这种方式适合单次消息传递,状态管理适合持续同步。

3. 修改C++ runner文件是否为最优方案?

目前来看,修改C++ runner是最可控、最成熟的方案。因为Flutter官方对Windows多窗口的支持还处于完善阶段(虽然有Experimental API,但尚未稳定发布),直接修改底层C++代码可以完全掌控窗口的创建、布局和生命周期。

当然,你也可以关注Flutter官方的多窗口API进展,未来官方推出稳定的Dart层多窗口API后,可以迁移过去。但现阶段,修改C++ runner是实现你需求的最优选择。


内容的提问来源于stack exchange,提问作者jacobsieradzki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 22:52:37