Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mouse cursor flickers over selected text - how to prevent this?

I'm encountering strange behaviour while moving the mouse over selected text in a RichTextBox (C#, .NET 4.0, WinForms): as I move the mouse cursor, it flickers between Cursors.Arrow and Cursors.IBeam.

I found code that disables the flickering:

protected override void WndProc(ref System.Windows.Forms.Message m)  
{  
     if (m.Msg == WM_SETCURSOR) //WM_SETCURSOR is set to 0x20
          return;
}

but then the mouse cursor is stuck as Cursors.Arrow, even when I manually set it to something else, ex:

void RTFBox_MouseMove(object sender, MouseEventArgs e)
{
    Cursor = Cursors.IBeam;
}

(I also had logic in the MouseMove function to set Cursor to other types of non-Arrow cursors, depending on what the mouse was over.)

I also tried:

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

which successfully made the cursor a cross (but only when I commented out the WndProc code), but the flickering remained when I moused over selected text (with the mouse cursor changing between Arrow and Cross).

In trying to find a solution, I came across this post, but calling
SendMessage(Handle, LVM_SETHOTCURSOR, IntPtr.Zero, Cursors.IBeam.Handle);
from a class inheriting from RichTextBox did not fix the flickering problem.

My problem seems identical to the one desribed in this post, but the problem was described to exist on .NET 3.0 and fixed in .NET 3.5.

When I created a new project and inserted a RichTextBox into the form, the flickering is still there.

Thus, my question is: How do I prevent this flickering? Or does anyone know if this problem is resolved in later versions of .NET/visual studio?

[Update: I downloaded Visual Studio 2013, but the "flicker" effect is still present. I downloaded .Net 4.5.1 installer and told it to repair, but the "flickering" remained. Under "Properties" > "References", it says that "System.Windows.Forms" is version 4.0.0.0; I suppose this means that updating past 4.0 was unnecessary?]

like image 625
chess123mate Avatar asked Mar 06 '14 19:03

chess123mate


4 Answers

Flickering is mostly because of Graphics objects or surface redrawing. If you put codes to an event of a control that continuosly updates itself (f.i. MouseMove), and the code modificates somehow the surface or the contents of it, flickering occurs. I used to use DoubleBuffering to fix flickering problems. Just add this code to your form's constructor (above or below the InitializeComponent() method):

DoubleBuffered = true;

If this doesn't fix the problem, the issue is probably not because of a graphical trouble.

Cursor could also flicker when two events codes want to change the cursor at the same time. It could be your code or a default code as well (f.i. the IBeam automatically appears when you move cursor above the Control). Check your code, whether it contains codes that modify the Cursor or the selected text during you use it. Then change the cursor from a nother event every time to the type you want. I mean:

//MouseMove is the best choice in this case
private void RichTextBox1_MouseMove(object sender, MouseEventArgs e)
{
    Cursor = Cursors.Arrow;
}

But I use .Net 4.0, and I don't have any problems with it. I think it has been fixed in the latest version.

Hope it helps a bit. :)

like image 97
Richtenzorg Avatar answered Sep 28 '22 07:09

Richtenzorg


The documentation for WndProc's WM_SETCURSOR is found here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms648382(v=vs.85).aspx
You can use this code to manually set the cursor to a specific type:

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

However, this code results in the text-caret flickering every time SetCursor is called (which happens every time the mouse is moved in the control).

like image 32
chess123mate Avatar answered Sep 28 '22 07:09

chess123mate


I added onto chess123mate's answer to get it to show the arrow cursor over the vertical scrollbar:

[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);
}
like image 44
user875234 Avatar answered Sep 28 '22 09:09

user875234


I can't really speak to the flickering issue... it sounds like something that you need to speak with the vendor about.

As to why your code "fixed" the issue, but doesn't let you change the cursor, it helps to understand more about how the windows message pump works.

Basically, at a low level, you are intercepting requests to change the cursor and then blocking them. If you look at the documentation for this function, you'll see this comment:

Notes to Inheritors
Inheriting controls should call the base class's WndProc method to process any messages that they do not handle.

You are overriding this function, essentially becoming an "inheritor", and then "handling" messages requesting the cursor to change by ignoring it.

like image 37
JDB Avatar answered Sep 28 '22 09:09

JDB