我在RichTextBox(C#,.NET 4.0,WinForms)中将鼠标移动到所选文本上时遇到奇怪的行为:当我移动鼠标光标时,它在Cursors.Arrow和Cursors.IBeam之间闪烁。
我找到了禁用闪烁的代码:
protected override void WndProc(ref System.Windows.Forms.Message m)
{
if (m.Msg == WM_SETCURSOR) //WM_SETCURSOR is set to 0x20
return;
}
然后鼠标光标卡在Cursors.Arrow上,即使我手动将其设置为其他东西,例如:
void RTFBox_MouseMove(object sender, MouseEventArgs e)
{
Cursor = Cursors.IBeam;
}
(我在MouseMove函数中也有逻辑将Cursor
设置为其他类型的非Arrow
游标,具体取决于鼠标的结束。)
我也尝试过:
public override Cursor Cursor
{
get
{
//(I have other logic here to determine the desired cursor type I want; in all cases it was a non-Arrow cursor)
return Cursors.Cross; //'Cross' instead of 'IBeam' just to prove whether this works
}
set
{
return;
}
}
成功地使光标成为十字架(但只有当我注释掉WndProc
代码时),但当我鼠标悬停在所选文本上时(鼠标光标在箭头和十字架之间切换),闪烁仍然存在。
在尝试寻找解决方案时,我遇到了this post,但是却打电话给了
SendMessage(Handle, LVM_SETHOTCURSOR, IntPtr.Zero, Cursors.IBeam.Handle);
从继承自RichTextBox的类中,没有修复闪烁问题。
我的问题似乎与this post中描述的问题相同,但问题被描述为存在于.NET 3.0上并在.NET 3.5中修复。
当我创建一个新项目并在表单中插入RichTextBox时,闪烁仍然存在。
因此,我的问题是:如何防止这种闪烁?或者有人知道在.NET / visual studio的更高版本中是否解决了这个问题吗?
[更新:我下载了Visual Studio 2013,但“闪烁”效果仍然存在。我下载了.Net 4.5.1安装程序并告诉它修复,但“闪烁”仍然存在。在“属性”下> “引用”,它说“System.Windows.Forms”是版本4.0.0.0;我想这意味着更新过去4.0是不必要的?]
答案 0 :(得分:2)
我在Chess123mate的答案中添加了答案,以使其在垂直滚动条上显示箭头光标:
[DllImport("user32.dll")]
public static extern int SetCursor(IntPtr cursor);
private const int WM_SETCURSOR = 0x20;
protected override void WndProc(ref System.Windows.Forms.Message m)
{
if (m.Msg == WM_SETCURSOR)
{
var scrollbarWidth = System.Windows.Forms.SystemInformation.VerticalScrollBarWidth;
var x = PointToClient(Control.MousePosition).X;
var inScrollbar = x > this.Width - scrollbarWidth;
var cursor = inScrollbar ? Cursors.Arrow : Cursors.IBeam;
SetCursor(cursor.Handle);
m.Result = new IntPtr(1); //Signify that we dealt with the message. We should be returning "true", but I can't figure out how to do that.
return;
}
base.WndProc(ref m);
}
答案 1 :(得分:1)
闪烁主要是因为图形对象或表面重绘。如果您将代码放入一个持续更新自身的控件事件(f.i.MouseMove),并且代码修改器以某种方式表面或其内容,则会发生闪烁。 我曾经使用DoubleBuffering来修复闪烁问题。只需将此代码添加到表单的构造函数中(在InitializeComponent()方法的上方或下方):
DoubleBuffered = true;
如果这不能解决问题,那么问题可能不是因为图形问题。
当两个事件代码想要同时更改光标时,光标也会闪烁。 它也可能是您的代码或默认代码(f.i.当您将光标移动到控件上方时,会自动显示IBeam)。 检查代码,它是否包含在使用过程中修改光标或所选文本的代码。然后每次将光标从其他事件更改为所需的类型。我的意思是:
//MouseMove is the best choice in this case
private void RichTextBox1_MouseMove(object sender, MouseEventArgs e)
{
Cursor = Cursors.Arrow;
}
但我使用.Net 4.0,我没有任何问题。我认为它已在最新版本中修复。
希望它有所帮助。 :)
答案 2 :(得分:1)
WndProc的WM_SETCURSOR文档可在此处找到:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms648382(v=vs.85).aspx
您可以使用此代码手动将光标设置为特定类型:
[DllImport("user32.dll")]
public static extern int SetCursor(IntPtr cursor);
private const int WM_SETCURSOR = 0x20;
protected override void WndProc(ref System.Windows.Forms.Message m)
{
if (m.Msg == WM_SETCURSOR)
{
SetCursor(Cursors.IBeam.Handle);
m.Result = new IntPtr(1); //Signify that we dealt with the message. We should be returning "true", but I can't figure out how to do that.
return;
}
base.WndProc(ref m);
}
但是,每次调用SetCursor时,此代码都会导致text-caret闪烁(每次在控件中移动鼠标时都会发生这种情况。)
答案 3 :(得分:0)
这一切都来自于使用您在互联网上找到的代码,即使您不知道它的作用。
我无法真正谈论闪烁的问题......这听起来像是你需要与供应商讨论的事情。
至于为什么你的代码“修复”了这个问题,但是不允许你更改光标,你需要了解windows消息泵是如何工作的。
基本上,在较低级别,您正在拦截更改光标然后阻止它们的请求。如果你看the documentation这个函数,你会看到这个评论:
对继承者的说明
继承控件应该调用基类的WndProc方法来处理它们不处理的任何消息。
您正在重写此函数,实际上成为“继承者”,然后选择“处理”请求光标更改的消息。但是,不是处理此消息,而是忽略它。