Flutter框架高阶——Window应用程序设置窗体窗口背景完全透明

csdn推荐

文章目录

Flutter的文件结构如下,找到图中的main.cpp的文件

1.修改 main.cpp

main.cpp文件中的代码应该和下面差不多:

#include 
#include 
#include 
#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文件中做一些更改:

#include 
// 省略代码...
#include "utils.h"
// 下面是新加的代码---------------------------------------------------------
#include
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);
    // 设置透明色和alpha
    COLORREF 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:FlutterProjectflutter_clock-masteruntitledwindowsrunnermain.cpp(1,1): error C2220: 以下警告被视为错误 [P:FlutterProjectflutter_clock-masteruntitledbuildwindowsx64runneruntitled.vcxproj]
P:FlutterProjectflutter_clock-masteruntitledwindowsrunnermain.cpp(1,1): warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 [P:FlutterProjectflutter_clock-masteruntitledbuildwindowsx64runneruntitled.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_window
  doWhenWindowReady(() {
    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 可能更适合你。

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_manager
  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());
  // Initialize bitsdojo_window
  doWhenWindowReady(() {
    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_manager
  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());
  // Initialize bitsdojo_window
  doWhenWindowReady(() {
    final initialSize = Size(800, 600);
    appWindow.minSize = initialSize;
    appWindow.size = initialSize;
    appWindow.alignment = Alignment.center;
    // Set the window to be transparent
    appWindow.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:',
              ),
            ],
          ),
        ),
      ),
    );
  }
}

如果觉得文章写的不错,就随手点个赞再走吧!

文章来源:https://blog.csdn.net/m0_73660699/article/details/139811422



微信扫描下方的二维码阅读本文

© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容