問題描述:
想在.Net下實現對一些非規則表單,沒有Caption,FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;表單的拖拽,最小化,最大化,特殊操作的實現(如圖1所示)。在黃色的地區即地區1裡實現對表單的拖拽操作,在橙色地區即地區2裡實現對表單的最小化操作,在藍色地區即地區3裡實現對表單的關閉操作,在綠色地區即地區4裡實現對表單的特殊操作(如雙倍表單)。
(圖1)
問題實現:
第一種方法:添加Label為Label添加Click事件。(如圖2所示) 如果要用這種方法實現,就要為每一個顏色地區進行切圖,並要保證有正確的切圖長和寬,然後設定Label的背景為這個圖片。
(圖2)
處理他們的Click事件,拖拽處理MouseDown MouseUp事件。
第二種方法:不添加Label只處理滑鼠事件,判斷滑鼠的位置然後決定執行什麼操作,這種方法很耗費資源,每次滑鼠點擊就要判斷,滑鼠是否在某個地區然後決定是否要處理。不過這個處理用多態封裝了。程式看起來比較整齊。
//定義常量
private Point point;
private const int dragMove=172;
private const int dragMin=72;
private const int dragClose=72;
private const int dragDouble=78;
private const int dragHeight=29;
private MouseHandleEnum dragEnum;
//定義MouseDown事件
private void DragMain_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
point.X=e.X;
point.Y=e.Y;
if(e.Y<dragHeight)
{
if(e.X<dragMove)
{
dragEnum = MouseHandleEnum.Move;
return;
}
if(e.X<dragMove+dragMin)
{
dragEnum = MouseHandleEnum.Min;
return;
}
if(e.X<dragMove+dragMin+dragClose)
{
dragEnum = MouseHandleEnum.Close;
return;
}
if(e.X<dragMove+dragMin+dragClose+dragDouble)
{
dragEnum = MouseHandleEnum.Double;
return;
}
}
}
//定義MouseUp事件
private void DragMain_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
point.X=e.X-point.X;
point.Y=e.Y-point.Y;
IDragMouse idragMouse;
switch(dragEnum)
{
case MouseHandleEnum.Move :
idragMouse = new MouseMove(point,this);
break;
case MouseHandleEnum.Min :
idragMouse = new MouseMin(point,this);
break;
case MouseHandleEnum.Close :
idragMouse = new MouseClose(point,this);
break;
case MouseHandleEnum.Double :
idragMouse = new MouseDouble(point,this);
break;
default:
idragMouse = null;
break;
}
if(idragMouse!=null)
idragMouse.MouseDo();
}
}
//定義基類
namespace DragMouse
{
public enum MouseHandleEnum
{
None=0,
Move=1,
Min=2,
Close=3,
Double=4,
}
public class DragMouseBase
{
protected Point point;
public Form form;
public DragMouseBase(Point point, Form form)
{
this.point = point;
this.form = form;
}
}
}
//定義介面
namespace DragMouse
{
/// <summary>
///
/// </summary>
public interface IDragMouse
{
void MouseDo();
}
}
//拖拽操作
namespace DragMouse
{
/// <summary>
///
/// </summary>
public class MouseClose : DragMouseBase,IDragMouse
{
public MouseClose(Point point,Form form):base(point,form)
{
//
// TODO: Add constructor logic here
//
}
#region IDragMouse Members
public void MouseDo()
{
Application.Exit();
// TODO: Add MouseClose.MouseDo implementation
}
#endregion
}
}
//其他動作類似。
第三種方法:是用責任鏈這個設計模式來封裝滑鼠的點擊操作,把操作分配到各個責任鏈的節點上,是程式更加物件導向,有更好的擴充性。
//兩個滑鼠事件
private void DragMain_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
request.GetInformation(e.X,e.Y);
}
private void DragMain_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
request.SetScreenPoint(e.X,e.Y);
}
//封裝的請求類
public class Request
{
public int iScreenX;
public int iScreenY;
public int eX;
public int eY;
public readonly int yHigh;
public readonly int dragLength;
public readonly int minLength;
public readonly int closeLength;
public readonly int doubleLength;
private DragHandler dragHandler;
private MinHandler minHandler;
private CloseHandler closeHandler;
private DoubleHandler doubleHandler;
public Form parentForm;
public void SetScreenPoint(int iX,int iY)
{
iScreenX = iX;
iScreenY = iY;
dragHandler.HandleRequest(this);
}
public void GetInformation(int ex,int ey)
{
eX=ex;
eY=ey;
}
public Request(int yhigh,int draglength,Form form)
{
yHigh = yhigh;
dragLength = draglength;
parentForm = form;
dragHandler = new DragHandler();
minHandler =new MinHandler();
closeHandler = new CloseHandler();
doubleHandler = new DoubleHandler();
dragHandler.SetSuccessor(minHandler);
minHandler.SetSuccessor(closeHandler);
closeHandler.SetSuccessor(doubleHandler);
}
public Request(int yhigh,int draglength,int minlength,Form form):this(yhigh,draglength,form)
{
minLength = minlength;
}
public Request(int yhigh,int draglength,int minlength,int closelength,Form form):this(yhigh,draglength,minlength,form)
{
closeLength = closelength;
}
public Request(int yhigh,int draglength,int minlength,int closelength, int doublelength , Form form):this(yhigh,draglength,minlength,closelength,form)
{
doubleLength = doublelength;
}
}
//拖拽操作
public class DragHandler : Handler
{
override public void HandleRequest(Request request)
{
// determine if we can handle the request
if ((request.eY<request.yHigh)&&(request.eX<request.dragLength)) // some complex decision making!
{
request.parentForm.Left += request.iScreenX-request.eX;
request.parentForm.Top += request.iScreenY-request.eY;
// request handling code goes here
}
else
{
// not handled here - pass on to next in the chain
if (successorHandler != null)
successorHandler.HandleRequest(request);
}
}
}
//其他動作類似
第四種方法:(只是有想法還沒有找到成功的實現辦法)
在MFC中可以用PostMessage或者SendMessag發訊息,當按一下滑鼠,但不在表單的CaptionTitle上時,發一個訊息告訴系統滑鼠在CaptionTitle(每個視窗自己TitleBar)上,這樣視窗的拖拽就可以由系統託管了。現在實現了在視窗中任意位置單擊滑鼠拖拽表單。但是沒有實現上面要求的那些多樣化操作。
if(point.y<this->m_Height)
{
//發訊息給系統偽裝滑鼠在Caption Bar 上。
if(point.x<this->m_Drag)
{
PostMessage(WM_NCLBUTTONDOWN,
HTCAPTION,
MAKELPARAM(point.x,point.y));
return;
}
if(point.x<this->m_Drag+this->m_Min&&point.x>this->m_Drag)
{
PostMessage(WM_NCLBUTTONDOWN,
HTMINBUTTON,
MAKELPARAM(point.x,point.y));
return;
}
if(point.x<this->m_Drag+this->m_Min+this->m_Close&&point.x>this->m_Drag+this->m_Min)
{
PostMessage(WM_NCLBUTTONDOWN,
HTCLOSE,
MAKELPARAM(point.x,point.y));
return;
}
if(point.x<this->m_Drag+this->m_Min+this->m_Close+this->m_Double&&point.x>this->m_Drag+this->m_Min+this->m_Close)
{
CRgn *rgn = new CRgn();
CRect *rect =new CRect();
this->GetWindowRect(*rect);
this->SetWindowRgn(*rgn,true);
return;
}
}