Page 1 of 2
ScrollBar events only on release
Posted: Sun Sep 12, 2010 12:23 pm
by Trond
When dragging a scrollbar on Windows XP it doesn't give any events until releasing the mouse button. On Linux it gives events while dragging.
Code: Select all
#W = 512
#H = 384
OpenWindow(0, 0, 0, #W, #H, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
ScrollBarGadget(0, 10, 10, 200, 23, 0, 100, 20)
Repeat
Select WaitWindowEvent()
Case #PB_Event_Gadget
Select EventGadget()
Case 0
Debug GetGadgetState(0)
EndSelect
Case #PB_Event_CloseWindow
Break
EndSelect
ForEver
Re: ScrollBar events only on release
Posted: Sun Sep 12, 2010 7:02 pm
by Fluid Byte
It's been that way since years. Practically since scrollbars were first introduced in PureBasic.
So not a bug at all, a missing feature at best.
Re: ScrollBar events only on release
Posted: Mon Sep 13, 2010 10:46 am
by Fred
That's because Windows uses a blocking callback for that, it's a limitation for sure, but not a bug.
Re: ScrollBar events only on release
Posted: Mon Sep 13, 2010 10:55 am
by srod
But the parent callback will still receive #WM_VSCROLL (or #WM_HSCROLL) notifications as the scroll is underway Fred.
Re: ScrollBar events only on release
Posted: Mon Sep 13, 2010 11:12 am
by Fred
Sure, but it won't exit the callback -> you won't have an event in the PB loop until the user release the button.
Re: ScrollBar events only on release
Posted: Mon Sep 13, 2010 11:25 am
by srod
I always imagined that PB's event loop was somehow 'invoked' by each Window proc, but now that I think about it, yes I understand.
Re: ScrollBar events only on release
Posted: Wed Dec 21, 2011 6:25 pm
by Trond
I still can't get this scrollbar thing to work properly. Look:
Code: Select all
Procedure WndProc(WindowID, Msg.i, wParam.i, lParam.i)
Select Msg
Case #WM_HSCROLL
Debug GetGadgetState(0)
EndSelect
ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure
W = 512
H = 384
OpenWindow(0, 0, 0, W, H, "", #PB_Window_ScreenCentered | #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget | #PB_Window_SizeGadget)
ScrollBarGadget(0, 10, 10, 200, 17, 0, 5, 1)
;OldProc = SetWindowLongPtr_(GadgetID(0), #GWLP_WNDPROC, @WndProc())
SetWindowCallback(@WndProc())
Repeat
Event = WaitWindowEvent()
Select Event
Case #PB_Event_CloseWindow
CloseWindow(0)
Break
EndSelect
ForEver
Drag the thumb one notch to the right, and it shows 0 a second time. Before releasing, drag it back to position 0 -
now it debugs 1! Release the mouse button and it shows 0 twice!
Or drag it slowly to the right. Even when fully jammed into the right side, it just won't display 4 - until the mouse button is released and it shows 4 twice!
Re: ScrollBar events only on release
Posted: Wed Dec 21, 2011 6:52 pm
by srod
I am not on my Windows machine right now but what you are describing is what I would expect.
Don't use a PB callback Trond, subclass the window instead - or at the very least do not return #PB_ProcessPureBasicEvents for the #WM_HSCROLL message. The thing is that Windows will not move the scrollbox in response to user actions and depends instead on your #WM_HSCROLL handler using SetScrollInfo_() etc. to actually move the thumb (tracking aside). Because you do not actually use SetScrollInfo_() you are seeing the wrong values debugged. By using #PB_ProcessPureBasicEvents, you are giving PB's default handler the chance to take over which will of course move the scrollbox, but not before you have debugged the (incorrect) value.
As for the repeated debugs, this is happening because #WM_HSCROLL is called multiple times whilst the user is dragging the thumb (scroll code #SB_THUMBTRACK) and again when the user releases the thumb (#SB_THUMBPOSITION). You need to examine the scrollcode which sits in the lower 16-bits of wParam.
I can hack some code up for you if you wish?
Re: ScrollBar events only on release
Posted: Wed Dec 21, 2011 7:01 pm
by srod
Try this :
Code: Select all
Global gOldProc
Procedure WndProc(WindowID, Msg.i, wParam.i, lParam.i)
result = CallWindowProc_(gOldProc, WindowID, Msg, wParam, lParam)
Select Msg
Case #WM_HSCROLL
scrollCode = wParam & $ffff
If scrollCode <> #SB_THUMBPOSITION And scrollCode <> #SB_ENDSCROLL
Debug GetGadgetState(0)
EndIf
EndSelect
ProcedureReturn result
EndProcedure
W = 512
H = 384
OpenWindow(0, 0, 0, W, H, "", #PB_Window_ScreenCentered | #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget | #PB_Window_SizeGadget)
ScrollBarGadget(0, 10, 10, 200, 17, 0, 5, 1)
gOldProc = SetWindowLongPtr_(WindowID(0), #GWLP_WNDPROC, @WndProc())
Repeat
Event = WaitWindowEvent()
Select Event
Case #PB_Event_CloseWindow
CloseWindow(0)
Break
EndSelect
ForEver
Here, the sublass proc calls the previous handler (the one installed by PB) to handle, in particular, the scrolling events. PB's handler will use SetScrollInfo_() to actually move the scrollthumb etc. and our procedure simply retrieves this new value via GetGadgetState(). Comment out the result = ... line and you will see that no movement of the scrollthumb takes place (tracking aside) which is the default behaviour for Windows.
Re: ScrollBar events only on release
Posted: Wed Dec 21, 2011 7:55 pm
by Trond
Wow, thank you!
I tried a PB window callback, and I tried subclassing the gadget, but I didn't think of subclassing the window. That being said, subclassing the gadget works, when I use your technique of calling the old callback at the start instead of at the end. I never would have figured that out.
Re: ScrollBar events only on release
Posted: Wed Dec 21, 2011 8:05 pm
by srod
Trond wrote:Wow, thank you!
I tried a PB window callback, and I tried subclassing the gadget, but I didn't think of subclassing the window. That being said, subclassing the gadget works, when I use your technique of calling the old callback at the start instead of at the end. I never would have figured that out.
Yes I do that so that PB can move the scrollbox for us, otherwise GetGadgetState() will return the incorrect value. Personally, I don't call the old callback at all for #WM_HSCROLL and instead move the scrollbox myself the appropriate distance using SetScrollInfo_() etc.
Re: ScrollBar events only on release
Posted: Fri Dec 23, 2011 1:26 pm
by charvista
@Trond
It looks like you asked the same question as me, in following your other topic
http://www.purebasic.fr/english/viewtop ... 88#p369888 (ScrollBarGadget can't reach max?).
DoubleDutch gave me an answer that gave me a solution from RASHAD through a search in the forum:
http://www.purebasic.fr/english/viewtop ... nt#p353306.
The difference with srod's solution is that RASHAD's code is portable (no APIs), but using a simple Thread.
Code below is from RASHAD, I modified it to have two scrollbars, and see if it can work with one Thread.
Code: Select all
;(c) Rashad 2011-05-22
; this will show in 'real-time' the current scrollbar position
Procedure Scrollbar(parameter)
Repeat
SetGadgetText(1,Str(GetGadgetState(2)))
SetGadgetText(4,Str(GetGadgetState(5)))
Delay(40)
ForEver
EndProcedure
OpenWindow(0, 0, 0, 305, 140, "ScrollBarGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
Vstart.i=50
TextGadget (0, 10,15, 220, 20, "VScrollBar Position : ",#PB_Text_Right)
TextGadget (1, 230,15, 20, 20, Str(Vstart),#PB_Text_Right)
ScrollBarGadget (2, 270, 10, 25, 120 ,0, 101, 1, #PB_ScrollBar_Vertical)
SetGadgetState (2,Vstart)
Hstart.i=20
TextGadget (3, 0,90, 120, 20, "HScrollBar Position : ",#PB_Text_Right)
TextGadget (4, 120,90, 20, 20, Str(Hstart),#PB_Text_Right)
ScrollBarGadget (5, 0, 110, 270, 20 ,0, 101, 1)
SetGadgetState (5,Hstart)
AddKeyboardShortcut(0, #PB_Shortcut_Up,10)
AddKeyboardShortcut(0, #PB_Shortcut_Down,11)
Thread = CreateThread(@Scrollbar(), 15)
ThreadPriority(Thread, 1)
Repeat
Select WaitWindowEvent(1)
Case #PB_Event_CloseWindow
Quit = 1
Case #PB_Event_Menu
Select EventMenu()
Case 10
SetGadgetState(2,GetGadgetState(2) - 1)
SetGadgetText(1,Str(GetGadgetState(2)))
Case 11
SetGadgetState(2,GetGadgetState(2) + 1)
SetGadgetText(1,Str(GetGadgetState(2)))
EndSelect
Case #PB_Event_Gadget
Select EventGadget()
Case 2
EndSelect
EndSelect
Until Quit = 1
CloseWindow(0)
Different approaches, same result.
Cheers!
Re: ScrollBar events only on release
Posted: Fri Dec 23, 2011 2:38 pm
by RASHAD
Using Windows CallBack
Code: Select all
Global Backg1,Backg2,OldVPos,OldHPos
Backg1 = CreateSolidBrush_($BDFFFF)
Backg2 = CreateSolidBrush_($DFFFDD)
Procedure WndProc(hwnd, uMsg, wParam, lParam)
result = #PB_ProcessPureBasicEvents
Select uMsg
Case #WM_CTLCOLORSCROLLBAR
If lParam = GadgetID(0)
Result = Backg1
Else
Result = Backg2
EndIf
Case #WM_MOUSEWHEEL
If (wParam >> 16 & $FFFF) <> $FF88
SetGadgetState(1,GetGadgetState(1) - 1)
Else
SetGadgetState(1,GetGadgetState(1) + 1)
EndIf
Case #WM_KEYDOWN ,#WM_MENUSELECT
Select wParam
Case #VK_UP
SetGadgetState(1,GetGadgetState(1) - 1)
Case #VK_DOWN
SetGadgetState(1,GetGadgetState(1) + 1)
Case #VK_LEFT
SetGadgetState(0,GetGadgetState(0) - 1)
Case #VK_RIGHT
SetGadgetState(0,GetGadgetState(0) + 1)
EndSelect
EndSelect
If IsGadget(0) And OldHPos <> GetGadgetState(0)
OldHPOs = GetGadgetState(0)
Debug "H.ScrollBar Pos.: "+Str(OldHPos)
ElseIf IsGadget(1) And OldVPos <> GetGadgetState(1)
OldVPOs = GetGadgetState(1)
Debug "V.ScrollBar Pos.: "+Str(OldVPos)
EndIf
ProcedureReturn result
EndProcedure
OpenWindow(0, 0, 0, 300, 250, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
ScrollBarGadget(0, 10, 10,200,18, 0, 100, 1)
ScrollBarGadget(1, 10, 40, 18,200, 0, 100, 1,#PB_ScrollBar_Vertical)
Frame3DGadget(2, 9, 9, 203, 21, "",#PB_Frame3D_Double)
Frame3DGadget(3, 9, 39, 21, 203, "",#PB_Frame3D_Double)
SetWindowCallback(@WndProc())
Repeat
Select WaitWindowEvent()
Case #PB_Event_Gadget
Select EventGadget()
Case 0
Case 1
EndSelect
Case #PB_Event_CloseWindow
Quit = 1
EndSelect
Until Quit = 1
Re: ScrollBar events only on release
Posted: Fri Dec 23, 2011 7:41 pm
by Kwai chang caine
Rashad wrote:Using Windows CallBack
Waoouuuh !!!

Re: ScrollBar events only on release
Posted: Fri Dec 23, 2011 7:51 pm
by charvista
Waoouuuh !!!

Rashad said once, KCC and me, we are trouble makers hahaha
Seriously now

. Rashad, excellent example. Nicely presented with CreateSolidBrush_ and Frame3DGadget.
