1. 常用结构
1) Point:点坐标
2) Size:大小
3) Rectangle:包括位置与大小
Rectangle.Location:位置坐标
Rectangle.Size:大小
4) Pen:画笔
红色笔:Pens.Red,黑色笔:Pens.Black
其它的一次类推。
5) Brush:画刷
红色画刷:Brushes.Red 黑色画刷:Brushes.Black
其它以此类推。
2. 坐标变换
对象 | 屏幕坐标转化为客户区坐标 | 客户区坐标转化为屏幕坐标 |
Point | PointToClinet(Point pt) | PointToScreen(Point pt) |
Rectangle | RectangleToClient | RectangleToScreen |
涉及坐标的程序必须先考虑是否需要坐标变换
坐标平移:
X目标=X现在+dx
Y目标=Y现在+dy
坐标缩放:
X目标=X现在*dx
Y目标=Y现在*dy
坐标旋转:
X目标=X现在*Cos(α)+Y现在*Sin(α)
Y目标= X现在*Sin(α)+Y现在*Cos(α)
综合后
引入矩阵
综合后的公式可以写为
坐标变换会因为顺序的不同而产生不同的结果,多次坐标变换的结果是多个矩阵相乘。
右下角矩阵说明
X | Y | 隐含列 |
Sx 缩放因子 | Ry旋转因子 | 0 |
Rx旋转因子 | sy缩放因子 | 0 |
Dx平移因子 | Dy平移因子 | 1 |
图-1 原始矩阵
图-2 x轴平移100个像素
图-3 y轴平移100个像素
图-4 x轴放大1.5倍
图-5 y轴放大1.5倍
图-6 x轴旋转0.5
图-7 y轴旋转0.5
3. 鼠标事件
事件名称 | 说明 |
OnMouseUp | 鼠标松开 |
OnMouseDown | 鼠标按下 |
OnMouseMove | 鼠标移动 |
OnMouseEnter | 鼠标进入 |
OnMouseLeave | 鼠标离开 |
OnMouseHover | 鼠标停留。Hover事件至多在Enter与Leave之间发生一次 |
OnMouseCaptureChanged | 鼠标捕获变化,捕获发生一次,释放发生一次 |
4. 常见问题与解决方法
1) 如判断鼠标按下拖动
首先在鼠标的OnMouseMoveMove事件中添加如下判断:
if (e.Button == MouseButtons.Left)
{
//鼠标移动的过程中是否按下了左键
}
2) 如何避免鼠标按住旋转后划线后出现多条痕迹
在OnPaint事件中添加如下代码:
//划线之前先用背景色把原先的痕迹抹掉。
g.Clear(this.BackColor);
3) 鼠标的Capture事件
鼠标的捕获释放只能在一个控件中完成,前一个控件A捕获了鼠标后,不可能由下一个控件B捕获,必须是A释放了之后才能由B控件捕获。
假设在A控件上按住鼠标移动,鼠标移出A放在了B控件上。假设在B控件中的OnMouseHover中添加了代码弹出对话框,这样的对话框不会弹出,因为A捕获了鼠标,在A未释放之前,其他控件不可能激发鼠标相关的事件,除非其他控件捕获它之后,才可能激发它的事件。
附坐标变化程序代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
namespace GDITransformApp
{
public partial class Transform1 : Form
{
public class MyMatrix
{
public float X
{
get ;
set ;
}
public float Y
{
get ;
set ;
}
public MyMatrix( float x, float y)
{
X = x;
Y = y;
}
}
#region Coordanate
// 坐标轴X与控件边缘的距离
private const int xPad = 80 ;
// 坐标轴Y与控件边缘的距离
private const int yPad = 60 ;
/// <summary>
/// X坐标标签间距
/// </summary>
private int coordinateLablePadX = 20 ;
public int CoordinateLablePadX
{
get
{
return coordinateLablePadX;
}
set
{
Invalidate();
coordinateLablePadX = value;
}
}
/// <summary>
/// Y坐标标签间距
/// </summary>
private int coordinateLablePadY = 30 ;
public int CoordinateLablePadY
{
get
{
return coordinateLablePadY;
}
set
{
Invalidate();
coordinateLablePadY = value;
}
}
/// <summary>
/// y坐标轴起点坐标
/// </summary>
public Point YCoordinateStartPoint
{
get
{
return new Point(xPad, this .Height - yPad);
}
}
/// <summary>
/// y坐标轴终点坐标
/// </summary>
public Point YCoordinateEndPoint
{
get
{
return new Point(xPad, yPad);
}
}
/// <summary>
/// x坐标轴起点坐标
/// </summary>
public Point XCoordinateStartPoint
{
get
{
return YCoordinateStartPoint;
}
}
/// <summary>
/// x坐标轴终点坐标
/// </summary>
public Point XCoordinateEndPoint
{
get
{
Point current = new Point();
current.X = Width - xPad;
current.Y = Height - yPad;
return current;
}
}
private void DrawCoordinate(PaintEventArgs e)
{
Pen currentPen = new Pen(Color.Black);
currentPen.EndCap = LineCap.ArrowAnchor;
// 绘制Y轴
e.Graphics.DrawLine(
currentPen,
YCoordinateStartPoint,
YCoordinateEndPoint
);
// 绘制Y轴
e.Graphics.DrawLine(
currentPen,
XCoordinateStartPoint,
XCoordinateEndPoint
);
currentPen.Dispose();
// 绘制X,Y 标签
DrawCoordinateLabel(e.Graphics, YCoordinateStartPoint, YCoordinateEndPoint, XCoordinateStartPoint, XCoordinateEndPoint);
}
/// <summary>
/// 绘制坐标标记
/// </summary>
private void DrawCoordinateLabel(Graphics gp, Point startYPoint, Point endYPoint, Point startXPoint, Point endXPoint)
{
// int y = YCoordinateStartPoint .Y - YCoordinateEndPoint.Y;
int currentValue = - 1 ;
float labelX = 0 , labelY = 0 ;
int pad = 5 ;
// 绘制Y轴
for ( int current = YCoordinateStartPoint.Y; current > YCoordinateEndPoint.Y; current -= CoordinateLablePadY)
{
currentValue ++ ;
SizeF textSize = gp.MeasureString(currentValue.ToString(), Font);
labelX = YCoordinateStartPoint.X - xPad / 2 ;
labelY = current - textSize.Height / 2 ;
// 绘制label
gp.DrawString(currentValue.ToString(), Font, Brushes.Black,
new PointF(labelX, labelY)
);
// 绘制|-
gp.DrawLine(Pens.Black, new Point(YCoordinateStartPoint.X, current), new Point(YCoordinateStartPoint.X + pad, current));
}
currentValue = - 1 ;
// 绘制X轴
for ( int current = XCoordinateStartPoint.X; current < XCoordinateEndPoint.X; current += CoordinateLablePadX)
{
currentValue ++ ;
SizeF textSize = gp.MeasureString(currentValue.ToString(), Font);
labelY = XCoordinateStartPoint.Y + yPad / 2 ;
labelX = current;
// 绘制label
gp.DrawString(currentValue.ToString(), Font, Brushes.Black,
new PointF(labelX, labelY)
);
// 绘制_|_
gp.DrawLine(Pens.Black,
new Point(current, XCoordinateStartPoint.Y),
new Point(current, XCoordinateStartPoint.Y - pad)
);
}
}
#endregion
float angle = 0f;
float scaleX = 1f;
float scaleY = 1f;
float translateX = 1f;
float translateY = 1f;
public Transform1()
{
InitializeComponent();
}
Matrix matrix = new Matrix();
List < MyMatrix > myList = new List < MyMatrix > ();
protected override void OnPaint(PaintEventArgs e)
{
base .OnPaint(e);
e.Graphics.Clear( this .BackColor);
DrawCoordinate(e);
DrawRectangle();
}
private void DrawRectangle()
{
using (Graphics gh = CreateGraphics())
{
Rectangle rect = new Rectangle( 100 , 100 , 200 , 200 );
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center ;
sf.LineAlignment = StringAlignment .Center ;
// 平移
gh.TranslateTransform(translateX, translateY);
// 旋转
gh.RotateTransform(angle);
// 缩放
gh.ScaleTransform(scaleX, scaleY);
// 设置gh的变换矩阵
gh.Transform = matrix;
gh.DrawRectangle(Pens.Red, rect);
gh.DrawString( " AAAAAAAAA " , this .Font, Brushes.Blue, rect, sf);
matrix = gh.Transform;
myList.Add( new MyMatrix(matrix.Elements[ 0 ], matrix.Elements[ 1 ]));
myList.Add( new MyMatrix(matrix.Elements[ 2 ], matrix.Elements[ 3 ]));
myList.Add( new MyMatrix(matrix.Elements[ 4 ], matrix.Elements[ 5 ]));
this .dgvMatrix.DataSource = myList;
}
}
private void button1_Click( object sender, EventArgs e)
{
angle += 10 ;
this .Invalidate();
}
private void btnScaleAdd_Click( object sender, EventArgs e)
{
scaleX += 1 ;
scaleY += 1 ;
this .Invalidate();
}
private void btnScaleSub_Click( object sender, EventArgs e)
{
scaleX -= 1 ;
scaleY -= 1 ;
this .Invalidate();
}
private void btnRolateSub_Click( object sender, EventArgs e)
{
angle -= 10 ;
this .Invalidate();
}
private void btnBack_Click( object sender, EventArgs e)
{
angle = 0f;
scaleX = 1f;
scaleY = 1f;
translateX = 0f;
translateY = 0f;
this .Invalidate();
}
private void btnTranslateAdd_Click( object sender, EventArgs e)
{
translateX += 3f;
translateY += 3f;
this .Invalidate();
}
private void btnTranslateSub_Click( object sender, EventArgs e)
{
translateX -= 5f;
translateY -= 5f;
this .Invalidate();
}
private void btnMatrixBack_Click( object sender, EventArgs e)
{
matrix = new Matrix
(
1 , 0 ,
0 , 1 ,
0 , 0
);
this .Invalidate();
}
private void button1_Click_1( object sender, EventArgs e)
{
matrix = new Matrix(
((MyMatrix) this .dgvMatrix.Rows[ 0 ].DataBoundItem).X, ((MyMatrix) this .dgvMatrix.Rows[ 0 ].DataBoundItem).Y ,
((MyMatrix) this .dgvMatrix.Rows[ 1 ].DataBoundItem).X, ((MyMatrix) this .dgvMatrix.Rows[ 1 ].DataBoundItem).Y ,
((MyMatrix) this .dgvMatrix.Rows[ 2 ].DataBoundItem).X, ((MyMatrix) this .dgvMatrix.Rows[ 2 ].DataBoundItem).Y
);
this .Invalidate();
}
}
}