1. 程式人生 > >C# 實現拖拉控制元件改變位置與大小

C# 實現拖拉控制元件改變位置與大小

前言:

  很多時候我們需要在執行時,動態地改變控制元件的位置以及大小,以獲得更好的佈局。比如說實際專案中的可自定義的報表、可自定義的單據等諸如此類。它們有個特點就是允許客戶或者二次開發人員設計它們需要的介面設定功能。

  本人以前也做過可自定義系統,包括介面和功能,主要為了減少開發人員的工作量以及程式的靈活性和健壯性。

  本篇主要討論下,在執行時如何實現拖拉控制元件,達到改變控制元件位置與大小。功能將模擬VS設計介面時的拖拉功能。

  (本篇暫不涉及多控制元件同時操作)

一、技術概述

  其實實現執行時控制元件的拖拉並不難,主要是改變控制元件的Location與Size即可。動態調整時再捕獲MouseDown、MouseMove及MouseUp事件來實時修改上述兩個屬性就可以實現。

二、功能規劃

  在此之前,我們先來看下.net設計介面,一旦選中某個控制元件時,將會出現如下圖的邊框:

  

  之後就可以通過拖拉出現的邊框改變其大小。而改變控制元件的位置,實際上是當滑鼠點選在控制元件內部拖動時實現的。

  所有本例也將功能分為兩個部分實現,分別為控制元件內部拖動改變位置與控制元件邊框拖拉改變大小。

三、具體實現

1.拖動控制元件改變位置

  首先,新建一個專案,然後新增一個類,取名叫MoveControl,該類用來給控制元件掛載事件實現拖動。

  接著在該類中新增欄位currentControl,用來儲存需要操作的控制元件,即通過建構函式傳遞的控制元件。

  接著建立一方法--AddEvents,用來給當前的控制元件掛載事件。

  程式碼如下:   

