前提 入行已經7,8年了,一直想做一套漂亮點的自定義控制項,於是就有了本系列文章。 GitHub:https://github.com/kwwwvagaa/NetWinformControl 碼雲:https://gitee.com/kwwwvagaa/net_winform_custom_contr ...
前提
入行已經7,8年了,一直想做一套漂亮點的自定義控制項,於是就有了本系列文章。
GitHub:https://github.com/kwwwvagaa/NetWinformControl
碼雲:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
如果覺得寫的還行,請點個 star 支持一下吧
麻煩博客下方點個【推薦】,謝謝
NuGet
Install-Package HZH_Controls
目錄
https://www.cnblogs.com/bfyx/p/11364884.html
用處及效果
1 HZH_Controls.Forms.FrmAnchorTips.ShowTips(button1, "測試提示信息\nLEFT", AnchorTipsLocation.LEFT); 2 HZH_Controls.Forms.FrmAnchorTips.ShowTips(button1, "測試提示信息\nRIGHT", AnchorTipsLocation.RIGHT); 3 HZH_Controls.Forms.FrmAnchorTips.ShowTips(button1, "測試提示信息\nTOP", AnchorTipsLocation.TOP); 4 HZH_Controls.Forms.FrmAnchorTips.ShowTips(button1, "測試提示信息\nBOTTOM", AnchorTipsLocation.BOTTOM);
準備工作
依然是GDI+畫圖,不懂可以自行百度一下
開始
思路是:根據參數畫圖,根據圖顯示不規則窗體
添加一個窗體FrmAnchorTips
重寫一些函數
1 #region Override 2 3 protected override void OnClosing(CancelEventArgs e) 4 { 5 e.Cancel = true; 6 base.OnClosing(e); 7 haveHandle = false; 8 this.Dispose(); 9 } 10 11 protected override void OnHandleCreated(EventArgs e) 12 { 13 InitializeStyles(); 14 base.OnHandleCreated(e); 15 haveHandle = true; 16 } 17 18 protected override CreateParams CreateParams 19 { 20 get 21 { 22 CreateParams cParms = base.CreateParams; 23 cParms.ExStyle |= 0x00080000; // WS_EX_LAYERED 24 return cParms; 25 } 26 } 27 28 #endregion
1 private void InitializeStyles() 2 { 3 SetStyle(ControlStyles.AllPaintingInWmPaint, true); 4 SetStyle(ControlStyles.UserPaint, true); 5 UpdateStyles(); 6 }
根據圖片顯示窗體,這個是網上copy的
1 #region 根據圖片顯示窗體 English:Display Forms Based on Pictures 2 /// <summary> 3 /// 功能描述:根據圖片顯示窗體 English:Display Forms Based on Pictures 4 /// 作 者:HZH 5 /// 創建日期:2019-08-29 15:31:16 6 /// 任務編號: 7 /// </summary> 8 /// <param name="bitmap">bitmap</param> 9 private void SetBits(Bitmap bitmap) 10 { 11 if (!haveHandle) return; 12 13 if (!Bitmap.IsCanonicalPixelFormat(bitmap.PixelFormat) || !Bitmap.IsAlphaPixelFormat(bitmap.PixelFormat)) 14 throw new ApplicationException("The picture must be 32bit picture with alpha channel."); 15 16 IntPtr oldBits = IntPtr.Zero; 17 IntPtr screenDC = Win32.GetDC(IntPtr.Zero); 18 IntPtr hBitmap = IntPtr.Zero; 19 IntPtr memDc = Win32.CreateCompatibleDC(screenDC); 20 21 try 22 { 23 Win32.Point topLoc = new Win32.Point(Left, Top); 24 Win32.Size bitMapSize = new Win32.Size(bitmap.Width, bitmap.Height); 25 Win32.BLENDFUNCTION blendFunc = new Win32.BLENDFUNCTION(); 26 Win32.Point srcLoc = new Win32.Point(0, 0); 27 28 hBitmap = bitmap.GetHbitmap(Color.FromArgb(0)); 29 oldBits = Win32.SelectObject(memDc, hBitmap); 30 31 blendFunc.BlendOp = Win32.AC_SRC_OVER; 32 blendFunc.SourceConstantAlpha = 255; 33 blendFunc.AlphaFormat = Win32.AC_SRC_ALPHA; 34 blendFunc.BlendFlags = 0; 35 36 Win32.UpdateLayeredWindow(Handle, screenDC, ref topLoc, ref bitMapSize, memDc, ref srcLoc, 0, ref blendFunc, Win32.ULW_ALPHA); 37 } 38 finally 39 { 40 if (hBitmap != IntPtr.Zero) 41 { 42 Win32.SelectObject(memDc, oldBits); 43 Win32.DeleteObject(hBitmap); 44 } 45 Win32.ReleaseDC(IntPtr.Zero, screenDC); 46 Win32.DeleteDC(memDc); 47 } 48 } 49 #endregion
然後是win32類
1 class Win32 2 { 3 [StructLayout(LayoutKind.Sequential)] 4 public struct Size 5 { 6 public Int32 cx; 7 public Int32 cy; 8 9 public Size(Int32 x, Int32 y) 10 { 11 cx = x; 12 cy = y; 13 } 14 } 15 16 [StructLayout(LayoutKind.Sequential, Pack = 1)] 17 public struct BLENDFUNCTION 18 { 19 public byte BlendOp; 20 public byte BlendFlags; 21 public byte SourceConstantAlpha; 22 public byte AlphaFormat; 23 } 24 25 [StructLayout(LayoutKind.Sequential)] 26 public struct Point 27 { 28 public Int32 x; 29 public Int32 y; 30 31 public Point(Int32 x, Int32 y) 32 { 33 this.x = x; 34 this.y = y; 35 } 36 } 37 38 public const byte AC_SRC_OVER = 0; 39 public const Int32 ULW_ALPHA = 2; 40 public const byte AC_SRC_ALPHA = 1; 41 42 [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] 43 public static extern IntPtr CreateCompatibleDC(IntPtr hDC); 44 45 [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)] 46 public static extern IntPtr GetDC(IntPtr hWnd); 47 48 [DllImport("gdi32.dll", ExactSpelling = true)] 49 public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObj); 50 51 [DllImport("user32.dll", ExactSpelling = true)] 52 public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); 53 54 [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] 55 public static extern int DeleteDC(IntPtr hDC); 56 57 [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] 58 public static extern int DeleteObject(IntPtr hObj); 59 60 [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)] 61 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); 62 63 [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] 64 public static extern IntPtr ExtCreateRegion(IntPtr lpXform, uint nCount, IntPtr rgnData); 65 }
然後就是構造函數了,根據傳入參數,畫出圖片並設置窗體
1 #region 構造函數 English:Constructor 2 /// <summary> 3 /// 功能描述:構造函數 English:Constructor 4 /// 作 者:HZH 5 /// 創建日期:2019-08-29 15:27:51 6 /// 任務編號: 7 /// </summary> 8 /// <param name="rectControl">停靠區域</param> 9 /// <param name="strMsg">消息</param> 10 /// <param name="location">顯示方位</param> 11 /// <param name="background">背景色</param> 12 /// <param name="foreColor">文字顏色</param> 13 /// <param name="fontSize">文字大小</param> 14 /// <param name="autoCloseTime">自動關閉時間,當<=0時不自動關閉</param> 15 private FrmAnchorTips( 16 Rectangle rectControl, 17 string strMsg, 18 AnchorTipsLocation location = AnchorTipsLocation.RIGHT, 19 Color? background = null, 20 Color? foreColor = null, 21 int fontSize = 10, 22 int autoCloseTime = 5000) 23 { 24 InitializeComponent(); 25 Graphics g = this.CreateGraphics(); 26 Font _font = new Font("微軟雅黑", fontSize); 27 Color _background = background == null ? Color.FromArgb(255, 77, 58) : background.Value; 28 Color _foreColor = foreColor == null ? Color.White : foreColor.Value; 29 System.Drawing.SizeF sizeText = g.MeasureString(strMsg, _font); 30 g.Dispose(); 31 var formSize = new Size((int)sizeText.Width + 20, (int)sizeText.Height + 20); 32 if (formSize.Width < 20) 33 formSize.Width = 20; 34 if (formSize.Height < 20) 35 formSize.Height = 20; 36 if (location == AnchorTipsLocation.LEFT || location == AnchorTipsLocation.RIGHT) 37 { 38 formSize.Width += 20; 39 } 40 else 41 { 42 formSize.Height += 20; 43 } 44 45 #region 獲取窗體path English:Get the form path 46 GraphicsPath path = new GraphicsPath(); 47 Rectangle rect; 48 switch (location) 49 { 50 case AnchorTipsLocation.TOP: 51 rect = new Rectangle(1, 1, formSize.Width - 2, formSize.Height - 20 - 1); 52 this.Location = new Point(rectControl.X + (rectControl.Width - rect.Width) / 2, rectControl.Y - rect.Height - 20); 53 break; 54 case AnchorTipsLocation.RIGHT: 55 rect = new Rectangle(20, 1, formSize.Width - 20 - 1, formSize.Height - 2); 56 this.Location = new Point(rectControl.Right, rectControl.Y + (rectControl.Height - rect.Height) / 2); 57 break; 58 case AnchorTipsLocation.BOTTOM: 59 rect = new Rectangle(1, 20, formSize.Width - 2, formSize.Height - 20 - 1); 60 this.Location = new Point(rectControl.X + (rectControl.Width - rect.Width) / 2, rectControl.Bottom); 61 break; 62 default: 63 rect = new Rectangle(1, 1, formSize.Width - 20 - 1, formSize.Height - 2); 64 this.Location = new Point(rectControl.X - rect.Width - 20, rectControl.Y + (rectControl.Height - rect.Height) / 2); 65 break; 66 } 67 int cornerRadius = 2; 68 69 path.AddArc(rect.X, rect.Y, cornerRadius * 2, cornerRadius * 2, 180, 90);//左上角 70 #region 上邊 71 if (location == AnchorTipsLocation.BOTTOM) 72 { 73 path.AddLine(rect.X + cornerRadius, rect.Y, rect.Left + rect.Width / 2 - 10, rect.Y);//上 74 path.AddLine(rect.Left + rect.Width / 2 - 10, rect.Y, rect.Left + rect.Width / 2, rect.Y - 19);//上 75 path.AddLine(rect.Left + rect.Width / 2, rect.Y - 19, rect.Left + rect.Width / 2 + 10, rect.Y);//上 76 path.AddLine(rect.Left + rect.Width / 2 + 10, rect.Y, rect.Right - cornerRadius * 2, rect.Y);//上 77 } 78 else 79 { 80 path.AddLine(rect.X + cornerRadius, rect.Y, rect.Right - cornerRadius * 2, rect.Y);//上 81 } 82 #endregion 83 path.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y, cornerRadius * 2, cornerRadius * 2, 270, 90);//右上角 84 #region 右邊 85 if (location == AnchorTipsLocation.LEFT) 86 { 87 path.AddLine(rect.Right, rect.Y + cornerRadius * 2, rect.Right, rect.Y + rect.Height / 2 - 10);//右 88 path.AddLine(rect.Right, rect.Y + rect.Height / 2 - 10, rect.Right + 19, rect.Y + rect.Height / 2);//右 89 path.AddLine(rect.Right + 19, rect.Y + rect.Height / 2, rect.Right, rect.Y + rect.Height / 2 + 10);//右 90 path.AddLine(rect.Right, rect.Y + rect.Height / 2 + 10, rect.Right, rect.Y + rect.Height - cornerRadius * 2);//右 91 } 92 else 93 { 94 path.AddLine(rect.Right, rect.Y + cornerRadius * 2, rect.Right, rect.Y + rect.Height - cornerRadius * 2);//右 95 } 96 #endregion 97 path.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y + rect.Height - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 0, 90);//右下角 98 #region 下邊 99 if (location == AnchorTipsLocation.TOP) 100 { 101 path.AddLine(rect.Right - cornerRadius * 2, rect.Bottom, rect.Left + rect.Width / 2 + 10, rect.Bottom); 102 path.AddLine(rect.Left + rect.Width / 2 + 10, rect.Bottom, rect.Left + rect.Width / 2, rect.Bottom + 19); 103 path.AddLine(rect.Left + rect.Width / 2, rect.Bottom + 19, rect.Left + rect.Width / 2 - 10, rect.Bottom); 104 path.AddLine(rect.Left + rect.Width / 2 - 10, rect.Bottom, rect.X + cornerRadius * 2, rect.Bottom); 105 } 106 else 107 { 108 path.AddLine(rect.Right - cornerRadius * 2, rect.Bottom, rect.X + cornerRadius * 2, rect.Bottom); 109 } 110 #endregion 111 path.AddArc(rect.X, rect.Bottom - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 90, 90);//左下角 112 #region 左邊 113 if (location == AnchorTipsLocation.RIGHT) 114 { 115 path.AddLine(rect.Left, rect.Y + cornerRadius * 2, rect.Left, rect.Y + rect.Height / 2 - 10);//左 116 path.AddLine(rect.Left, rect.Y + rect.Height / 2 - 10, rect.Left - 19, rect.Y + rect.Height / 2);//左 117 path.AddLine(rect.Left - 19, rect.Y + rect.Height / 2, rect.Left, rect.Y + rect.Height / 2 + 10);//左 118 path.AddLine(rect.Left, rect.Y + rect.Height / 2 + 10, rect.Left, rect.Y + rect.Height - cornerRadius * 2);//左 119 } 120 else 121 { 122 path.AddLine(rect.X, rect.Bottom - cornerRadius * 2, rect.X, rect.Y + cornerRadius * 2);//左 123 } 124 #endregion 125 path.CloseFigure(); 126 #endregion 127 128 Bitmap bit = new Bitmap(formSize.Width, formSize.Height); 129 this.Size = formSize; 130 131 #region 畫圖 English:Drawing 132 Graphics gBit = Graphics.FromImage(bit); 133 gBit.SetGDIHigh(); 134 gBit.FillPath(new SolidBrush(_background), path); 135 gBit.DrawString(strMsg, _font, new SolidBrush(_foreColor), rect.Location + new Size(10, 10)); 136 gBit.Dispose(); 137 #endregion 138 139 SetBits(bit); 140 if (autoCloseTime > 0) 141 { 142 Timer t = new Timer(); 143 t.Interval = autoCloseTime; 144 t.Tick += (a, b) => 145 { 146 this.Close(); 147 }; 148 t.Enabled = true; 149 } 150 } 151 #endregion
再來2個靜態函數以供調用
1 #region 顯示一個提示 English:Show a hint 2 /// <summary> 3 /// 功能描述:顯示一個提示 English:Show a hint 4 /// 作 者:HZH 5 /// 創建日期:2019-08-29 15:28:58 6 /// 任務編號: 7 /// </summary> 8 /// <param name="parentControl">停靠控制項</param> 9 /// <param name="strMsg">消息</param> 10 /// <param name="location">顯示方位</param> 11 /// <param name="background">背景色</param> 12 /// <param name="foreColor">文字顏色</param> 13 /// <param name="deviation">偏移量</param> 14 /// <param name="fontSize">文字大小</param> 15 /// <param name="autoCloseTime">自動關閉時間,當<=0時不自動關閉</param> 16 public static FrmAnchorTips ShowTips( 17 Control parentControl, 18 string strMsg, 19 AnchorTipsLocation location = AnchorTipsLocation.RIGHT, 20 Color? background = null, 21 Color? foreColor = null, 22 Size? deviation = null, 23 int fontSize = 10, 24 int autoCloseTime = 5000) 25 { 26 Point p; 27 if (parentControl is Form) 28 { 29 p = parentControl.Location; 30 } 31 else 32 { 33 p = parentControl.Parent.PointToScreen(parentControl.Location); 34 } 35 if (deviation != null) 36 { 37 p = p + deviation.Value; 38 } 39 return ShowTips(parentControl.FindForm(), new Rectangle(p, parentControl.Size), strMsg, location, background, foreColor, fontSize, autoCloseTime); 40 } 41 #endregion 42 43 #region 顯示一個提示 English:Show a hint 44 /// <summary> 45 /// 功能描述:顯示一個提示 English:Show a hint 46 /// 作 者:HZH 47 /// 創建日期:2019-08-29 15:29:07 48 /// 任務編號: 49 /// </summary> 50 /// <param name="parentForm">父窗體</param> 51 /// <param name="rectControl">停靠區域</param> 52 /// <param name="strMsg">消息</param> 53 /// <param name="location">顯示方位</param> 54 /// <param name="background">背景色</param> 55 /// <param name="foreColor">文字顏色</param> 56 /// <param name="fontSize">文字大小</param> 57 /// <param name="autoCloseTime">自動關閉時間,當<=0時不自動關閉</param> 58 /// <returns>返回值</returns> 59 public static FrmAnchorTips ShowTips( 60 Form parentForm, 61 Rectangle rectControl, 62 string strMsg, 63 AnchorTipsLocation location = AnchorTipsLocation.RIGHT, 64 Color? background = null, 65 Color? foreColor = null, 66 int fontSize = 10, 67 int autoCloseTime = 5000) 68 { 69 FrmAnchorTips frm = new FrmAnchorTips(rectControl, strMsg, location, background, foreColor, fontSize, autoCloseTime); 70 frm.TopMost = true; 71 frm.Show(parentForm); 72 return frm; 73 } 74 #endregion
全部代碼