c# winform 透明窗口PNG 锯齿毛边 解决方案



问题说明: 普通应用下,设置背景透明可实现透明窗口,如果PNG为方形 不会有锯齿和毛边的情形;但是如果透明背景为圆形,则可能会出现 锯齿毛边的情况(和PNG图片的导入像素无关)。

解决方法:

  1. 皮肤窗口类
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;

    namespace WindowsFormsApp1
    {
    public partial class Skin : Form
    {
    public FormShow show;
    public Skin(FormShow show)
    {
    InitializeComponent();
    this.show = show;
    this.BackgroundImage = WindowsFormsApp3.Properties.Resource1.log_bg;//将背景图应用到皮肤层
    this.BackgroundImageLayout = ImageLayout.Stretch;//自动拉伸背景图以适应窗口
    this.Size = show.Size;//统一大小
    show.Owner = this;//设置控件层的拥有皮肤层

    Location = new Point(show.Location.X, show.Location.Y);//统一控件层和皮肤层的位置
    }

    private void Form1_Load(object sender, EventArgs e)
    {
    FormBorderStyle = FormBorderStyle.None;//取消窗口边框
    SetBits(new Bitmap(BackgroundImage, new Size(135, 70)));//设置不规则窗体
    FormMovableEvent();
    }
    bool haveHandle = false;//窗体句柄创建完成
    private void InitializeStyles()
    {
    SetStyle(
    ControlStyles.UserPaint |
    ControlStyles.AllPaintingInWmPaint |
    ControlStyles.OptimizedDoubleBuffer |
    ControlStyles.ResizeRedraw |
    ControlStyles.SupportsTransparentBackColor, true);
    SetStyle(ControlStyles.Selectable, false);
    UpdateStyles();
    }

    protected override void OnHandleCreated(EventArgs e)
    {
    InitializeStyles();//设置窗口样式、双缓冲等
    base.OnHandleCreated(e);
    haveHandle = true;
    }
    protected override CreateParams CreateParams
    {
    get
    {
    CreateParams cParms = base.CreateParams;
    cParms.ExStyle |= 0x00080000; // WS_EX_LAYERED
    return cParms;
    }
    }
    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);
    }
    }

    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的时候,等于0
    if (this.Top < 0)
    {
    this.Top = 0;
    }
    }
    }

    private void Skin_Move(object sender, EventArgs e)
    {
    show.Location = new Point(Location.X, Location.Y);//统一控件层和皮肤层的位置
    }
    }
    }

  2. 主窗口 添加内容文字等
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Diagnostics;
    using System.Drawing;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;

    namespace WindowsFormsApp1
    {
    public partial class FormShow : Form
    {
    public Skin Skin;
    public FormShow()
    {
    InitializeComponent();

    }
    private void FormShow_Load(object sender, EventArgs e)
    {
    if (!DesignMode)
    {

    Skin = new Skin(this);//创建皮肤层
    this.BackgroundImage = null;//去除控件层背景
    TransparencyKey = BackColor;//使控件层背景透明
    this.ShowInTaskbar = false;
    Skin.Show();//显示皮肤层
    }
    }

    }
    }

  3. WIN32API

    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);
    }

引用来源:https://download.csdn.net/download/gaocongdehao/10368078