WinForms使用TransparencyKey的透明窗体如何实现拖拽与缩放
WinForms 透明背景无边框窗体的拖拽与缩放实现
我用VS2019、.NET Framework 4.8 开发WinForms应用时,做了一个特殊配置的窗体:
- 给窗体设置自选图片作为显示背景
- 将窗体背景色设为指定色值,同时把这个色值赋值给
TransparencyKey,实现指定颜色区域完全透明的效果 - 窗体
Opacity保持100%,不做整体半透明处理 - 给窗体绑定了点击触发的上下文菜单,该功能运行正常
- 关闭了窗体所有原生可见元素:最小/最大化按钮、窗体边框、标题栏图标等,最终窗体只显示设置好的背景图,完全符合预期
目前我想实现的需求是:给这种仅靠背景图显示内容的窗体,增加拖拽移动和/或缩放调整尺寸的功能。
补充说明:之前查找过的同主题相近问题,没有完全适配当前场景的可直接复用方案。
已落地的实现方案
拖拽功能(已完成)
按参考提示整理了适配VB.NET的拖拽实现,不需要额外新建独立功能类,直接把代码写在主窗体文件里即可运行。实现逻辑很简单:先在窗体类里声明几个全局状态变量,绑定窗体的MouseDown、MouseMove、MouseUp三个鼠标事件,在对应事件处理逻辑里补充少量代码即可。完整代码如下:
Public Class FrmShieldMenu ' 记录鼠标拖拽时的偏移量、当前是否处于拖拽状态 Private movX, movY As Integer Private isMoving As Boolean Private Sub FrmShieldMenu_MouseMove(sender As Object, e As MouseEventArgs) Handles MyBase.MouseMove ' 拖拽状态下,跟随鼠标位置更新窗体坐标 If isMoving Then SetDesktopLocation(MousePosition.X - movX, MousePosition.Y - movY) End If End Sub Private Sub FrmShieldMenu_MouseUp(sender As Object, e As MouseEventArgs) Handles MyBase.MouseUp ' 松开鼠标左键时,结束拖拽状态 isMoving = False End Sub Private Sub FrmShieldMenu_MouseDown(sender As Object, e As MouseEventArgs) Handles MyBase.MouseDown ' 按下鼠标左键时进入拖拽状态,记录鼠标相对于窗体左上角的偏移量 isMoving = True movX = e.X movY = e.Y End Sub End Class
缩放功能(临时实现方案)
目前临时做了一个可通过上下文菜单调出的调整窗体,上面放两个NumericUpDown控件,分别对应调整主窗体的高度和宽度,配套代码如下:
Public Class FrmResize ' 记录主窗体的原始宽高,用于一键重置 Dim OldHeight As Integer Dim OldWidth As Integer Private Sub FrmResize_Load(sender As Object, e As EventArgs) Handles MyBase.Load ' 加载调整窗体时,先记录主窗体当前的尺寸作为原始值 OldHeight = FrmShieldMenu.Height OldWidth = FrmShieldMenu.Width ' 把控件的初始值设为当前主窗体的实际尺寸 HeightNumericUpDown.Value = OldHeight WidthNumericUpDown.Value = OldWidth End Sub Private Sub BtnReset_Click(sender As Object, e As EventArgs) Handles BtnReset.Click ' 点击重置按钮,将主窗体尺寸恢复为打开调整界面前的数值 FrmShieldMenu.Height = OldHeight FrmShieldMenu.Width = OldWidth End Sub Private Sub BtnApply_Click(sender As Object, e As EventArgs) Handles BtnApply.Click ' 点击应用按钮,将主窗体尺寸设置为控件选定的数值 FrmShieldMenu.Height = HeightNumericUpDown.Value FrmShieldMenu.Width = WidthNumericUpDown.Value Me.Close() End Sub End Class
这个方案虽然不算优雅,但从功能层面完全可用。之前看到的其他同类实现方案普遍存在几个不适用的问题:是C#版本无法直接复用、代码逻辑过于复杂、属于过度设计,不符合当前的简单需求。
内容的提问来源于stack exchange,提问作者John Dovey
相关产品推荐
相关产品推荐

