Mike Torrettinni 198 Posted April 27, 2020 (edited) I'm looking at this simple example to scroll 2 Scroll boxes at the same time: hhttps://stackoverflow.com/a/17788516/5198394 If I click just 1x on scrollbar button to scroll down on Scrollbox1 , why is message WM_VSCROLL 'executed' twice? If I debug the method: procedure TScrollBox.WMVScroll(var Message: TWMVScroll); begin inherited; if Assigned(FOnScrollVert) then FOnScrollVert(Self); end; the Self is Scrollbox1 in both calls: Each Scrollbox has 2 oversized panels so that scrollbars are visible from the start: Any ideas why is VMVScroll method called twice? How to prevent it? Shouldn't 1 click on scrollbar button send 1 WM_VSCROLL or WM_HSCROLL message? Edited April 27, 2020 by Mike Torrettinni fixed link Share this post Link to post
Mike Torrettinni 198 Posted April 27, 2020 I can make it not execute MyScrollVert twice, with a check if VertScrollBar.Position has changed after inherited: procedure TScrollBox.WMVScroll(var Message: TWMVScroll); begin fScrollPrevPos := Self.VertScrollBar.Position; inherited; if fScrollPrevPos <> Self.VertScrollBar.Position then if Assigned(FOnScrollVert) then FOnScrollVert(Self); end; but this is just a fix on something I don't know how to prevent in first place. Share this post Link to post
eivindbakkestuen 47 Posted April 29, 2020 Have you looked at the Message parameter values to see what you're actually getting? Share this post Link to post
Mike Torrettinni 198 Posted April 29, 2020 Yes, I guess this is how scroll messaging works, when pressing on scroll button: 1. Scroll line down (button pressed) 2. End scroll (button released) Which is probably fine for most applications, but I synchronize 3 or 4 scroll boxes at the same time and it was executing custom scroll 2x. So, annoying for anything that is customized, but I guess it is the right way. So, now I have: procedure TScrollBox.WMVScroll(var Message: TWMVScroll); begin inherited; if Message.ScrollCode <> SB_ENDSCROLL then if Assigned(FOnScrollVert) then FOnScrollVert(Self); end; Until better solution comes along 🙂 Share this post Link to post
David Heffernan 2353 Posted April 29, 2020 Do you observe incorrect behaviour of your program? Share this post Link to post
David Heffernan 2353 Posted April 29, 2020 8 hours ago, Mike Torrettinni said: Yes, I guess this is how scroll messaging works, when pressing on scroll button: 1. Scroll line down (button pressed) 2. End scroll (button released) Which is probably fine for most applications, but I synchronize 3 or 4 scroll boxes at the same time and it was executing custom scroll 2x. So, annoying for anything that is customized, but I guess it is the right way. So, now I have: procedure TScrollBox.WMVScroll(var Message: TWMVScroll); begin inherited; if Message.ScrollCode <> SB_ENDSCROLL then if Assigned(FOnScrollVert) then FOnScrollVert(Self); end; Until better solution comes along 🙂 This looks badly wrong to me. What problem are you trying to fix? Share this post Link to post
Mike Torrettinni 198 Posted April 29, 2020 The problem is that method assigned to FOnScrollVert is called 2x. So, the code in the method had to be wrapped with IF's that determine if scroll has occurred - to limit the flicker. The method was originally not designed to be executed 2x for 1 scrolled line. Share this post Link to post
Attila Kovacs 631 Posted April 29, 2020 There is a reason for the two calls. See msg.ScrollCode and https://docs.microsoft.com/en-us/windows/win32/controls/wm-vscroll Try this. TScrollBox = class(Vcl.Forms.TScrollBox) procedure WMVScroll(var msg: TWMVScroll); message WM_VSCROLL; end; procedure TForm1.ScrollBoxMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); procedure SetPos(ScrollBox: TScrollBox); var NewPos: Integer; begin NewPos := ScrollBox.VertScrollBar.Position - WheelDelta div 5; // sensitivity NewPos := Max(NewPos, 0); NewPos := Min(NewPos, ScrollBox.VertScrollBar.Range); ScrollBox.VertScrollBar.Position := NewPos; end; begin SetPos(ScrollBox1); SetPos(ScrollBox2); Handled := True; end; var InScroll: Boolean; procedure TScrollBox.WMVScroll(var msg: TWMVScroll); begin inherited; if not InScroll then begin InScroll := True; try if Self = Form1.ScrollBox1 then Form1.ScrollBox2.Dispatch(msg) else Form1.ScrollBox1.Dispatch(msg); finally InScroll := False; end; end; end; Share this post Link to post
Mike Torrettinni 198 Posted April 29, 2020 Thanks @Attila Kovacs, but your example doesn't prevent executing 2x the line: Form8.ScrollBox2.Dispatch(msg) Share this post Link to post
Attila Kovacs 631 Posted April 29, 2020 That was never my intention to suppress standard windows messages. I answered the question: "I'm looking at this simple example to scroll 2 Scroll boxes at the same time." Does it scroll 2 scrollboxes the same time? (Vertically, I did not implement the horizontal scroll message) Share this post Link to post
Attila Kovacs 631 Posted April 29, 2020 (edited) If you were looking for "How to implement OnScroll events" you can trigger it on SB_ENDSCROLL and not on NOT SB_ENDSCROLL. But in this case your question was misleading and wasting our time. Edited April 29, 2020 by Attila Kovacs Share this post Link to post
Mike Torrettinni 198 Posted April 29, 2020 3 minutes ago, Attila Kovacs said: If you were looking for "How to implement OnScroll events" you can trigger it on SB_ENDSCROLL and not on NOT SB_ENDSCROLL. But in this case your question was misleading and wasting our time. Sorry, thank you trying. Share this post Link to post
Mike Torrettinni 198 Posted April 29, 2020 17 minutes ago, Attila Kovacs said: you can trigger it on SB_ENDSCROLL and not on NOT SB_ENDSCROLL. Yes, I think you missed my final solution where I use it. Share this post Link to post
David Heffernan 2353 Posted April 29, 2020 It's quite possible to solve your problem, but what you are proposing is not the solution. Solve your problem by responding to the underlying messages. If you have issues with flicker, they can doubtless be solved. Share this post Link to post
Mike Torrettinni 198 Posted April 29, 2020 Yes, I solved it by checking if scroll has actually occurred and not assuming that if FOnScrollVert is executed it automatically means the scrollbar has moved. Not a problem, just annoying that OnScroll is execute also when no-scroll 🙂 Share this post Link to post
Attila Kovacs 631 Posted April 29, 2020 (edited) No I didn't miss it, and if it works for you then fine. Just fyi, if you drag the thumb, there will be messages coming (more than 2) and if you release the mouse button SB_ENDSCROLL fires. So depending on what you need, "OnScrolling" (Message.ScrollCode <> SB_ENDSCROLL) or "OnScroll" (Message.ScrollCode = SB_ENDSCROLL) you can call your event if assigned. May I ask what do you have in those events? Edited April 29, 2020 by Attila Kovacs Share this post Link to post
Mike Torrettinni 198 Posted April 29, 2020 I have up to 4 scroll boxes with a few controls in each scroll box and a few controls outside scroll boxes that are aligned, and need to reposition on each scroll. So, on each scroll message, a lot of calculations and repainting is done. Share this post Link to post
Attila Kovacs 631 Posted April 29, 2020 I see. Then you could also check how Align "alCustom" works. It could save you some repainting/flickering. Share this post Link to post
Mike Torrettinni 198 Posted April 29, 2020 6 hours ago, Attila Kovacs said: I see. Then you could also check how Align "alCustom" works. It could save you some repainting/flickering. Thank you, tried, but it doesn't improve the flicker, jittering effect of moving controls when scrolling fast. Learned something new today! 🙂 Share this post Link to post