C# Winform 窗体美化(三、不规则窗体)

三、不规则窗体

概况

之前学习的 LayeredSkin 看到里面有个异形窗口,比较感兴趣,所以就找一下资料研究一下。不规则窗体学习有一个比较好的例子,叫 GoldFishProject,是一条鱼金鱼在屏幕上游。

不规则窗口示例代码
GoldFishProject 游动金鱼的学习代码

如果没有积分,也可以关注我获取哟~
hi

现学习了两种实现方式:

  1. UpdateLayeredWindow
  2. GraphicsPath

1.UpdateLayeredWindow

这种方式实现的不规则窗口很平滑,没有锯齿,可以带半透明的效果,但是不在响应 paint 方法,绘制不了窗体上的控件,效果图:
不规则窗口

代码如下:

窗体代码:

public partial class UpdateLayeredWindowForm : Form
{bool haveHandle = false;//窗体句柄创建完成public UpdateLayeredWindowForm(){InitializeComponent();}private void UpdateLayeredWindowForm_Load(object sender, EventArgs e){FormBorderStyle = FormBorderStyle.None;//取消窗口边框SetBits(new Bitmap(BackgroundImage));//设置不规则窗体FormMovableEvent();//设置拖动窗体移动}#region 防止窗体闪屏private void InitializeStyles(){SetStyle(ControlStyles.UserPaint |ControlStyles.AllPaintingInWmPaint |ControlStyles.OptimizedDoubleBuffer |ControlStyles.ResizeRedraw |ControlStyles.SupportsTransparentBackColor, true);SetStyle(ControlStyles.Selectable, false);UpdateStyles();} #endregion#region 句柄创建事件protected override void OnHandleCreated(EventArgs e){InitializeStyles();//设置窗口样式、双缓冲等base.OnHandleCreated(e);haveHandle = true;} #endregion#region 设置窗体样式protected override CreateParams CreateParams{get{CreateParams cParms = base.CreateParams;cParms.ExStyle |= 0x00080000; // WS_EX_LAYEREDreturn cParms;}} #endregion#region 设置不规则窗体public void SetBits(Bitmap bitmap){if (!haveHandle) return;if (!Bitmap.IsCanonicalPixelFormat(bitmap.PixelFormat) || !Bitmap.IsAlphaPixelFormat(bitmap.PixelFormat))throw new ApplicationException("The picture must be 32bit picture with alpha channel.");IntPtr oldBits = IntPtr.Zero;IntPtr screenDC = Win32.GetDC(IntPtr.Zero);IntPtr hBitmap = IntPtr.Zero;IntPtr memDc = Win32.CreateCompatibleDC(screenDC);try{Win32.Point topLoc = new Win32.Point(Left, Top);Win32.Size bitMapSize = new Win32.Size(bitmap.Width, bitmap.Height);Win32.BLENDFUNCTION blendFunc = new Win32.BLENDFUNCTION();Win32.Point srcLoc = new Win32.Point(0, 0);hBitmap = bitmap.GetHbitmap(Color.FromArgb(0));oldBits = Win32.SelectObject(memDc, hBitmap);blendFunc.BlendOp = Win32.AC_SRC_OVER;blendFunc.SourceConstantAlpha = 255;//这里设置窗体绘制的透明度blendFunc.AlphaFormat = Win32.AC_SRC_ALPHA;blendFunc.BlendFlags = 0;Win32.UpdateLayeredWindow(Handle, screenDC, ref topLoc, ref bitMapSize, memDc, ref srcLoc, 0, ref blendFunc, Win32.ULW_ALPHA);}finally{if (hBitmap != IntPtr.Zero){Win32.SelectObject(memDc, oldBits);Win32.DeleteObject(hBitmap);}Win32.ReleaseDC(IntPtr.Zero, screenDC);Win32.DeleteDC(memDc);}} #endregion#region 无标题栏的窗口移动private Point mouseOffset; //记录鼠标指针的坐标private bool isMouseDown = false; //记录鼠标按键是否按下/// <summary>/// 窗体移动监听绑定/// </summary>private void FormMovableEvent(){//窗体移动this.MouseDown += new MouseEventHandler(Frm_MouseDown);this.MouseMove += new MouseEventHandler(Frm_MouseMove);this.MouseUp += new MouseEventHandler(Frm_MouseUp);}/// <summary>/// 窗体按下时/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Frm_MouseDown(object sender, MouseEventArgs e){int xOffset;int yOffset;//点击窗体时,记录鼠标位置,启动移动if (e.Button == MouseButtons.Left){xOffset = -e.X;yOffset = -e.Y;mouseOffset = new Point(xOffset, yOffset);isMouseDown = true;}}/// <summary>/// 窗体移动时/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Frm_MouseMove(object sender, MouseEventArgs e){if (isMouseDown){//移动的位置计算Point mousePos = Control.MousePosition;mousePos.Offset(mouseOffset.X, mouseOffset.Y);Location = mousePos;}}/// <summary>/// 窗体按下并释放按钮时/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Frm_MouseUp(object sender, MouseEventArgs e){// 修改鼠标状态isMouseDown的值// 确保只有鼠标左键按下并移动时,才移动窗体if (e.Button == MouseButtons.Left){//松开鼠标时,停止移动isMouseDown = false;//Top高度小于0的时候,等于0if (this.Top < 0){this.Top = 0;}}}#endregion
}

