Cursor problem (Windows)


I am currently writing a simple text editor (for practicing purposes) which includes keyword highlighting. As always the MacOS version runs my highlighting methods as smoothly as expected, but the Windows version caused me some trouble.

At first I had a lot of “jumping” and flickering of my TextArea (a subclass of Xojo’s TextArea class) while editing if keyword highlighting was enabled. Then I modified the subclass with the declares I found in this forum, which (almost) stopped the flickering of my TextArea but caused a lot of flickering of the app icon in the task bar. After modifying the declare methods so that they stop/restart redrawing of just the TextArea instead of the whole window, the flickering went away.
The code now looks like this (triggered in the TextChanged event of my TextArea):

[code]If Highlight.CurrentFile <> Nil And Not IsPlain Then
#If TargetWindows
Dim pos As Integer = Me.ScrollPosition

// calling some highlighting methods

#If TargetWindows
Me.ScrollPosition = pos
End If[/code]

But there is one problem left: Usually if you type, the mouse cursor disappears while typing and reappears, if you move the mouse. But (due to the declares, as it seems) the mouse cursor remains to be seen while typing, which wouldn’t be so annoying, if it wouldn’t flicker like the rest of the window did before.
I tried the following workarounds:

  1. I called “System.Cursors.Hide” at the end of the above method after invalidating the TextArea; the cursor disappeared, but it didn’t reappear again.
  2. Adding a call of “System.Cursors.Show” in the MouseMove event of the TextArea made the cursor visible (and flicker) all the time again (although I didn’t move the mouse).
  3. Finally I saved the MouseX and MouseY coordinates to properties when starting my highlighting method and added an if clause to the MouseMove event to show the cursor only if the x and y coordinates differed from the properties (i. e. if the mouse was actually moved). Still the cursor remained all the time although the mouse wasn’t moved.

Could you think of any other way to make the cursor temporarilly unseen? (I cannot think of any way to stop the cursor from flickering, which would be sufficient …)

Could you not use System.Cursors.Hide at the end of the method like you tried and then use System.Cursors.Show when the mouse moves or when the mouse leaves the control.

I cannot remember off the top of my head but you might have to make sure you call the hide & show methods an equal number of times for things to work correctly.

I already tried that, but without any success.

What exactly didn’t work?

If you could post a simple version of the code showing the problem that would help a lot.

There is nothing more to show than the above code that is processed in the TextArea’s TextChanged event. The highlighting methods I commented out have nothing to do with the problem because the problem remains even if I comment out the method calls in the actual code.

I added the line “System.Cursors.Hide” after “Me.Invalidate(False)”, which caused the cursor to disappear after pressing a key and not to reappear. Then I added the line “System.Cursors.Show” in the TextArea’s MouseMove event, which lead to the cursor being visible all the time again.

I think that something about the declare methods causes the cursor to reappear again after having disappeared as it should. And this short period of disappearing and reappearing is visible as flickering.

I used this version of the declare methods:

[code]Private Function SendMessage(hwnd as Integer, msg as Integer, wParam as Integer, lParam as Integer) as Integer
#If TargetWindows
Soft Declare Function SendMessageA Lib “User32” (hwnd as Integer, msg as Integer, wParam as Integer, lParam as Integer) as Integer
Soft Declare Function SendMessageW Lib “User32” (hwnd as Integer, msg as Integer, wParam as Integer, lParam as Integer) as Integer

If System.IsFunctionAvailable("SendMessageW", "User32") then
  return SendMessageW(hwnd, msg, wParam, lParam)
  return SendMessageA(hwnd, msg, wParam, lParam)
end if

#Pragma unused hwnd
#Pragma unused msg
#Pragma unused wParam
#Pragma unused lParam
End Function

Public Sub Freeze(extends w as TextArea) Const WM_SETREDRAW = &hB Call SendMessage(w.Handle, WM_SETREDRAW, 0, 0) End Sub

Public Sub UnFreeze(extends w as TextArea) Const WM_SETREDRAW = &hB Call SendMessage(w.Handle, WM_SETREDRAW, 1, 0) End Sub

This would have been done quicker if you had made a little demo to start with, saving me from having to make a demo then work on it as code very rarely just cuts and pastes into an empty project and just works :stuck_out_tongue: :slight_smile: Demos rule!

Something to note. There is a counter behind the scenes when Showing/Hiding a cursor, you have to call it the same number of times in the other direction to get it back, so if you call hide 10 times, and call show 1 time, it wont show so the easiest way is to keep a state then you only can call it once in each direction (show/hide).

I also found 4-5 bugs while working on this. Where required, they have all been worked around in the code and the way its been implemented. Off to feedback I go…

PS. Tested on Win10, two monitors, one 100% and the other 200% scaling, everything seems fine but someone might find an issue with it :slight_smile:

Thank you for your help and work, I appreciate that very much!

A demo project would have been difficult because there are some classes and subclasses involved. Next time I try to work even more modularly (one purpose I already tried to follow on this project, but there is still much room for improvement as it happens with autodidacts), so that I can extract certain functions more easily.

Since it is already rather late here I will have a closer look at your code tomorrow morning and let you know how it works with my project. Those declares are uncharted territory for me (the more so as I work with Windows very rarely) …

Thank you very much again! :slight_smile:

I just tested your code and it works very well in my project, thanks again!

I think it is kind of sad that so much declare effort is necessary just to avoid showing the cursor over the title bar (otherwise they would not be needed at all).
The main problem turned out to be the multiple calling of “System.Cursors.Hide” indeed. “Wieder etwas gelernt” as we say in Germany. :slight_smile: