文章目录
- 1.修改 main.cpp
- 1)C++ 与 Win32 API
- 2)EnableTransparency()
- 3)中文注释
- 2.编写 Flutter 代码
- 1)bitsdojo_window
- 2)window_manager
- 3)区别对比
- 4)同时使用
- (1)设置初始化代码
- (2)处理冲突和集成
Flutter的文件结构如下,找到图中的main.cpp
的文件
1.修改 main.cpp
main.cpp
文件中的代码应该和下面差不多:
#include <flutter/dart_project.h>
#include <flutter/flutter_view_controller.h>
#include <windows.h>#include "flutter_window.h"
#include "utils.h"int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,_In_ wchar_t *command_line, _In_ int show_command) {// Attach to console when present (e.g., 'flutter run') or create a// new console when running with a debugger.if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {CreateAndAttachConsole();}// Initialize COM, so that it is available for use in the library and/or// plugins.::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);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"untitled", origin, size)) {return EXIT_FAILURE;}window.SetQuitOnClose(true);::MSG msg;while (::GetMessage(&msg, nullptr, 0, 0)) {::TranslateMessage(&msg);::DispatchMessage(&msg);}::CoUninitialize();return EXIT_SUCCESS;
}
1)C++ 与 Win32 API
由上面的代码不难看出flutter
的window
应用程序使用的是C++语言,通过 Win32 API 与 Windows 操作系统进行交互实现。所以让窗口变得透明,对窗口的背景颜色进行设置,并启用层叠窗口样式。就要在main.cpp
文件中做一些更改:
- 在创建窗口时,设置窗口的样式为层叠窗口。
- 使用
SetLayeredWindowAttributes
函数设置窗口透明度。
#include <flutter/dart_project.h>
// 省略代码...
#include "utils.h"// 下面是新加的代码---------------------------------------------------------
#include<bitsdojo_window_windows/bitsdojo_window_plugin.h>
auto bdw = bitsdojo_window_configure(BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP);void EnableTransparency(HWND hwnd) {SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);COLORREF colorKey = RGB(255, 255, 255); BYTE alpha = 0;SetLayeredWindowAttributes(hwnd, colorKey, alpha, LWA_ALPHA);
}
// 到这里结束---------------------------------------------------------------int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, _In_ wchar_t *command_line, _In_ int show_command) {// 省略代码...if (!window.Create(L"untitled", origin, size)) {return EXIT_FAILURE;}// 下面是新加的代码------------------------------------------------------EnableTransparency(window.GetHandle()); // 到这里结束-----------------------------------------------------------window.SetQuitOnClose(true);// 省略代码...return EXIT_SUCCESS;
}
2)EnableTransparency()
// 启用透明度的函数
void EnableTransparency(HWND hwnd) {// 设置窗口样式为分层SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);// 设置透明色和alphaCOLORREF colorKey = RGB(255, 255, 255); // The color to make transparent// 透明程度:透明度水平(0 - 255,0完全透明,255完全不透明)BYTE alpha = 0;SetLayeredWindowAttributes(hwnd, colorKey, alpha, LWA_ALPHA);
}
EnableTransparency函数:这是一个新的函数,函数名随意,它接收窗口句柄作为参数,并设置窗口为层叠样式(WS_EX_LAYERED
),然后通过SetLayeredWindowAttributes
函数设置窗口的透明度。这里的透明度由alpha
参数决定,取值范围是0到255,其中0表示完全透明,255表示完全不透明。
EnableTransparency(window.GetHandle());
window.Create之后调用EnableTransparency:在创建窗口之后,我们调用EnableTransparency
函数并传递窗口句柄,以使窗口透明。
GetHandle函数属于Win32Window
类,它返回后台窗口句柄,使客户端能够设置图标和其他窗口属性。如果窗口已被销毁,则返回nullptr。
3)中文注释
使用Android Studio
在main.cpp
文件中使用中文注释容易报文件编码的错误,在文件中指定编码格式或者在编辑器中修改编码格式都能解决,不过不用中文注释应该是最简单直接的做法。
// 错误信息示例
P:\FlutterProject\flutter_clock-master\untitled\windows\runner\main.cpp(1,1): error C2220: 以下警告被视为错误 [P:\FlutterProject\flutter_clock-master\untitled\build\windows\x64\runner\untitled.vcxproj]
P:\FlutterProject\flutter_clock-master\untitled\windows\runner\main.cpp(1,1): warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 [P:\FlutterProject\flutter_clock-master\untitled\build\windows\x64\runner\untitled.vcxproj]
Exception: Build process failed.
2.编写 Flutter 代码
网上有两个包bitsdojo_window
和window_manager
进行Flutter
的window
应用程序编程,bitsdojo_window
和 window_manager
是两个用于 Flutter 桌面应用开发的包,咱们已经修改了main.cpp
,只要在组件中设置背景即可,这两个包都能实现,下面列出bitsdojo_window
的实现:
import 'package:flutter/material.dart';
import 'package:bitsdojo_window/bitsdojo_window.dart';void main() {runApp(const MyApp());doWhenWindowReady(() {appWindow.show();});
}class MyApp extends StatelessWidget {const MyApp({super.key});Widget build(BuildContext context) {return MaterialApp(color: Colors.transparent,theme: ThemeData(// 设置窗口的背景颜色scaffoldBackgroundColor: Colors.transparent,),home: Container(color: Colors.transparent),);}
}
上面几乎把存在的组件都设置成了transparent
,所以现在窗口的透明与否完全由组件说了算,两个包只要写一条让窗体显示的代码(如上面的 appWindow.show();
)即可。既然提到这两个包,这里说明一下它们两个的区别:
1)bitsdojo_window
功能:
- 自定义窗口边框:允许开发者自定义窗口的边框和标题栏,可以实现无边框窗口并完全控制窗口的外观和行为。
- 窗口拖动:提供简单的 API 用于实现自定义标题栏的拖动。
- 窗口按钮:允许自定义最小化、最大化和关闭按钮的行为。
- 窗口透明度:支持设置窗口的透明度。
- 多平台支持:支持 Windows、macOS 和 Linux。
典型用例:
- 需要高度自定义窗口外观和行为的应用。
- 希望实现无边框窗口并自行处理窗口标题栏和按钮。
示例代码:
import 'package:bitsdojo_window/bitsdojo_window.dart';void main() {runApp(MyApp());// Initialize bitsdojo_windowdoWhenWindowReady(() {final initialSize = Size(600, 450);appWindow.minSize = initialSize;appWindow.size = initialSize;appWindow.alignment = Alignment.center;appWindow.show();});
}
2)window_manager
功能:
- 窗口管理:提供多种窗口管理功能,包括窗口最小化、最大化、恢复、隐藏、显示等。
- 窗口信息:可以获取窗口的位置、大小、标题等信息。
- 窗口事件:支持窗口的各种事件监听,如窗口关闭、聚焦、失焦等事件。
- 多平台支持:支持 Windows、macOS 和 Linux。
典型用例:
- 需要对窗口进行全面控制和管理的应用。
- 需要监听窗口事件或获取窗口状态信息的应用。
示例代码:
import 'package:window_manager/window_manager.dart';void main() async {WidgetsFlutterBinding.ensureInitialized();await windowManager.ensureInitialized();WindowOptions windowOptions = WindowOptions(size: Size(800, 600),center: true,title: 'My Flutter App',);windowManager.waitUntilReadyToShow(windowOptions, () async {await windowManager.show();await windowManager.focus();});runApp(MyApp());
}
3)区别对比
- bitsdojo_window:侧重于窗口外观的高度自定义,特别是无边框窗口的实现和自定义窗口控制按钮。
- window_manager:提供全面的窗口管理功能,适合需要对窗口进行各种操作和事件处理的应用。
选择哪个包取决于你的具体需求:如果你需要自定义窗口的外观和行为,bitsdojo_window
是一个很好的选择;如果你需要全面的窗口管理功能,window_manager
可能更适合你。
4)同时使用
当然有大聪明就想了,我都用可不可以呢?在同一个 Flutter 项目中同时使用 bitsdojo_window
和 window_manager
当然是可以的,但需要注意它们可能在某些功能上存在冲突或重叠,因此需要谨慎管理。方法如下,仅供参考:
(1)设置初始化代码
在 main.dart
文件中初始化 bitsdojo_window
和 window_manager
,确保它们不互相干扰:
import 'package:flutter/material.dart';
import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:window_manager/window_manager.dart';void main() async {WidgetsFlutterBinding.ensureInitialized();// Initialize window_managerawait windowManager.ensureInitialized();WindowOptions windowOptions = WindowOptions(size: Size(800, 600),center: true,title: 'My Flutter App',);windowManager.waitUntilReadyToShow(windowOptions, () async {await windowManager.show();await windowManager.focus();});runApp(MyApp());// Initialize bitsdojo_windowdoWhenWindowReady(() {final initialSize = Size(800, 600);appWindow.minSize = initialSize;appWindow.size = initialSize;appWindow.alignment = Alignment.center;appWindow.show();});
}class MyApp extends StatelessWidget {Widget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',theme: ThemeData(primarySwatch: Colors.blue,),home: MyHomePage(),);}
}class MyHomePage extends StatelessWidget {Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Flutter Demo Home Page'),),body: WindowBorder(color: Colors.black,width: 1,child: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[Text('You have pushed the button this many times:',),],),),),);}
}
(2)处理冲突和集成
在整合过程中,注意以下几点:
- 窗口初始化:确保
window_manager
和bitsdojo_window
的初始化代码不互相干扰。window_manager
用于窗口管理,bitsdojo_window
用于自定义窗口外观。 - 窗口事件:如果需要监听窗口事件,如最小化、最大化等,优先使用
window_manager
提供的事件处理机制。 - 自定义边框和按钮:使用
bitsdojo_window
自定义窗口边框和按钮时,确保这些自定义不会影响window_manager
的功能。
以下是一个实现透明窗口并管理窗口事件的示例:
import 'package:flutter/material.dart';
import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:window_manager/window_manager.dart';void main() async {WidgetsFlutterBinding.ensureInitialized();// Initialize window_managerawait windowManager.ensureInitialized();WindowOptions windowOptions = WindowOptions(size: Size(800, 600),center: true,title: 'My Flutter App',);windowManager.waitUntilReadyToShow(windowOptions, () async {await windowManager.show();await windowManager.focus();});runApp(MyApp());// Initialize bitsdojo_windowdoWhenWindowReady(() {final initialSize = Size(800, 600);appWindow.minSize = initialSize;appWindow.size = initialSize;appWindow.alignment = Alignment.center;// Set the window to be transparentappWindow.setEffect(effect: WindowEffect.transparent,color: Colors.transparent,);appWindow.show();});
}class MyApp extends StatelessWidget {Widget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',theme: ThemeData(primarySwatch: Colors.blue,),home: MyHomePage(),);}
}class MyHomePage extends StatelessWidget {Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Flutter Demo Home Page'),),body: WindowBorder(color: Colors.black,width: 1,child: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[Text('You have pushed the button this many times:',),],),),),);}
}
如果觉得文章写的不错,就随手点个赞再走吧!😊