cristianbuse / VBA-UserForm-MouseScroll

Use the Mouse Scroll Wheel to scroll VBA UserForms and Controls
MIT License
70 stars 12 forks source link

Shift-scroll failed for WordWrap:=False textboxes #2

Closed billyswong closed 4 years ago

billyswong commented 4 years ago

How to reproduce: In demo file, change the TextBox1 to WordWrap:=False in design mode. Vertical scroll will still work but shift-scroll-as-horizontal to that text box will fail.

Environment: Office 365 32-bit Version 2004

cristianbuse commented 4 years ago

Hi billyswong,

The horizontal scroll for a textbox was never implemented. You can quickly see that in the 'ScrollX' method there is no case for a 'TextBox' like control. The vertical scroll is possible by manipulating the TextBox.CurLine property but there is no equivalent property to do that horizontally. The only way I was able to scroll the TextBox horizontally was to move the cursor but that has 2 serious drawbacks: 1) The action itself to reposition the cursor is something that affects your current selection and many other properties which is undesirable 2) If the current line has only 2 characters but the line with the most characters has 100 you can only move the cursor for 2 characters or try to always find the largest line and make that the current line before moving the cursor

Moving the cursor is definitely possible but as mentioned above is worse than not having the horizontal scroll.

Finally, if you know a way to move the textbox's horizontal scrollbar through code without moving the cursor then please let me know and I will implement it. I might have overlooked something.

I will leave the issue opened until your reply or until a couple of weeks pass by.

All the best, Cristian Buse

billyswong commented 4 years ago

If we really can't use .CurTargetX and .CurX to provide horizontal scroll...

I am not so sure if moving the cursor is really that bad, since .CurLine seems to be also cursor-moving, and the code is backing-up the .SelStart and .SelLength and restoring it after .CurLine operation. I think it is okay to only lookup the lines in visible region and ignore the 100 chars line you mention if it is "out of scroll". In such case maybe the "find the largest line" operation will be lighter? Or we may cache which line is longest after the mouse-scroll library traverse the textbox and measure .CurX to find it out. Then until the cache is invalidated (perhaps by textbox_update), the scrolling code don't need to check it again.


Another crazy way is: Step 1: Screen capture to "look" if the textbox has a horizontal scrollbar http://msexcelmania.weebly.com/blog/vba-screen-capture-routines-macro Step 2: Move the mouse pointer to "click" the scrollbar https://wellsr.com/vba/2015/excel/vba-mouse-move-and-mouse-click-macro/

cristianbuse commented 4 years ago

You are correct in that .CurLine is moving the cursor. I was speaking from memory and I forgot. Sorry about that. Thanks for looking into it. The selection is restored after .CurLine is set as you said. CurLine actually ruins the horizontal scroll if WordWrap is False because it places the cursor at the start of the line. This is another reason why I avoided the horizontal scroll.

We could use .CurX but it is a bit more tricky. If the new value exceeds the maximum .CurX available in the active line then the cursor actually moves on the previous line thus interfering with the vertical scroll.

Again, you are correct by limiting the horizontal scroll to the visible region. Even if we could find a large enough line to set the horizontal scroll that would be ruined by the vertical scroll (jumps at the beginning of the line). So .CurX can be used for scrolling horizontally but only up to the visible region's longest line. Caching would not be needed in this scenario as the longest line could be outside of the visible region.

The "crazy" ways you've mentioned (screen capture and moving the mouse) are interesting but I believe to be overkill.

When I've decided to create this project, I also spend quite a lot of hours trying to scroll a TextBox by embedding it into a Frame. The Text box was set to AutoSize to full extent and the frame would basically have the size and position that the text box initially had and both ScrollBars on. The results were quite good but I was not able to fully synchronize the frame scrollbars mainly due to the fact that the textbox does not have a SelectionChange event (and the user can hold the left click and drag the mouse to change selection and scroll - or using the arrow keys). Maybe it's achievable by doing logic for both key presses (Arrow Keys) and MouseDown+MouseMove events but I think it could be quite complicated.

I won't have time to work on this for a couple of weeks but I will get back to you after I have another thorough look and investigate again both the .CurX approach and the Frame embedding.

In the meanwhile, if you are interested to collaborate please do a Pull Request. If not, suggestions like the above are always welcome.

cristianbuse commented 4 years ago

Unfortunately, I had no time to look into this in the last few months and probably won't have time this year. I will close this issue as it's more like a feature request. However, I will keep it on my to-do list.