DragControl
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 using System.Windows.Forms;
 5 using System.Drawing;
 6 
 7 namespace DragControl
 8 {
 9     public class MoveControl
10     {
11         #region Constructors
12
public MoveControl(Control ctrl) 13 { 14 currentControl = ctrl; 15 AddEvents(); 16 } 17 #endregion 18 19 #region Fields 20 private Control currentControl; //傳入的控制元件 21 #endregion 22 23 #region Properties 24 25 #endregion 26 27 #region Methods 28 /// <summary> 29 /// 掛載事件 30 /// </summary> 31 private void AddEvents() 32 { 33 currentControl.MouseClick += new MouseEventHandler(MouseClick); 34 currentControl.MouseDown += new MouseEventHandler(MouseDown); 35 currentControl.MouseMove += new MouseEventHandler(MouseMove); 36 currentControl.MouseUp += new MouseEventHandler(MouseUp); 37 } 38 #endregion 39 40 #region Events 41 /// <summary> 42 /// 滑鼠單擊事件:用來顯示邊框 43 /// </summary> 44 /// <param name="sender"></param> 45 /// <param name="e"></param> 46 void MouseClick(object sender, MouseEventArgs e) 47 { 48 } 49 50 /// <summary> 51 /// 滑鼠按下事件:記錄當前滑鼠相對窗體的座標 52 /// </summary> 53 void MouseDown(object sender, MouseEventArgs e) 54 { 55 56 } 57 58 /// <summary> 59 /// 滑鼠移動事件:讓控制元件跟著滑鼠移動 60 /// </summary> 61 void MouseMove(object sender, MouseEventArgs e) 62 { 63 } 64 65 /// <summary> 66 /// 滑鼠彈起事件:讓自定義的邊框出現 67 /// </summary> 68 void MouseUp(object sender, MouseEventArgs e) 69 { 70 } 71 #endregion 72 } 73 }

  接著我們需要實現MouseDown、MouseMove、MouseUp三個事件。

  不過在此之前,我們必須要弄清楚,移動即表示座標的改變,所以必定要有個起始座標和終點座標。

  所以我們在MoveControl類中加入兩個欄位。

private Point pPoint; //上個滑鼠座標
private Point cPoint; //當前滑鼠座標

  而且在開始拖動之前,我們肯定需要先單擊一次控制元件。在MouseDown時獲取當前游標的位置,儲存到pPoint中。

  (此處用Cursor獲得座標的好處,就是忽略掉容器的麻煩問題)

1         /// <summary>
2         /// 滑鼠單擊事件:用來顯示邊框
3         /// </summary>
4         void MouseClick(object sender, MouseEventArgs e)
5         {
6             pPoint = Cursor.Position;   
7         }

  接著便實現MouseMove的事件,當滑鼠左鍵按下時,接著移動滑鼠後,繼續滑鼠移動後的座標,然後與MouseDown時記下的座標相減,就得到滑鼠的位移值,接著控制元件的Location加上該位移值即可,然後更新pPoint。  

 1         /// <summary>
 2         /// 滑鼠移動事件:讓控制元件跟著滑鼠移動
 3         /// </summary>
 4         void MouseMove(object sender, MouseEventArgs e)
 5         {
 6             Cursor.Current = Cursors.SizeAll; //當滑鼠處於控制元件內部時,顯示游標樣式為SizeAll
 7             //當滑鼠左鍵按下時才觸發
 8             if (e.Button == MouseButtons.Left)
 9             {
10                 cPoint = Cursor.Position; //獲得當前滑鼠位置
11                 int x = cPoint.X - pPoint.X;
12                 int y = cPoint.Y - pPoint.Y;
13                 currentControl.Location = new Point(currentControl.Location.X + x, currentControl.Location.Y + y);
14                 pPoint = cPoint;
15             }
16         }

  由於此時還沒涉及到邊框,所以MouseUp暫時不用處理。至此拖動的基本功能已經實現!

  目前MoveControl的完整程式碼如下:  

MoveControl
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 using System.Windows.Forms;
 5 using System.Drawing;
 6 
 7 namespace DragControl
 8 {
 9     public class MoveControl
10     {
11         #region Constructors
12         public MoveControl(Control ctrl)
13         {
14             currentControl = ctrl;
15             AddEvents();
16         }
17         #endregion
18 
19         #region Fields
20         private Control currentControl; //傳入的控制元件
21         private Point pPoint; //上個滑鼠座標
22         private Point cPoint; //當前滑鼠座標
23         #endregion
24 
25         #region Properties
26 
27         #endregion
28 
29         #region Methods
30         /// <summary>
31         /// 掛載事件
32         /// </summary>
33         private void AddEvents()
34         {
35             currentControl.MouseDown += new MouseEventHandler(MouseDown);
36             currentControl.MouseMove += new MouseEventHandler(MouseMove);
37             currentControl.MouseUp += new MouseEventHandler(MouseUp);
38         }
39 
40         /// <summary>
41         /// 繪製拖拉時的黑色邊框
42         /// </summary>
43         public static void DrawDragBound(Control ctrl)
44         {
45             ctrl.Refresh();
46             Graphics g = ctrl.CreateGraphics();
47             int width = ctrl.Width;
48             int height = ctrl.Height;
49             Point[] ps = new Point[5]{new Point(0,0),new Point(width -1,0),
50                 new Point(width -1,height -1),new Point(0,height-1),new Point(0,0)};
51             g.DrawLines(new Pen(Color.Black), ps);
52         }   
53         #endregion
54 
55         #region Events
56         /// <summary>
57         /// 滑鼠按下事件:記錄當前滑鼠相對窗體的座標
58         /// </summary>
59         void MouseDown(object sender, MouseEventArgs e)
60         {
61             pPoint = Cursor.Position;
62         }
63 
64         /// <summary>
65         /// 滑鼠移動事件:讓控制元件跟著滑鼠移動
66         /// </summary>
67         void MouseMove(object sender, MouseEventArgs e)
68         {
69             Cursor.Current = Cursors.SizeAll; //當滑鼠處於控制元件內部時,顯示游標樣式為SizeAll
70             //當滑鼠左鍵按下時才觸發
71             if (e.Button == MouseButtons.Left)
72             {
73                 MoveControl.DrawDragBound(this.currentControl);
74                 cPoint = Cursor.Position; //獲得當前滑鼠位置
75                 int x = cPoint.X - pPoint.X;
76                 int y = cPoint.Y - pPoint.Y;
77                 currentControl.Location = new Point(currentControl.Location.X + x, currentControl.Location.Y + y);
78                 pPoint = cPoint;
79             }
80         }
81 
82         /// <summary>
83         /// 滑鼠彈起事件:讓自定義的邊框出現
84         /// </summary>
85         void MouseUp(object sender, MouseEventArgs e)
86         {
87             this.currentControl.Refresh();
88         }
89         #endregion
90     }
91 }

  下面我們來測試下拖動的功能。

  建立一個Form窗體,可以再介面上新增你要測試的控制元件型別,此處我只用TextBox左下測試。在Load的中新增以下程式碼,將Form中的所有控制元件掛載上拖拉功能。

1         private void Form1_Load(object sender, EventArgs e)
2         {
3             foreach (Control ctrl in this.Controls)
4             {
5                 new MoveControl(ctrl);
6             }
7         }

  此時,有心人可能會發現VS中拖動控制元件時,將會出現黑色邊框,而處於沒有。

  這也很簡單,我們在MouseMove時加上如下程式碼即可。

 1         /// <summary>
 2         /// 繪製拖拉時的黑色邊框
 3         /// </summary>
 4         public static void DrawDragBound(Control ctrl)
 5         {
 6             ctrl.Refresh();
 7             Graphics g = ctrl.CreateGraphics();
 8             int width = ctrl.Width;
 9             int height = ctrl.Height;
10             Point[] ps = new Point[5]{new Point(0,0),new Point(width -1,0),
11                 new Point(width -1,height -1),new Point(0,height-1),new Point(0,0)};
12             g.DrawLines(new Pen(Color.Black), ps);
13         }    
14 
15 
16         /// <summary>
17         /// 滑鼠移動事件:讓控制元件跟著滑鼠移動
18         /// </summary>
19         void MouseMove(object sender, MouseEventArgs e)
20         {
21             Cursor.Current = Cursors.SizeAll; //當滑鼠處於控制元件內部時,顯示游標樣式為SizeAll
22             //當滑鼠左鍵按下時才觸發
23             if (e.Button == MouseButtons.Left)
24             {
25                 MoveControl.DrawDragBound(this.currentControl);
26                 cPoint = Cursor.Position; //獲得當前滑鼠位置
27                 int x = cPoint.X - pPoint.X;
28                 int y = cPoint.Y - pPoint.Y;
29                 currentControl.Location = new Point(currentControl.Location.X + x, currentControl.Location.Y + y);
30                 pPoint = cPoint;
31             }
32         }

  同時要在MoveUp的時候,重新整理一下自己,讓黑色邊框消失掉!  

1         /// <summary>
2         /// 滑鼠彈起事件:讓自定義的邊框出現
3         /// </summary>
4         void MouseUp(object sender, MouseEventArgs e)
5         {
6             this.currentControl.Refresh();
7         }

  接著用沒有邊框的控制元件測試下就會很明顯。如下圖所示:   

 

2.通過邊框拖拉控制元件改變大小

  此處的主要思路為:點選控制元件的時候,建立一個自定義的使用者控制元件,該使用者控制元件響應區域就是傳入控制元件的邊框區域,同時給它畫上虛線與8個小圓圈。

  第一、建立使用者控制元件--FrameControl(邊框控制元件),然後增加一個欄位用來儲存傳入的控制元件,還有載入事件,此處類同前面的MoveControl。

FrameControl

            
           

相關推薦

C# 實現拖拉控制元件改變位置大小

前言:   很多時候我們需要在執行時,動態地改變控制元件的位置以及大小,以獲得更好的佈局。比如說實際專案中的可自定義的報表、可自定義的單據等諸如此類。它們有個特點就是允許客戶或者二次開發人員設計它們需要的介面設定功能。   本人以前也做過可自定義系統,包括

c#如何保持控制元件位置窗體同比例?C#實現窗體控制元件隨窗體大小改變(包括字型大小)

可以通過Dock屬性和Anchor屬性來控制 設定控制元件的 Anchor屬性 如果要隨著窗體變化而變化 則設定為Top, Bottom, Left, Right 當然也可以只設定期中幾個值 左邊的設定TOP,LEFT,中間設NONE,右邊的設right,bottom

C#當窗體大小改變時,控制元件位置大小隨之改變

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.For

C# 實現TrackBar控制元件美化換膚

TrackBar控制元件沒有像其他控制元件那樣,直接提供給使用者重繪的函式,要實現個性化的TrackBar控制元件,一種方法是繼承Control完全的自己實現,這種方法就是實現標準的Windows控制元件功能需要自己處理很多東西,例如:實現一樣的屬性、鍵盤的操作、滑鼠滾

C++實現WebBrowser控制元件中對滑鼠點選事件的監聽,並獲取所點選標籤的超連結

        主要步驟如下:         1、接收網頁事件(參考資料) 要響應網頁事件,需要實現IDispatch介面,並在其Invoke()方法中處理收到的訊息。對於MFC,因為CCmdTarget類已經實現了該介面,所以只需要繼承CCmdTarget並結合相關巨

duilib中獲取的控制元件位置或者大小不對的可能的原因

duilib初學者可能總會有這樣的疑問:為什麼我獲取的控制元件位置或者大小和我想象中的不一樣? 位置不一樣可能的原因: 1.xml中直接配置的位置和實際顯示之後的位置確實是不一樣的.xml中設定的位置(相對或絕對)都是基於他的父控制元件左上角.而實際顯示之後獲取的位置,是基於整個客戶區的

C#如何讓控制元件隨著窗體變化大小

分析需求   各位請看這個小窗體,我把這控制元件按陣型依次排開, 可當我讓窗體全屏顯示的時候,問題就出來了!如圖      如何全屏顯示窗體裡的控制元件 採用Form_Resize(

android 控制控制元件位置大小

方法一: Android的介面佈局可以用兩種方法,一種是在xml中佈局,一種是和JAVA中Swing一樣在JAVA程式碼中實現Ui介面的佈局,用xml的佈局管理器佈局是很方便的,但是在一些程式碼中需要動態的顯示介面,這個時候xml就缺少了一種靈活性,使用XML和JAVA

android 開發零起步學習筆記(九):android 控制控制元件位置大小及Layout相關屬性

1、 ? 1 2 3 4 5 6 7 8 9 10 11 LinearLayout.LayoutParams p = newLinearLayout.LayoutParams(      

如何實現控制元件隨對話方塊大小變化而自動調整大小位置

1. 處理對話方塊的WM_SIZE,然後用MoveWindow或者SetWindowPos來把對話方塊上面的控制元件重新調整新位置和大小。  2. 基本的做法就是響應WM_SIZE訊息,並按照視窗大小比例來調整控制元件的位置和大小,控制元件的大小最好設定成視窗的百分之幾,這

iOS開發之資訊類App常用分類控制元件的封裝實現(CollectionView+Swift3.0+)

今天部落格中,我們就來實現一下一些常用資訊類App中常用的分類選擇的控制元件的封裝。本篇部落格中沒有使用到什麼新的技術點,如果非得說用到了什麼新的技術點的話,那麼勉強的說,用到了一些iOS9以後UICollectionView新增的一些新的特性。本篇部落格所涉及的技術點主要有UICollectionView的

C#】透明控制元件實現

  轉載 http://wtunuiyf.blog.163.com/blog/static/18003200871951529580/   最近做的一個任務中需要用到透明控制元件,結果在網上找了好久,也沒有一個能真正實現的。當然,講透明form的到是很多,需要呼叫Window

C#通過webbrowser控制元件javascript互動

1.C#裡呼叫控制元件裡面網頁的js函式     //呼叫JavaScript的messageBox方法,並傳入引數     object[] objects = new object[1];     objects[0] = “C#訪問JavaScript指令碼";  

C#控制元件改變大小時閃爍問題

首先是一段窗體控制元件隨窗體大小改變程式碼,但是在使用這段程式碼後,當窗體中控制元件較多時每次改變窗體大小後都會出現閃爍情況 private float X; private float Y; private void setTag(Control cons) { fo

Android 程式碼當中動態改變某個控制元件位置

不多說,直接上程式碼: private ImageView imageView; //小圓圈 private RelativeLayout mRlImg; mRlImg = (RelativeLayout) view.findViewById(R.id.rl_img);

Android 動態佈局 動態生成 銷燬控制元件 改變控制元件位置

一種基於Android的動態佈局和管理的實現方法 技術領域 本實用新型涉及到一種在嵌入式平臺上動態生成、銷燬控制元件及動態改變位置的方法,尤其涉及Android平臺的通過自定義的XML或INI配置檔案動態佈局方法。 背景技術 為了更好地管理Android應用的使用者介面裡面

執行時動態移動控制元件位置改變控制元件的尺寸

Delphi的TCustomForm留有一個為IDE的視覺化設計的用的介面Designer. Designer是IDesignerNotify, IDesignerHook 介面. 我在這裡實現了這些介面. 程式不用做任何改動,只要調函式BeginDesign就可以開始像I

使用C#的Timer控制元件實現定時觸發事件

使用C#的Timer控制元件來實現定時觸發事件,其主要引數如下: Timer.Enabled 屬性用於設定是否啟用定時器 Timer.Interval 屬性,事件的間隔,單位毫秒 Timer.Elapsed 事件,達到間隔時發生 示例: using System; usin

C# WPF TextBox控制元件變數的繫結

在WPF中,可以將TextBox控制元件(其他控制元件也基本一樣)與相應的變數進行繫結,做出改變變數則控制元件也跟著改變的效果。雖然其原理跟原本的訊息響應是一樣的,只是在外部加了層封裝,但就是因為這層封裝,使得在編寫介面的過程中方便了很多。 首先需要宣告一個類

C#WebBrowser控制元件使用教程技巧收集

[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern bool InternetGetCookieEx(string pchUrl, string pchCookieName, S