鼠标光标在选定的文本上闪烁 - 如何防止这种情况?

时间:2014-03-06 19:13:39

标签: c# .net winforms richtextbox

我在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是不必要的?]

4 个答案:

答案 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方法来处理它们不处理的任何消息。

您正在重写此函数,实际上成为“继承者”,然后选择“处理”请求光标更改的消息。但是,不是处理此消息,而是忽略它。