📄 crecttracker.cs
字号:
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Drawing.Drawing2D;
namespace zuobiao
{
/// <summary>
/// CRectTracker 的摘要说明。
/// </summary>
/// <summary>
/// CRectTracker主要是绘制橡皮线的一个类
/// </summary>
public class CRectTracker : System.Object
{
private static Cursor []Cursors =new Cursor[10];
private static HatchBrush HatchBrush = null;
private static Pen BlackDottedPen = null;
private static int HandleSize = 4;
private static Pen DotedPen=null;
#region "API Calls"
struct POINTAPI
{
public Int32 x;
public Int32 y;
};
struct MSG
{
public Int32 hwnd;
public Int32 message;
public Int32 wParam;
public Int32 lParam;
public Int32 time;
public POINTAPI pt;
};
[DllImport("user32.dll", SetLastError=true )]
private static extern Int32 GetMessage (ref MSG lpMsg,Int32 hwnd,Int32 wMsgFilterMin,Int32 wMsgFilterMax);
[DllImport("user32.dll", SetLastError=true )]
private static extern Int32 DispatchMessage (ref MSG lpMsg);
[DllImport("user32.dll", SetLastError=true )]
private static extern Int32 TranslateMessage (ref MSG lpMsg);
[DllImport("gdi32.dll", SetLastError=true )]
private static extern drawingMode SetROP2(IntPtr hdc,drawingMode fnDrawMode);
[DllImport("gdi32.dll", SetLastError=true )]
private static extern backMode SetBkMode(IntPtr hdc,backMode fnBKMode);
public enum drawingMode
{
R2_BLACK= 1 ,
R2_NOTMERGEPEN= 2 ,
R2_MASKNOTPEN= 3 ,
R2_NOTCOPYPEN= 4 ,
R2_MASKPENNOT= 5 ,
R2_NOT= 6 ,
R2_XORPEN= 7 ,
R2_NOTMASKPEN= 8 ,
R2_MASKPEN= 9 ,
R2_NOTXORPEN= 10 ,
R2_NOP= 11 ,
R2_MERGENOTPEN= 12 ,
R2_COPYPEN= 13 ,
R2_MERGEPENNOT= 14 ,
R2_MERGEPEN= 15 ,
R2_WHITE= 16 ,
R2_LAST= 16
};
[DllImport("gdi32.dll", SetLastError=true )]
private static extern bool MoveToEx(IntPtr hDC,int x,int y,POINTAPI lpPoint);
[DllImport("gdi32.dll", SetLastError=true )]
private static extern bool LineTo(IntPtr hDC,int x,int y);
[DllImport("gdi32.dll", SetLastError=true )]
private static extern IntPtr CreatePen(int nPenStyle,int nWidth,int crColor);
[DllImport("gdi32.dll", SetLastError=true )]
private static extern IntPtr SelectObject(IntPtr hDC,IntPtr hObject);
[DllImport("gdi32.dll", SetLastError=true )]
private static extern bool DeleteObject(IntPtr hObject);
private const int CX_BORDER=1;
private const int CY_BORDER=1;
private const int WM_MOUSEFIRST = 0x0200;
private const int WM_MOUSEMOVE = 0x0200;
private const int WM_LBUTTONDOWN = 0x0201;
private const int WM_LBUTTONUP = 0x0202;
private const int WM_LBUTTONDBLCLK = 0x0203;
private const int WM_RBUTTONDOWN = 0x0204;
private const int WM_RBUTTONUP = 0x0205;
private const int WM_RBUTTONDBLCLK = 0x0206;
private const int WM_MBUTTONDOWN = 0x0207;
private const int WM_MBUTTONUP = 0x0208;
private const int WM_MBUTTONDBLCLK = 0x0209;
private const int WM_KEYDOWN = 0x100;
private const int WM_KEYUP = 0x101;
#endregion
// Style Flags
public enum StyleFlags
{
solidLine = 1, dottedLine = 2, hatchedBorder = 4,
resizeInside = 8, resizeOutside = 16, hatchInside = 32,
};
// Hit-Test codes
public enum TrackerHit
{
hitNothing = -1,
hitTopLeft = 0, hitTopRight = 1, hitBottomRight = 2, hitBottomLeft = 3,
hitTop = 4, hitRight = 5, hitBottom = 6, hitLeft = 7, hitMiddle = 8
};
public enum backMode
{
TRANSPARENT= 1,
OPAQUE= 2
};
public enum rectPos
{
Left =0,
Right,
Top,
Bottom
};
struct HANDLEINFO
{
public HANDLEINFO(rectPos X,rectPos Y,int CX,int CY,int HX,int HY,int IX,int IY)
{
nOffsetX=X;
nOffsetY=Y;
nCenterX=CX;
nCenterY=CY;
nHandleX=HX;
nHandleY=HY;
nInvertX=IX;
nInvertY=IY;
}
public rectPos nOffsetX; // offset within RECT for X coordinate
public rectPos nOffsetY; // offset within RECT for Y coordinate
public int nCenterX; // adjust X by Width()/2 * this number
public int nCenterY; // adjust Y by Height()/2 * this number
public int nHandleX; // adjust X by handle size * this number
public int nHandleY; // adjust Y by handle size * this number
public int nInvertX; // handle converts to this when X inverted
public int nInvertY; // handle converts to this when Y inverted
};
struct RECTINFO
{
public RECTINFO(rectPos offset,int nsign)
{
nOffsetAcross=offset;
nSignAcross=nsign;
}
public rectPos nOffsetAcross; // offset of opposite point (ie. left->right)
public int nSignAcross; // sign relative to that point (ie. add/subtract)
}
static HANDLEINFO [] HandleInfo=new HANDLEINFO[]{
// corner handles (top-left, top-right, bottom-right, bottom-left
new HANDLEINFO(rectPos.Left, rectPos.Top,0, 0, 0, 0, 1, 3 ),
new HANDLEINFO(rectPos.Right,rectPos.Top,0, 0, -1, 0, 0, 2),
new HANDLEINFO(rectPos.Right,rectPos.Bottom,0, 0, -1, -1, 3, 1),
new HANDLEINFO(rectPos.Left, rectPos.Bottom, 0, 0, 0, -1, 2, 0 ),
// side handles (top, right, bottom, left)
new HANDLEINFO(rectPos.Left, rectPos.Top,1, 0, 0, 0, 4, 6),
new HANDLEINFO(rectPos.Right,rectPos.Top,0, 1, -1, 0, 7, 5),
new HANDLEINFO(rectPos.Left, rectPos.Bottom, 1, 0, 0, -1, 6, 4 ),
new HANDLEINFO(rectPos.Left, rectPos.Top,0, 1, 0, 0, 5, 7)
};
static RECTINFO [] RectInfo=new RECTINFO[]{
new RECTINFO(rectPos.Right, +1),
new RECTINFO(rectPos.Bottom, +1),
new RECTINFO(rectPos.Left,-1),
new RECTINFO(rectPos.Top, -1 )
};
// Attributes
public StyleFlags m_nStyle; // current state
public Rectangle m_rect; // current position (always in pixels)
public Size m_sizeMin; // minimum X and Y size during track operation
public int m_nHandleSize=0; // size of resize handles (default from WIN.INI)
protected bool m_bAllowInvert=false; // flag passed to Track or TrackRubberBand
protected Rectangle m_rectLast;
protected Size m_sizeLast;
protected bool m_bErase=false; // TRUE if DrawTrackerRect is called for erasing
protected bool m_bFinalErase=false; // TRUE if DragTrackerRect called for final erase
protected static bool bInitialized=false;
public CRectTracker()
{
Construct();
}
public CRectTracker(Rectangle rect, StyleFlags nStyle)
{
Construct();
m_rect=rect;
m_nStyle = nStyle;
}
protected void Construct()
{
if(false==bInitialized)
{
// initialize the cursor array
Cursors[0] = System.Windows.Forms.Cursors.SizeNWSE;
Cursors[1] = System.Windows.Forms.Cursors.SizeNESW;
Cursors[2] = Cursors[0];
Cursors[3] = Cursors[1];
Cursors[4] = System.Windows.Forms.Cursors.SizeNS;
Cursors[5] = System.Windows.Forms.Cursors.SizeWE;
Cursors[6] = Cursors[4];
Cursors[7] = Cursors[5];
Cursors[8] = System.Windows.Forms.Cursors.SizeAll;
Cursors[9] = System.Windows.Forms.Cursors.PanSW;
bInitialized = true;
BlackDottedPen=new Pen(System.Drawing.Color.Red,1);
HatchBrush=new HatchBrush(HatchStyle.BackwardDiagonal,Color.Red,Color.FromArgb(0));
DotedPen=new Pen(Color.Red ,1);
DotedPen.DashStyle=DashStyle.Dot;
}
m_nStyle = 0;
m_nHandleSize = HandleSize;
m_sizeMin.Height = m_sizeMin.Width = m_nHandleSize*2;
m_rectLast=new Rectangle(0,0,0,0);
m_sizeLast.Width = m_sizeLast.Height = 0;
m_bErase = false;
m_bFinalErase = false;
}
// Operations
public void OnDraw(Graphics gs)
{
System.Drawing.Drawing2D.GraphicsState OldState=gs.Save();
IntPtr hdc = new IntPtr();
// get normalized rectangle
Rectangle rect = m_rect;
NormalizeRect(ref rect);
// draw lines
if ((m_nStyle & (StyleFlags.dottedLine|StyleFlags.solidLine)) != 0)
{
if((m_nStyle&StyleFlags.dottedLine)!=0)
BlackDottedPen.DashStyle=DashStyle.Dot;
else
BlackDottedPen.DashStyle=DashStyle.Solid;
rect.Inflate(new Size(+1, +1)); // borders are one pixel outside
gs.DrawRectangle(BlackDottedPen,rect);
}
// hatch inside
if ((m_nStyle & StyleFlags.hatchInside) != 0)
{
gs.FillRectangle(HatchBrush,rect.Left+1, rect.Top+1, rect.Width-1, rect.Height-1);
}
// draw hatched border
if ((m_nStyle & StyleFlags.hatchedBorder) != 0)
{
Rectangle rectTrue=new Rectangle(0,0,0,0);
GetTrueRect(ref rectTrue);
gs.FillRectangle(HatchBrush,rectTrue.Left, rectTrue.Top, rectTrue.Width,rect.Top-rectTrue.Top);
gs.FillRectangle(HatchBrush,rectTrue.Left, rect.Bottom,rectTrue.Width,rectTrue.Bottom-rect.Bottom);
gs.FillRectangle(HatchBrush,rectTrue.Left, rect.Top, rect.Left-rectTrue.Left,rect.Height);
gs.FillRectangle(HatchBrush,rect.Right, rect.Top, rectTrue.Right-rect.Right,rect.Height);
}
// draw resize handles
if ((m_nStyle & (StyleFlags.resizeInside|StyleFlags.resizeOutside)) != 0)
{
uint mask = GetHandleMask();
for (int i = 0; i < 8; ++i)
{
if ((mask&(1<<i))!=0)
{
GetHandleRect(i, ref rect);
SolidBrush bursh=new SolidBrush(Color.YellowGreen);
gs.FillRectangle(bursh,rect);
}
}
}
gs.Restore(OldState);
}
public bool SetCursor(System.Windows.Forms.Control frm, uint nHitTest,Point MousePoint)
{
// trackers should only be in client area
frm.PointToClient(MousePoint);
if (!frm.ClientRectangle.Contains(MousePoint))
return false;
// convert cursor position to client co-ordinates
// do hittest and normalize hit
int nHandle = (int)HitTestHandles(MousePoint);
if (nHandle < 0)
return false;
// need to normalize the hittest such that we get proper cursors
nHandle = NormalizeHit(nHandle);
// handle special case of hitting area between handles
// (logically the same -- handled as a move -- but different cursor)
if (nHandle == (int)TrackerHit.hitMiddle && !m_rect.Contains(MousePoint))
{
// only for trackers with hatchedBorder (ie. in-place resizing)
if ((m_nStyle & StyleFlags.hatchedBorder)!=0)
nHandle = 9;
}
Debug.Assert(nHandle < 10);
frm.Cursor=Cursors[nHandle];
return true;
}
public TrackerHit HitTest(Point point)
{
TrackerHit hitResult = TrackerHit.hitNothing;
Rectangle rectTrue=new Rectangle();
GetTrueRect(ref rectTrue);
Debug.Assert(rectTrue.Left <= rectTrue.Right);
Debug.Assert(rectTrue.Top <= rectTrue.Bottom);
if (rectTrue.Contains(point))
{
if ((m_nStyle & (StyleFlags.resizeInside|StyleFlags.resizeOutside)) != 0)
hitResult = HitTestHandles(point);
else
hitResult = TrackerHit.hitMiddle;
}
return hitResult;
}
protected int NormalizeHit(int nHandle)
{
Debug.Assert(nHandle <= 8 && nHandle >= -1);
if (nHandle == (int)TrackerHit.hitMiddle || nHandle ==(int)TrackerHit.hitNothing)
return nHandle;
HANDLEINFO refHandleInfo = HandleInfo[nHandle];
if (m_rect.Width< 0)
{
nHandle = refHandleInfo.nInvertX;
refHandleInfo = HandleInfo[nHandle];
}
if (m_rect.Height< 0)
nHandle = refHandleInfo.nInvertY;
return nHandle;
}
public bool Track(System.Windows.Forms.Control frm, Point point, bool bAllowInvert,Form frmClipTo)
{
// perform hit testing on the handles
int nHandle = (int)HitTestHandles(point);
if (nHandle < 0)
{
// didn't hit a handle, so just return FALSE
return false;
}
// otherwise, call helper function to do the tracking
m_bAllowInvert = bAllowInvert;
return TrackHandle(nHandle, frm, point, frmClipTo);
}
public bool TrackRubberBand(System.Windows.Forms.Control frm, Point point, bool bAllowInvert)
{
// simply call helper function to track from bottom right handle
m_bAllowInvert = bAllowInvert;
m_rect=new Rectangle(point.X, point.Y,0, 0);
return TrackHandle((int)TrackerHit.hitBottomRight, frm, point, null);
}
// Overridables
private void DrawDragRect(Graphics gs,Rectangle rect,Rectangle rectLast)
{
IntPtr hdc=new IntPtr();
IntPtr hPen=new IntPtr();
IntPtr hOldPen=new IntPtr();
POINTAPI ptsOld = new POINTAPI();
hdc=gs.GetHdc();
drawingMode OldMode=SetROP2(hdc,drawingMode.R2_NOTXORPEN);
hPen=CreatePen(2,1,0x0);
hOldPen=SelectObject(hdc,hPen);
if(!rectLast.IsEmpty)
{
MoveToEx(hdc, rectLast.Left, rectLast.Top, ptsOld);
LineTo(hdc, rectLast.Right,rectLast.Top);
LineTo(hdc, rectLast.Right,rectLast.Bottom);
LineTo(hdc, rectLast.Left,rectLast.Bottom);
LineTo(hdc, rectLast.Left,rectLast.Top);
}
MoveToEx(hdc, rect.Left, rect.Top, ptsOld);
LineTo(hdc, rect.Right,rect.Top);
LineTo(hdc, rect.Right,rect.Bottom);
LineTo(hdc, rect.Left,rect.Bottom);
LineTo(hdc, rect.Left,rect.Top);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -