使用desktop_multi_window包时,如何完全禁用Flutter桌面应用主窗口?
实现主窗口在表单窗口打开期间禁用的方案
要实现主窗口在表单窗口打开时完全禁用,直到表单关闭,可以通过模态子窗口配置 + 主窗口交互拦截的组合方式,结合desktop_multi_window包的特性来实现,具体步骤如下:
1. 将主窗口改为StatefulWidget
因为需要维护表单窗口的打开状态,把MyMainApp从StatelessWidget改为StatefulWidget,用于控制主窗口的交互状态:
class MyMainApp extends StatefulWidget { const MyMainApp({super.key}); @override State<MyMainApp> createState() => _MyMainAppState(); } class _MyMainAppState extends State<MyMainApp> { // 标记表单窗口是否处于打开状态 bool _isFormWindowOpen = false; @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Stack( children: [ // 原主窗口内容 Center( child: ElevatedButton( onPressed: _isFormWindowOpen ? null : _openFormWindow, child: const Text('Open Form'), ), ), // 表单打开时,添加全屏透明拦截层,阻止主窗口交互 if (_isFormWindowOpen) Positioned.fill( child: AbsorbPointer( absorbing: true, child: Container(color: Colors.transparent), ), ), ], ), ), ); } // 打开表单窗口的方法 Future<void> _openFormWindow() async { // 获取主窗口ID,用于关联子窗口 final mainWindowId = DesktopMultiWindow.getCurrentWindowId(); // 创建表单子窗口,并指定父窗口 final formWindow = await DesktopMultiWindow.createWindow( jsonEncode({'args1': 'v1'}), parentWindowId: mainWindowId, ); // 配置子窗口属性 formWindow ..setFrame(const Offset(0, 0) & const Size(400, 600)) ..center() ..setTitle('Form') // 设置子窗口为模态窗口(系统层面禁用主窗口) ..setModal(true) ..show(); // 标记表单窗口已打开,更新UI显示拦截层 setState(() { _isFormWindowOpen = true; }); // 监听子窗口关闭事件,关闭后恢复主窗口状态 formWindow.onClose.listen((_) { setState(() { _isFormWindowOpen = false; }); }); } }
2. 关键细节说明
- 模态窗口配置:通过
parentWindowId关联主窗口,并调用setModal(true),让系统原生层面将表单窗口设为主窗口的模态对话框,这会自动让主窗口失去焦点且无法被激活(符合Windows原生模态窗口的行为)。 - 交互拦截层:使用
AbsorbPointer在主窗口内容上方添加全屏透明层,确保即使系统层面的禁用失效,Flutter层面也能拦截所有点击操作。 - 窗口关闭监听:通过
formWindow.onClose监听表单窗口的关闭事件,及时更新主窗口的状态,恢复交互能力。
3. 跨平台适配注意事项
- Windows:
setModal(true)会自动触发原生模态窗口行为,主窗口会被完全禁用,且表单窗口会保持激活状态。 - macOS:同样支持模态窗口配置,主窗口会被锁定,直到表单窗口关闭。
内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