Win32API代码:(从金鱼的例子中引用的代码)

//##########################################################################
//★★★★★★★           http://www.cnpopsoft.com           ★★★★★★★
//★★          VB & C# source code and articles for free !!!           ★★
//★★★★★★★                Davidwu                       ★★★★★★★
//##########################################################################using System;
using System.Runtime.InteropServices;/// <summary>
/// Wind32API
/// </summary>
internal class Win32
{#region 消息public const int MF_REMOVE = 0x1000;public const int SC_RESTORE = 0xF120; //还原public const int SC_MOVE = 0xF010; //移动public const int SC_SIZE = 0xF000; //大小public const int SC_MINIMIZE = 0xF020; //最小化public const int SC_MAXIMIZE = 0xF030; //最大化public const int SC_CLOSE = 0xF060; //关闭 public const int WM_SYSCOMMAND = 0x0112;public const int WM_COMMAND = 0x0111;public const int GW_HWNDFIRST = 0;public const int GW_HWNDLAST = 1;public const int GW_HWNDNEXT = 2;public const int GW_HWNDPREV = 3;public const int GW_OWNER = 4;public const int GW_CHILD = 5;public const int WM_NCCALCSIZE = 0x83;public const int WM_WINDOWPOSCHANGING = 0x46;public const int WM_PAINT = 0xF;public const int WM_CREATE = 0x1;public const int WM_NCCREATE = 0x81;public const int WM_NCPAINT = 0x85;public const int WM_PRINT = 0x317;public const int WM_DESTROY = 0x2;public const int WM_SHOWWINDOW = 0x18;public const int WM_SHARED_MENU = 0x1E2;public const int HC_ACTION = 0;public const int WH_CALLWNDPROC = 4;public const int GWL_WNDPROC = -4;public const int WS_SYSMENU = 0x80000;public const int WS_SIZEBOX = 0x40000;public const int WS_MAXIMIZEBOX = 0x10000;public const int WS_MINIMIZEBOX = 0x20000;#endregion[StructLayout(LayoutKind.Sequential)]public struct Size{public Int32 cx;public Int32 cy;public Size(Int32 x, Int32 y){cx = x;cy = y;}}[StructLayout(LayoutKind.Sequential, Pack = 1)]public struct BLENDFUNCTION{public byte BlendOp;public byte BlendFlags;public byte SourceConstantAlpha;public byte AlphaFormat;}[StructLayout(LayoutKind.Sequential)]public struct Point{public Int32 x;public Int32 y;public Point(Int32 x, Int32 y){this.x = x;this.y = y;}}public const byte AC_SRC_OVER = 0;public const Int32 ULW_ALPHA = 2;public const byte AC_SRC_ALPHA = 1;[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]public static extern IntPtr CreateCompatibleDC(IntPtr hDC);[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]public static extern IntPtr GetDC(IntPtr hWnd);[DllImport("gdi32.dll", ExactSpelling = true)]public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObj);[DllImport("user32.dll", ExactSpelling = true)]public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]public static extern int DeleteDC(IntPtr hDC);[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]public static extern int DeleteObject(IntPtr hObj);[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]public static extern int UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pptSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags);[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]public static extern IntPtr ExtCreateRegion(IntPtr lpXform, uint nCount, IntPtr rgnData);[DllImport("user32")]public static extern int SendMessage(IntPtr hwnd, int msg, int wp, int lp);
}

