C# 自定義窗體收縮容器 伸縮控件的實現


  這個容器的用途我就不多BB了,直接上效果。小哥哥我的原創,在這里分享給大家。

 

想要實現的效果,不用解釋也看得出來了,為了給窗體節省空間,讓它可以貼附在窗體的邊緣。

那么怎么實現這個效果呢?原理在於對Padding這個屬性的妙用。

另外可以看見,窗體在設計的時候也是可以進行事件的交互的,就像TabControl在設計的時候可以點擊每一個Page一樣,關於這個如果有興趣,就可以參考一下msdn 關於ParentControlDesigner和ControlDesigner給的例子了。

好了廢話不多說先上容器的代碼

  1 [Designer(typeof(MiracleControls.ControlDesigner.LayoutPanelDesigner))]
  2     [ToolboxBitmap(typeof(LayoutPanel))]
  3     public class LayoutPanel : Panel
  4     {
  5         private System.ComponentModel.Container components = null;
  6         public LayoutPanel()
  7         {
  8             components = new System.ComponentModel.Container();
  9             DoubleBuffered = true;
 10             BackColor = Color.Transparent;
 11             Padding = new Padding(0, 0, _controlSize, 0);
 12             if (_state == States.Open)
 13                 buttonRect = new Rectangle(Width - _controlSize, Height / 2 - _controlSize / 2, _controlSize, _controlSize);
 14             else
 15                 buttonRect = new Rectangle(0, Height / 2 - _controlSize / 2, _controlSize, _controlSize);
 16             Dock = DockStyle.Right;
 17         }
 18         #region Properties
 19         private Color _arrowColor = Color.White;
 20         private int _controlSize = 20;
 21         private Color _buttonColor = Color.FromArgb(55, 55, 55);
 22         private Color _hoverColor = Color.Orange;
 23         private States _state = States.Open;
 24         private int _memorySize = 50;
 25         private bool _hover = false;
 26         private bool _down = false;
 27 
 28         public override DockStyle Dock 
 29         {
 30             get { return base.Dock; }
 31             set { base.Dock = value == DockStyle.Left || value == DockStyle.Right ? value : Dock; }
 32         }
 33         public int ButtonSize
 34         {
 35             get { return _controlSize; }
 36             set { _controlSize = value >= 20 ? value : 20; changeSize(); Invalidate(); }
 37         }
 38         public Color ArrowColor
 39         {
 40             get { return _arrowColor; }
 41             set { _arrowColor = value; Invalidate(); }
 42         }
 43         public Color ButtonColor
 44         {
 45             get { return _buttonColor; }
 46             set { _buttonColor = value; Invalidate(); }
 47         }
 48         public Color HoverColor
 49         {
 50             get { return _hoverColor; }
 51             set { _hoverColor = value;Invalidate(buttonRect); }
 52         }
 53         private bool Hover
 54         {
 55             get { return _hover; }
 56             set
 57             {
 58                 _hover = value;
 59                 if (_hover)
 60                     Cursor = Cursors.Hand;
 61                 else
 62                     Cursor = Cursors.Default;
 63                 Invalidate(buttonRect);
 64             }
 65         }
 66         private bool Down
 67         {
 68             get { return _down; }
 69             set { _down = value; }
 70         }
 71         [Browsable(false)]
 72         public int MemorySize
 73         {
 74             get { return _memorySize; }
 75             set { _memorySize = value; }
 76         }
 77         public States State
 78         {
 79             get { return _state; }
 80             set
 81             {
 82                 _state = value;
 83                 changeSize();
 84                 Invalidate(buttonRect);
 85             }
 86         }
 87         public enum States
 88         { Open, Close };
 89         #endregion
 90 
 91         private void changeSize()
 92         {
 93             if (State == States.Close)
 94             {
 95                 if (Dock == DockStyle.Left)
 96                 {
 97                     Size = new Size(_controlSize, Height);
 98                     Padding = new Padding(_controlSize, 0, 0, 0);
 99                 }
100                 else if (Dock == DockStyle.Right)
101                 {
102                     Size = new Size(_controlSize, Height);
103                     Padding = new Padding(_controlSize, 0, 0, 0);
104                 }
105             }
106             else
107             {
108                 if (Dock == DockStyle.Left)
109                 {
110                     Padding = new Padding(0, 0, _controlSize, 0);
111                     Size = new Size(_memorySize, Height);
112                 }
113                 else if (Dock == DockStyle.Right)
114                 {
115                     Size = new Size(MemorySize, Height);
116                     Padding = new Padding(_controlSize, 0, 0, 0);
117                 }
118             }
119         }
120         Rectangle buttonRect;
121         protected override void OnPaint(PaintEventArgs e)
122         {
123             base.OnPaint(e);
124             Graphics G = e.Graphics;
125             G.SmoothingMode = SmoothingMode.HighQuality;
126             //繪制虛線框
127             if (Site != null)
128                 using (Pen pen = new Pen(Color.Blue))
129                 {
130                     pen.DashStyle = DashStyle.Custom;
131                     pen.DashPattern = new float[] { 5, 5 };
132                     G.DrawRectangle(pen, new Rectangle(Padding.Left, Top, Width - Padding.Right - 1, Height - Padding.Bottom - 1));
133                 }
134 
135             Rectangle circleRect = new Rectangle(buttonRect.X + 1, buttonRect.Y + 1, buttonRect.Width - 2, buttonRect.Height - 2);
136             using (LinearGradientBrush lb = new LinearGradientBrush(Dock == DockStyle.Left ? buttonRect :
137                 new Rectangle(buttonRect.X, buttonRect.Y, buttonRect.Width + 1, buttonRect.Height), BackColor, Color.FromArgb(180, _buttonColor), 0F))
138             {
139                 lb.SetBlendTriangularShape(0.5F);
140                 using (GraphicsPath GP = CreatePath())
141                     G.FillPath(lb, GP);
142             }
143             using (SolidBrush sb = new SolidBrush(ControlPaint.Dark(_buttonColor, 0.2F)))
144                 G.FillEllipse(sb, buttonRect);
145             using (SolidBrush sb = new SolidBrush(_buttonColor))
146             {
147                 G.FillEllipse(sb, circleRect);
148             }
149             if (Dock == DockStyle.Left || Dock == DockStyle.Right)
150                 DrawLeftRight(G, circleRect);
151         }
152         private void DrawLeftRight(Graphics G, Rectangle circleRect)
153         {
154             using (Pen pen = new Pen(_hover ? _hoverColor : _arrowColor, 2))
155             {
156                 if (Dock == DockStyle.Left)
157                     if (State == States.Open)
158                     {
159                         G.DrawLine(pen, circleRect.X + circleRect.Width / 8 + circleRect.Width / 4, circleRect.Y + 1 + circleRect.Height / 2,
160                                circleRect.X + circleRect.Width / 8 + circleRect.Width / 2, circleRect.Y + 1 + circleRect.Height / 4);
161                         G.DrawLine(pen, circleRect.X + circleRect.Width / 8 + circleRect.Width / 4, circleRect.Y + circleRect.Height / 2,
162                             circleRect.X + circleRect.Width / 8 + circleRect.Width / 2, circleRect.Y + circleRect.Height - circleRect.Height / 4);
163                     }
164                     else
165                     {
166                         G.DrawLine(pen, circleRect.X + circleRect.Width / 2 - circleRect.Width / 8, circleRect.Y + 1 + circleRect.Height / 4,
167                               circleRect.X - circleRect.Width / 8 + circleRect.Width - circleRect.Width / 4, circleRect.Y + 1 + circleRect.Height / 2);
168                         G.DrawLine(pen, circleRect.X + circleRect.Width / 2 - circleRect.Width / 8, circleRect.Y + circleRect.Height - circleRect.Height / 4,
169                                circleRect.X - circleRect.Width / 8 + circleRect.Width - circleRect.Width / 4, circleRect.Y + circleRect.Height / 2);
170                     }
171                 else
172                 if (State == States.Close)
173                 {
174                     G.DrawLine(pen, circleRect.X + circleRect.Width / 8 + circleRect.Width / 4, circleRect.Y + 1 + circleRect.Height / 2,
175                            circleRect.X + circleRect.Width / 8 + circleRect.Width / 2, circleRect.Y + 1 + circleRect.Height / 4);
176                     G.DrawLine(pen, circleRect.X + circleRect.Width / 8 + circleRect.Width / 4, circleRect.Y + circleRect.Height / 2,
177                         circleRect.X + circleRect.Width / 8 + circleRect.Width / 2, circleRect.Y + circleRect.Height - circleRect.Height / 4);
178                 }
179                 else
180                 {
181                     G.DrawLine(pen, circleRect.X + circleRect.Width / 2 - circleRect.Width / 8, circleRect.Y + 1 + circleRect.Height / 4,
182                           circleRect.X - circleRect.Width / 8 + circleRect.Width - circleRect.Width / 4, circleRect.Y + 1 + circleRect.Height / 2);
183                     G.DrawLine(pen, circleRect.X + circleRect.Width / 2 - circleRect.Width / 8, circleRect.Y + circleRect.Height - circleRect.Height / 4,
184                            circleRect.X - circleRect.Width / 8 + circleRect.Width - circleRect.Width / 4, circleRect.Y + circleRect.Height / 2);
185                 }
186             }
187         }
188         private GraphicsPath CreatePath()
189         {
190             GraphicsPath GP = new GraphicsPath();
191             if (Dock == DockStyle.Left)
192                 GP.AddLines(new PointF[] {new PointF(Width-_controlSize,Height/2-2*_controlSize),
193             new Point(Width-_controlSize/2,Height/2-_controlSize),new PointF(Width-_controlSize/2,Height/2+_controlSize)
194             ,new PointF(Width-_controlSize,Height/2+2*_controlSize),new PointF(Width-_controlSize,Height/2-2*_controlSize)});
195             else if (Dock == DockStyle.Right)
196                 GP.AddLines(new PointF[] {new PointF(_controlSize,Height/2-2*_controlSize),
197             new Point(_controlSize/2,Height/2-_controlSize),new PointF(_controlSize/2,Height/2+_controlSize)
198             ,new PointF(_controlSize,Height/2+2*_controlSize),new PointF(_controlSize,Height/2-2*_controlSize)});
199             return GP;
200         }
201         protected override void OnMouseDown(MouseEventArgs e)
202         {
203             base.OnMouseDown(e);
204             if (e.X > buttonRect.X && e.X < buttonRect.X + buttonRect.Width && e.Y > buttonRect.Y && e.Y < buttonRect.Y + buttonRect.Height)
205             {
206                 if (!Down)
207                     Down = true;
208             }
209             else { if (Down) Down = false; }
210         }
211         protected override void OnMouseLeave(EventArgs e)
212         {
213             base.OnMouseLeave(e);
214             Hover = false;
215         }
216         protected override void OnMouseUp(MouseEventArgs e)
217         {
218             base.OnMouseUp(e);
219             Down = false;
220         }
221         protected override void OnMouseMove(MouseEventArgs e)
222         {
223             base.OnMouseMove(e);
224             if (e.X > buttonRect.X && e.X < buttonRect.X + buttonRect.Width && e.Y > buttonRect.Y && e.Y < buttonRect.Y + buttonRect.Height)
225             {
226                 if (!Hover)
227                     Hover = true;
228             }
229             else { if (Hover) Hover = false; }
230         }
231         protected override void OnMouseClick(MouseEventArgs e)
232         {
233             base.OnMouseClick(e);
234             if (Hover && Down)
235                 State = _state == States.Open ? States.Close : States.Open;
236         }
237         protected override void OnResize(EventArgs eventargs)
238         {
239             base.OnResize(eventargs);
240             if (State != States.Close && this.Width > _controlSize)
241                 MemorySize = Width;
242             if (Dock == DockStyle.Left)
243             {
244                 if (_state == States.Open)
245                     buttonRect = new Rectangle(Width - _controlSize, Height / 2 - _controlSize / 2, _controlSize - 1, _controlSize - 1);
246                 else
247                     buttonRect = new Rectangle(0, Height / 2 - _controlSize / 2, _controlSize - 1, _controlSize - 1);
248             }
249             else if (Dock == DockStyle.Right)
250             {
251                 if (_state == States.Open)
252                     buttonRect = new Rectangle(0, Height / 2 - _controlSize / 2, _controlSize - 1, _controlSize - 1);
253                 else
254                     buttonRect = new Rectangle(0, Height / 2 - _controlSize / 2, _controlSize - 1, _controlSize - 1);
255             }
256             Invalidate();
257         }
258         protected override void Dispose(bool disposing)
259         {
260             if (disposing)
261             {
262                 if (components != null)
263                     components.Dispose();
264             }
265             base.Dispose(disposing);
266         }
267     }
View Code

