先看效果图
最近在做一个组态的项目,里面涉及到在
设计模式
时容器里加个标尺及游标,标尺很容易画,在容器里重绘即可,但游标把我彻底搞晕了!在网上搜索了很多,都没找到好的方法.
1.我实验了全局鼠标钩子,应用程序鼠标钩子,有人或许疑惑直接使用MouseMove不就行了吗?其实你忘了我说的是在组态方式的
设计模式
里,鼠标移动事件控件是无法响应的,而且会被控件捕获!用全局鼠标钩子后,关闭文档最大化最小化会严重滞后,使用应用程序钩子会出现游标颤动并严重影响鼠标移动.
2.使用ControlPaint绘制可擦除的线,可当鼠标拖动控件或缩放控件时,绘制出来的游标线会多一条直接就混乱了!
3.最终实现仅供参考!
程序中定义一个消息筛选器
/// <summary>
/// 截获鼠标移动消息
/// </summary>
public class GlobalMouseHandler : IMessageFilter
{
private const int WM_MOUSEMOVE = 0x0200;
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_MOUSEMOVE)
{
//这个程序是从我程序里截取出来的,可能需要屏幕坐标和控件坐标的转换,请调试跟踪一下坐标,自行调整
Control control = System.Windows.Forms.Form.FromHandle(m.HWnd) as Control;
if (control != null) e = control.PointToScreen(new Point(m.LParam.ToInt32() & 0xFFff, m.LParam.ToInt32() >> 16));
你标尺所在的窗口.HookManager_MouseMove(e );
}
return false;
}
}
在主窗口Load事件中加入:
过滤鼠标信息
GlobalMouseHandler globalClick = new GlobalMouseHandler();
Application.AddMessageFilter(globalClick);
接下来实现HookManager_MouseMove
public void HookManager_MouseMove(Point e)
{
Monitor.Enter(this);
//说明一下,这个程序是从我程序里截取出来的,可能需要坐标的转换,屏幕坐标和控件坐标的转换,可以在消息过滤器里面进行转换
//画游标
Point sp = this.PointToClient(e);
//top = sp.Y + this.toolStripContainer1.Height + 25;
Point[] p = new Point[4];
Pen pen = new Pen(Color.Red);
Rectangle r = new Rectangle(30, 30, this.Width – 30, this.Height – 30);
if (r.Contains(sp))
{
Graphics g = this.CreateGraphics();
p[0] = new Point(sp.X, 0);
p[1] = new Point(sp.X, 20);
p[2] = new Point(0, sp.Y);
p[3] = new Point(20, sp.Y);
this.Invalidate(new Rectangle(0, 0, this.Width, 21), true);//这是X轴标尺的区域重绘
this.Invalidate(new Rectangle(0, 0, 21, this.Height), true);//这是Y轴标尺的区域重绘
Application.DoEvents();//这条必须加,否则新绘制的也被重绘掉
g.DrawLine(pen, p[0], p[1]);
g.DrawLine(pen, p[2], p[3]);
}
else
{
this.Invalidate(new Rectangle(0, 0, this.Width, 21), true);
this.Invalidate(new Rectangle(0, 0, 21, this.Height), true);
Application.DoEvents();
}
Monitor.Exit(this);
}
重绘事件,主要是绘制标尺
//重绘事件–绘制标尺
private void 你需要绘制的窗口_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
//g.FillRectangle(new SolidBrush(Color.Black), new Rectangle(0, 0, this.Width, this.Height));
Rectangle[] bc = { new Rectangle(0, 0, this.Width, 20), new Rectangle(0, 0, 20, this.Height) };
g.FillRectangles(new SolidBrush(Color.WhiteSmoke), bc);
//从40像素开始画
int ks = 40;
//X轴画刻度
for (int i = 0; i < this.Width – ks; i++)
{
if (i % 10 == 0)
{
if (i == 0 || i % 100 == 0)
{
//画大刻度
g.DrawLine(new Pen(Color.DarkGray), i + ks, 0, i + ks, 20);
//文字
g.DrawString(i.ToString(), new Font(“宋体”, 8f), new SolidBrush(Color.Black), new PointF(i + ks + 2, -1));
}
else
{
//画小刻度
g.DrawLine(new Pen(Color.DarkGray), i + ks, 10, i + ks, 20);
}
}
}
//Y轴画刻度
for (int i = 0; i < this.Height – ks; i++)
{
if (i % 10 == 0)
{
if (i == 0 || i % 100 == 0)
{
//画大刻度
g.DrawLine(new Pen(Color.DarkGray), 0, i + ks, 20, i + ks);
//文字
StringFormat sf = new StringFormat();
//sf.Alignment = StringAlignment.Center;
sf.FormatFlags = StringFormatFlags.DirectionVertical;
//StringFormat strF = new StringFormat(StringFormatFlags.DirectionVertical);
//e.Graphics.TranslateTransform(0.0F, 0.0F);
//e.Graphics.RotateTransform(180.0F);
g.DrawString(i.ToString(), new Font(“宋体”, 8f), new SolidBrush(Color.Black), new PointF(-2, i + ks + 1), sf);
}
else
{
//画小刻度
g.DrawLine(new Pen(Color.DarkGray), 10, i + ks, 20, i + ks);
}
}
}
//画面ID
int id = IDEBase.Project.GetFrameID(Path.GetFileName(_xmlFile));
g.DrawString(“ID:” + id.ToString(), new Font(“宋体”, 10, FontStyle.Bold), new SolidBrush(Color.Black), ks, 25);
}
这样绘制出来的效果即不影响鼠标移动的速度,也不会出现拖动控件时产生的双游标,还不会影响关闭最大最小化窗口的速度,如果想继续完善,可以去想办法捕获拖动和缩放控件时的鼠标移动!