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;我们还是先了解系统是如何工作的&…

Java CharArrayWriter size()方法与示例

CharArrayWriter类的size()方法 (CharArrayWriter Class size() method) size() method is available in java.io package. size()方法在java.io包中可用。 size() method is used to get the current size of this buffer (CharArrayWriter). size()方法用于获取此缓冲区的当前…

C# Winform 窗体美化(四、镂空窗体)

四、镂空窗体 例子下载 如果没有积分&#xff0c;可以关注公众号找一下【大鱼code】 直接贴效果图吧&#xff1a; 1、控件的透明 [外链图片转存中…(img-d0Kky9yO-1655564321951)] 2、窗体的透明 [外链图片转存中…(img-zF1WTwWl-1655564321952)] 代码如下&#xff1a; p…

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

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

Spring与Hibernate两种组合方式

Spring与Hibernate大致有两种组合方式&#xff0c;主要区别是一种是在Hibernate中的hibernate.cfg.xml中配置数据源&#xff0c;一种是借助Spring的jdbc方式在Spring的applicationContext.xml文件中配置数据源,然后在Spring配置sessionFactory的bean有些区别 下面大致的说明一下…

Java CharArrayReader mark()方法与示例

CharArrayReader类mark()方法 (CharArrayReader Class mark() method) mark() method is available in java.io package. mark()方法在java.io包中可用。 mark() method is used to mark the current position in the stream and whenever the call to reset() method so it re…

C# Winform 窗体美化(五、鼠标穿透)

五、鼠标穿透 以前在玩射击游戏的时候&#xff0c;狙击枪的设定一般是开镜才有准星&#xff0c;所以想是不是可以自己造一个默认准星出来&#xff0c;思路是现在窗口上画一个准星&#xff0c;然后把窗体其他区域都透明&#xff0c;然后设置鼠标穿透&#xff1b; 结果是&#…

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

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

ZooKeeper学习笔记—配置管理

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

Java BigDecimal compareTo()方法与示例

BigDecimal类compareTo()方法 (BigDecimal Class compareTo() method) compareTo() method is available in java.math package. compareTo()方法在java.math包中可用。 compareTo() method is used to compare this BigDecimal object to the given object or in other words …

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…

Java LocalDate类| 带示例的getEra()方法

LocalDate类的getEra()方法 (LocalDate Class getEra() method) getEra() method is available in java.time package. getEra()方法在java.time包中可用。 getEra() method is used to get the era applicable for this LocalDate object. getEra()方法用于获取适用于此LocalD…

MyBatis 的执行流程,学废了!

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