首先 映入眼簾的有這樣一行特性[Designer(typeof(MiracleControls.ControlDesigner.LayoutPanelDesigner))]這是什么意思呢,這就是讓這個容器在窗體設計器上可以進行交互的一個必不可少的東西了,至於MiracleControls.ControlDesigner這個命名空間,可以不用關心,因為這是寫在我自己的類庫中的,有點懶,代碼中出現類似的命名空間,均不用關心。

好了,先提供設計器的類:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.ComponentModel;
 6 using System.Drawing;
 7 using MiracleControls.ContainerControls;
 8 using System.Windows.Forms;
 9 using System.Windows.Forms.Design;
10 
11 namespace MiracleControls.ControlDesigner
12 {
13     public class LayoutPanelDesigner : System.Windows.Forms.Design.ParentControlDesigner
14     {
15         public override SelectionRules SelectionRules
16         {
17             get
18             {
19                 if ((Control as LayoutPanel).State == LayoutPanel.States.Close)
20                     return System.Windows.Forms.Design.SelectionRules.None;//讓容器在關閉的狀態下不可以被調整
21                 else
22                     return SelectionRules.AllSizeable;
23             }
24         }
25         protected override bool GetHitTest(Point point)
26         {
27             LayoutPanel lay = base.Control as LayoutPanel;//得到宿主控件
28             Point e = lay.PointToClient(point);//得到鼠標的坐標
29             Rectangle buttonRect = new Rectangle(lay.Width - lay.ButtonSize, lay.Height / 2 - lay.ButtonSize / 2, lay.ButtonSize - 1, lay.ButtonSize - 1);//定義可以點擊的按鈕區域
30 if (lay.Dock == DockStyle.Left) 31 { 32 if (lay.State == LayoutPanel.States.Open) 33 buttonRect = new Rectangle(lay.Width - lay.ButtonSize, lay.Height / 2 - lay.ButtonSize / 2, lay.ButtonSize - 1, lay.ButtonSize - 1); 34 else 35 buttonRect = new Rectangle(0, lay.Height / 2 - lay.ButtonSize / 2, lay.ButtonSize - 1, lay.ButtonSize - 1); 36 } 37 else if (lay.Dock == DockStyle.Right) 38 { 39 if (lay.State == LayoutPanel.States.Open) 40 buttonRect = new Rectangle(0, lay.Height / 2 - lay.ButtonSize / 2, lay.ButtonSize - 1, lay.ButtonSize - 1); 41 else 42 buttonRect = new Rectangle(0, lay.Height / 2 - lay.ButtonSize / 2, lay.ButtonSize - 1, lay.ButtonSize - 1); 43 } 44 if (e.X > buttonRect.X && e.X < buttonRect.X + buttonRect.Width && e.Y > buttonRect.Y && e.Y < buttonRect.Y + buttonRect.Height) 45 { 46 if (isMouseDown) 47 { 48 lay.State = lay.State == LayoutPanel.States.Close ? LayoutPanel.States.Open : LayoutPanel.States.Close; 49 isMouseDown = false; 50 } 51 } 52 else 53 { isMouseDown = false; } 54 return false; 55 } 56 bool isMouseDown = false; 57 58 protected override void WndProc(ref Message m) 59 { 60 if (m.Msg == 0x0202) 61 { isMouseDown = true; } 62 base.WndProc(ref m); 63 } 64 } 65 }

