标尺及游标的实现

  • Post author:
  • Post category:其他


先看效果图

最近在做一个组态的项目,里面涉及到在

设计模式

时容器里加个标尺及游标,标尺很容易画,在容器里重绘即可,但游标把我彻底搞晕了!在网上搜索了很多,都没找到好的方法.

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);

}

这样绘制出来的效果即不影响鼠标移动的速度,也不会出现拖动控件时产生的双游标,还不会影响关闭最大最小化窗口的速度,如果想继续完善,可以去想办法捕获拖动和缩放控件时的鼠标移动!



版权声明:本文为cfyouling原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。