2.GraphicsPath

这种方式不能实现半透明效果,有锯齿,好处是能显示出控件,贴个效果图感受下:

删除完全透明区域
只保留不透明区域

代码如下:

public partial class GraphicsPathForm : Form
{public GraphicsPathForm(){InitializeComponent();}private void GraphicsPathForm_Load(object sender, EventArgs e){TopMost = true;//设置为最顶层FormBorderStyle = FormBorderStyle.None;//取消窗口边框this.Region = new Region(GetWindowRegion(new Bitmap(BackgroundImage)));//设置不规则窗体FormMovableEvent();//设置拖动窗体移动}#region 设置不规则窗体private GraphicsPath GetWindowRegion(Bitmap bitmap){Color TempColor;GraphicsPath gp = new GraphicsPath();if (bitmap == null) return null;for (int nX = 0; nX < bitmap.Width; nX++){for (int nY = 0; nY < bitmap.Height; nY++){TempColor = bitmap.GetPixel(nX, nY);//if (TempColor.A != 0)//去掉完全透明区域if (TempColor.A == 255)//保留完全不透明的区域{gp.AddRectangle(new Rectangle(nX, nY, 1, 1));}}}return gp;} #endregion#region 无标题栏的窗口移动private Point mouseOffset; //记录鼠标指针的坐标private bool isMouseDown = false; //记录鼠标按键是否按下/// <summary>/// 窗体移动监听绑定/// </summary>private void FormMovableEvent(){//窗体移动this.MouseDown += new MouseEventHandler(Frm_MouseDown);this.MouseMove += new MouseEventHandler(Frm_MouseMove);this.MouseUp += new MouseEventHandler(Frm_MouseUp);}/// <summary>/// 窗体按下时/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Frm_MouseDown(object sender, MouseEventArgs e){int xOffset;int yOffset;//点击窗体时,记录鼠标位置,启动移动if (e.Button == MouseButtons.Left){xOffset = -e.X;yOffset = -e.Y;mouseOffset = new Point(xOffset, yOffset);isMouseDown = true;}}/// <summary>/// 窗体移动时/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Frm_MouseMove(object sender, MouseEventArgs e){if (isMouseDown){//移动的位置计算Point mousePos = Control.MousePosition;mousePos.Offset(mouseOffset.X, mouseOffset.Y);Location = mousePos;}}/// <summary>/// 窗体按下并释放按钮时/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Frm_MouseUp(object sender, MouseEventArgs e){// 修改鼠标状态isMouseDown的值// 确保只有鼠标左键按下并移动时,才移动窗体if (e.Button == MouseButtons.Left){//松开鼠标时,停止移动isMouseDown = false;//Top高度小于0的时候,等于0if (this.Top < 0){this.Top = 0;}}}#endregion
}

像第一种不能添加控件的方法要想实现显示控件的话,下一个关键词就是“双层窗体”,使用两层窗体来实现一个不规则窗体的效果,大致步骤如下:

底层是皮肤层,使用第一种方法;
上层是控件层,使用第二种方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/544701.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mybatis中SQL注入攻击的3种方式,真是防不胜防!

作者 | sunnyf来源 | https://www.freebuf.com/vuls/240578.html前言SQL注入漏洞作为WEB安全的最常见的漏洞之一&#xff0c;在java中随着预编译与各种ORM框架的使用&#xff0c;注入问题也越来越少。新手代码审计者往往对Java Web应用的多个框架组合而心生畏惧&#xff0c;不知…

Hadoop源代码分析(MapReduce概论)

大家都熟悉文件系统&#xff0c;在对HDFS进行分析前&#xff0c;我们并没有花很多的时间去介绍HDFS的背景&#xff0c;毕竟大家对文件系统的还是有一定的理解的&#xff0c;而且也有很好的文档。在分析Hadoop的MapReduce部分前&#xff0c;我们还是先了解系统是如何工作的&…

再有人问你MySql的隔离级别,直接把这篇文章发给他!

作者 l zyz1992来源 l Hollis&#xff08;ID&#xff1a;hollischuang&#xff09;首先要明白什么是事务&#xff1f;事务是程序中一系列严密的操作&#xff0c;所有的操作必须完成&#xff0c;否则在所有的操作中所做的所有的更改都会被撤销。也就是事务的原子性&#xff0c;一…

生产环境一次诡异的NPE问题,反转了4次

前言公司为了保证系统的稳定性&#xff0c;加了很多监控&#xff0c;比如&#xff1a;接口响应时间、cpu使用率、内存使用率、错误日志等等。如果系统出现异常情况&#xff0c;会邮件通知相关人员&#xff0c;以便于大家能在第一时间解决隐藏的系统问题。此外&#xff0c;我们这…

ZooKeeper学习笔记—配置管理

为什么80%的码农都做不了架构师&#xff1f;>>> 最近在工作中&#xff0c;为了完善公司集群服务的架构&#xff0c;提高可用性&#xff0c;降低运维成本&#xff0c;因此开始学习ZooKeeper。 至于什么是ZooKeeper&#xff1f;它能做什么&#xff1f;如何安装ZooKee…

C# Winform 窗体美化(六、双层窗体)

六、双层窗体 大概情况 双层床体是为了平滑的创建异形窗体的一个解决方案&#xff0c;找了很多资料&#xff0c;整理了一下。 双层窗体的逻辑是建立在 UpdateLayeredWindow 不能绘制控件的基础上&#xff0c;上层再添加一个专门放置控件的层&#xff1b;这样就可以在上层“控…

批处理框架 Spring Batch 这么强,你会用吗?

来源&#xff1a;blog.csdn.net/topdeveloperr/article/details/84337956spring batch简介Spring Batch架构介绍Spring Batch核心概念介绍chunk 处理流程批处理操作指南spring batch简介 spring batch是spring提供的一个数据处理框架。企业域中的许多应用程序需要批量处理才能在…

Android Bundle类别

即使在今天发现自己Bundle类不明确&#xff0c;因此&#xff0c;花时间去研究了一下。 依据google官方文件&#xff08;http://developer.android.com/reference/android/os/Bundle.html&#xff09; Bundle类是一个key-value对&#xff0c;“A mapping from String values to …

C# Winform 窗体美化(七、Win7 Aero 毛玻璃效果)

七、Win7 Aero 毛玻璃效果 在 Win7 上有一种 Aero 效果&#xff0c;毛玻璃透明效果&#xff0c;搭配不同风格的颜色&#xff0c;效果很好。在学习 Winform 美化的时候顺便看到的这种效果&#xff0c;也整理进来了。 注意&#xff1a;Win7 上想看到这种效果需要开启并使用 Aer…

非导向传输媒体| 计算机网络

Transmission media can be categorized in two ways, 传输媒体可以通过两种方式进行分类&#xff1a; Guided Transmission Media 引导传输媒体 Unguided Transmission Media 非引导传输媒体 1)非引导传输媒体 (1) Unguided Transmission Media) It is also called wireless …

面霸篇:MQ 的 5 大关键问题详解

最近mq越来越火&#xff0c;很多公司在用&#xff0c;很多人在用&#xff0c;其重要性不言而喻。但是如果我让你回答下面的这些问题&#xff1a;我们为什么要用mq&#xff1f;引入mq会多哪些问题&#xff1f;如何解决这些问题&#xff1f;你心中是否有答案了呢&#xff1f;本文…

C# Winform 窗体美化(八、Icon)

八、Icon 之前 Winform 项目也有在 Icon 上遇到些问题&#xff08;这里的 Icon 指的是 .ico 类型的文件&#xff09;&#xff0c;比如刚开始不知道怎么让自己的程序 Icon 和其他软件一样可以放大&#xff0c;还有放大之后在音量合成器中会出现比较奇葩的效果之类的问题&#x…

MyBatis 的执行流程,学废了!

作者&#xff1a;双子孤狼来源&#xff1a;blog.csdn.net/zwx900102/article/details/108455514MyBatis可能很多人都一直在用&#xff0c;但是MyBatis的SQL执行流程可能并不是所有人都清楚了&#xff0c;那么既然进来了&#xff0c;通读本文你将收获如下&#xff1a;1、Mapper接…

C# Winform 窗体美化(九、嵌入窗体)

九、嵌入窗体 还是关于 Winform 窗体的一些操作问题&#xff0c;这次是研究了一个嵌入窗体&#xff0c;这次学习纯属偶然&#xff0c;项目中确实没遇到过这种需求。就是把别人的程序嵌入到自己的程序中&#xff0c;就像这样&#xff1a; 这里我嵌入了测试显示器的程序 [外链图…

SpringBoot 优雅的参数效验!

引言 不知道大家平时的业务开发过程中 controller 层的参数校验都是怎么写的&#xff1f;是否也存在下面这样的直接判断&#xff1f;public String add(UserVO userVO) {if(userVO.getAge() null){return "年龄不能为空";}if(userVO.getAge() > 120){return &quo…

NTFS Change Journal(USN Journal)详解

写在前面 最近又用了一下usn日志来获取所有文件列表&#xff0c;在分多次加载文件列表的时候发现有文件丢失的情况&#xff0c;后来发现一篇文章比较详细的讲了usn。 用cmd来读取usn日志 如图&#xff1a; 以下是转载内容&#xff1a; 还是那个文件监控的应用&#xff0c;…

绝,Java 中创建对象的 5 种方法!

我们日常生活中会创建很多对象&#xff0c;但是这个对象和你理解的那么对象不一样&#xff0c;因为作者不是女娲&#xff0c;不能造人。作者只是程序员&#xff0c;他只能在 Java 中创建对象。那么我问你一个问题&#xff0c;你知道 Java 中如何创建对象吗&#xff1f;这个问题…

C# Winform 窗体美化(十、自定义窗体)

十、自定义窗体 写在前面 最近在做 winform 应用程序&#xff0c;需要自定义一种窗口的样式&#xff0c;所以就随便搞了一个简单的窗口。 效果图 有两种样式&#xff0c;界面如下&#xff1a; 无标题&#xff1a; 有标题&#xff1a; 关键词 1、黑色描边边框 对于…

SpringBoot时间格式化的5种方法!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;在我们日常工作中&#xff0c;时间格式化是一件经常遇到的事儿&#xff0c;所以本文我们就来盘点一下 Spring Boot 中时间格…

C#文件加密和解密

下载 CSDN下载&#xff1a;https://download.csdn.net/download/myinc/9913318 Github&#xff1a;GitHub 如果没有积分&#xff0c;也可以关注我获取哟~【文件加密】 // * 最近看了一下加密算法&#xff0c;对加密文件突然很感兴趣&#xff0c;就研究了一下&#xff1a;…