代碼中沒什么解釋,這也是我一個不好的習慣。恐怕有一天自己都看不懂了。

 先看圖

 

 這是一個 繼承Panel的容器,這里為了空出位置 繪制可以點擊的那個按鈕,所以我們把這個容器的Padding改了,定義按鈕的尺寸為ButtonSize 那么上面的情況,按鈕的的位置也就好計算了,自己去悟吧。

 

 收縮的效果如上圖,只顯示一個可以展開的按鈕,收縮的原理猜也能夠猜測到了,就是改變了容器的尺寸。假如我們把容器的尺寸改變成ButtonSize 並且這個容器的Dock屬性 改為Right 那么是不是就可以貼附在窗體的右側了呢?想想這個道理就很簡單對不對。那么此時我們有一個問題,就是收縮之后怎么恢復呢?在代碼1中可以看到我寫的,我用一個屬性專門記錄了它展開時候的寬度,如果重新展開那么,恢復尺寸即可。

 

 那么上圖的這個 點擊事件 我們怎么判斷呢,這很簡單,判斷鼠標按下和移動的位置,就可以得到用戶是否點擊的這里了。提醒一下哦,鼠標移動和按下必須是同一個區域。至於按鈕的形狀,重寫OnPaint,就可以在里面盡情得繪制啦,如果對於繪制這方面不懂得畫,就去百度吧,我也懶得講。GDI+ 是很方便的。

算了 晚上10點40分了,該睡覺了,有問題的,再聯系我吧。對了感謝一下那些曾將幫助過我的人們,謝謝。晚安!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM