Scrollbar event work-around?
Scrollbar event work-around?
I just submitted this bug for scrollbar events. On the project I'm currently working on I need to know when the scrollbar is activated to know when to update the work area. Does anyone know how work around this bug?
http://www.purebasic.fr/english/viewtopic.php?t=28797
http://www.purebasic.fr/english/viewtopic.php?t=28797
Wow. A coding question that hasn't been answered yet. I'm shocked and amazed. I actually get to answer something @_@
I patched this together for you to try out. Unfortunately, I only know of callbacks giving you this ability.
You'd want to put your code in the "offset\X = HoldInfo\nPos" and "offset\Y = HoldInfo\nPos" block because that's where the position is actually updated.
Also, this will enable tracking with the scrollbar and allow you to update as the user tracks versus waiting until they release the mouse.
Good luck.
I patched this together for you to try out. Unfortunately, I only know of callbacks giving you this ability.
Code: Select all
Global offset.POINT
Procedure TestCallback(Handle.l, uMsg.l, wParam.l, lParam.l)
;
Protected lResult.l
;
Protected AllowScroll.l
;
Protected HoldInfo.SCROLLINFO
;
If uMsg = #WM_HSCROLL
;{ User is scrolling a horizontal scrollbar.
; If lParam = GadgetID(0)
;/ This would be a place to test which scrollbar is used.
HoldInfo\cbSize = SizeOf(SCROLLINFO)
;
HoldInfo\fMask = #SIF_ALL
;
GetScrollInfo_(lParam, #SB_CTL, @HoldInfo)
;
AllowScroll = #True
; Allow scrolling by default.
If wParam & $FFFF = #SB_THUMBTRACK
HoldInfo\nPos = HoldInfo\nTrackPos
ElseIf wParam & $FFFF = #SB_LINERIGHT
HoldInfo\nPos + 1
ElseIf wParam & $FFFF = #SB_LINELEFT
HoldInfo\nPos - 1
ElseIf wParam & $FFFF = #SB_PAGERIGHT
HoldInfo\nPos + 3
ElseIf wParam & $FFFF = #SB_PAGELEFT
HoldInfo\nPos - 3
Else
; The scroll message is unhandled.
AllowScroll = #False
; Do not allow the user to scroll.
EndIf
;
If AllowScroll
;
If HoldInfo\nPos <> offset\X
;
offset\X = HoldInfo\nPos
;
Else
;
ProcedureReturn #True
;
EndIf
;
Else
;
ProcedureReturn #True
;
EndIf
;
;}
ElseIf uMsg = #WM_VSCROLL
;{ User is scrolling a vertical scrollbar.
; If lParam = GadgetID(1)
;/ This would be a place to test which scrollbar is used.
HoldInfo\cbSize = SizeOf(SCROLLINFO)
; Store the size of the ScrollInfo structure.
HoldInfo\fMask = #SIF_ALL
; All settings are needed.
GetScrollInfo_(lParam, #SB_CTL, @HoldInfo)
; Retrieve information on the scrollbar.
AllowScroll = #True
; Allow scrolling by default.
If wParam & $FFFF = #SB_THUMBTRACK
HoldInfo\nPos = HoldInfo\nTrackPos
ElseIf wParam & $FFFF = #SB_LINEUP
HoldInfo\nPos - 1
ElseIf wParam & $FFFF = #SB_LINEDOWN
HoldInfo\nPos + 1
ElseIf wParam & $FFFF = #SB_PAGEUP
HoldInfo\nPos - 3
ElseIf wParam & $FFFF = #SB_PAGEDOWN
HoldInfo\nPos + 3
Else
; The scroll message is unhandled.
AllowScroll = #False
; Do not allow the user to scroll.
EndIf
;
If AllowScroll
;
If HoldInfo\nPos <> offset\Y
offset\Y = HoldInfo\nPos
Else
ProcedureReturn #True
EndIf
;
Else
; The user is not allowed to scroll to the desired position.
ProcedureReturn #True
; Do not process the scrollbar event.
EndIf
;}
EndIf
;
ProcedureReturn #PB_ProcessPureBasicEvents
;
EndProcedure
If OpenWindow(0, 0, 0, 305, 140, "ScrollBarGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0))
TextGadget (2, 10, 25, 250, 20, "ScrollBar Standard (start=50, page=30/100)",#PB_Text_Center)
ScrollBarGadget (0, 10, 42, 250, 20, 0, 100, 30)
SetGadgetState (0, 50) ; set 1st scrollbar (ID = 0) to 50 of 100
TextGadget (3, 10,115, 250, 20, "ScrollBar Vertical (start=100, page=50/300)",#PB_Text_Right)
ScrollBarGadget (1, 270, 10, 25, 120 ,0, 300, 50, #PB_ScrollBar_Vertical)
SetGadgetState (1, 100) ; set 2nd scrollbar (ID = 1) to 100 of 300
SetWindowCallback(@TestCallback())
Repeat
Event=WaitWindowEvent()
EventGadget=EventGadget()
If Event=#PB_Event_Gadget And EventGadget=0
Debug "1 : "+Str(EventType())
EndIf
If Event=#PB_Event_Gadget And EventGadget=1
Debug "2 : "+Str(EventType())
EndIf
Until Event=#PB_Event_CloseWindow
EndIf
Also, this will enable tracking with the scrollbar and allow you to update as the user tracks versus waiting until they release the mouse.
Good luck.
As some questions do go unanswered I'm always grateful to anyone who tries to help.
Thank you!
I have a few other questions if you don't mind?
I'm having some trouble with DisableGadget(). After disabling a scrollbar modifying it with SetGadgetAttribute(#scrollbar,#PB_ScrollBar_PageLength,#window) enables it. This reaction is very undesirable. Is there another way through API flags to make the bar look disabled and override this?
Also, when I disable a gadget using DisableGadget() I have to set my own variable flag for each one if I want to check and to see if it's currently disabled. Is there a way to return whether a gadget has been disabled in this way? Maybe by setting an API disabled flag on the control and reading from that?
I think part of the code you've already provided can help but I'm unfamiliar with how to work with callbacks. Sorry if I'm asking an obvious question for an anwer you may already given me. :roll:
Thank you!

I have a few other questions if you don't mind?
I'm having some trouble with DisableGadget(). After disabling a scrollbar modifying it with SetGadgetAttribute(#scrollbar,#PB_ScrollBar_PageLength,#window) enables it. This reaction is very undesirable. Is there another way through API flags to make the bar look disabled and override this?
Also, when I disable a gadget using DisableGadget() I have to set my own variable flag for each one if I want to check and to see if it's currently disabled. Is there a way to return whether a gadget has been disabled in this way? Maybe by setting an API disabled flag on the control and reading from that?
I think part of the code you've already provided can help but I'm unfamiliar with how to work with callbacks. Sorry if I'm asking an obvious question for an anwer you may already given me. :roll:
Last edited by Mistrel on Tue Sep 18, 2007 9:17 pm, edited 1 time in total.
More code...
So now there are 4 buttons at the top: D, S, E, ?
D disables the horizontal scrollbar. S sets the attribute and E enables the scrollbar. ? should output whether the scrollbar is enabled or not.
I'm not seeing the behavior you're seeing. I click D to disable the scrollbar and then S to set the attribute as you say and the scrollbar is still disabled.
So...? Is that not how you're doing it?
Code: Select all
Global offset.POINT
Procedure TestCallback(Handle.l, uMsg.l, wParam.l, lParam.l)
;
Protected lResult.l
;
Protected AllowScroll.l
;
Protected HoldInfo.SCROLLINFO
;
If uMsg = #WM_HSCROLL
;{ User is scrolling a horizontal scrollbar.
; If lParam = GadgetID(0)
;/ This would be a place to test which scrollbar is used.
HoldInfo\cbSize = SizeOf(SCROLLINFO)
;
HoldInfo\fMask = #SIF_ALL
;
GetScrollInfo_(lParam, #SB_CTL, @HoldInfo)
;
AllowScroll = #True
; Allow scrolling by default.
If wParam & $FFFF = #SB_THUMBTRACK
HoldInfo\nPos = HoldInfo\nTrackPos
ElseIf wParam & $FFFF = #SB_LINERIGHT
HoldInfo\nPos + 1
ElseIf wParam & $FFFF = #SB_LINELEFT
HoldInfo\nPos - 1
ElseIf wParam & $FFFF = #SB_PAGERIGHT
HoldInfo\nPos + 3
ElseIf wParam & $FFFF = #SB_PAGELEFT
HoldInfo\nPos - 3
Else
; The scroll message is unhandled.
AllowScroll = #False
; Do not allow the user to scroll.
EndIf
;
If AllowScroll
;
If HoldInfo\nPos <> offset\X
;
offset\X = HoldInfo\nPos
;
Else
;
ProcedureReturn #True
;
EndIf
;
Else
;
ProcedureReturn #True
;
EndIf
;
;}
ElseIf uMsg = #WM_VSCROLL
;{ User is scrolling a vertical scrollbar.
; If lParam = GadgetID(1)
;/ This would be a place to test which scrollbar is used.
HoldInfo\cbSize = SizeOf(SCROLLINFO)
; Store the size of the ScrollInfo structure.
HoldInfo\fMask = #SIF_ALL
; All settings are needed.
GetScrollInfo_(lParam, #SB_CTL, @HoldInfo)
; Retrieve information on the scrollbar.
AllowScroll = #True
; Allow scrolling by default.
If wParam & $FFFF = #SB_THUMBTRACK
HoldInfo\nPos = HoldInfo\nTrackPos
ElseIf wParam & $FFFF = #SB_LINEUP
HoldInfo\nPos - 1
ElseIf wParam & $FFFF = #SB_LINEDOWN
HoldInfo\nPos + 1
ElseIf wParam & $FFFF = #SB_PAGEUP
HoldInfo\nPos - 3
ElseIf wParam & $FFFF = #SB_PAGEDOWN
HoldInfo\nPos + 3
Else
; The scroll message is unhandled.
AllowScroll = #False
; Do not allow the user to scroll.
EndIf
;
If AllowScroll
;
If HoldInfo\nPos <> offset\Y
offset\Y = HoldInfo\nPos
Else
ProcedureReturn #True
EndIf
;
Else
; The user is not allowed to scroll to the desired position.
ProcedureReturn #True
; Do not process the scrollbar event.
EndIf
;}
EndIf
;
ProcedureReturn #PB_ProcessPureBasicEvents
;
EndProcedure
If OpenWindow(0, 0, 0, 305, 140, "ScrollBarGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0))
TextGadget (2, 10, 25, 250, 20, "ScrollBar Standard (start=50, page=30/100)",#PB_Text_Center)
ScrollBarGadget (0, 10, 42, 250, 20, 0, 100, 30)
SetGadgetState (0, 50) ; set 1st scrollbar (ID = 0) to 50 of 100
TextGadget (3, 10,115, 250, 20, "ScrollBar Vertical (start=100, page=50/300)",#PB_Text_Right)
ScrollBarGadget (1, 270, 10, 25, 120 ,0, 300, 50, #PB_ScrollBar_Vertical)
SetGadgetState (1, 100) ; set 2nd scrollbar (ID = 1) to 100 of 300
ButtonGadget(4, 0, 0, 20, 20, "D")
ButtonGadget(5, 20, 0, 20, 20, "S")
ButtonGadget(6, 40, 0, 20, 20, "E")
ButtonGadget(7, 60, 0, 20, 20, "?")
SetWindowCallback(@TestCallback())
Repeat
Event=WaitWindowEvent()
EventGadget=EventGadget()
If Event=#PB_Event_Gadget And EventGadget=0
Debug "1 : "+Str(EventType())
EndIf
If Event=#PB_Event_Gadget And EventGadget=1
Debug "2 : "+Str(EventType())
EndIf
If Event=#PB_Event_Gadget And EventGadget=4 And EventType() = #PB_EventType_LeftClick
DisableGadget(0, #True)
EndIf
If Event=#PB_Event_Gadget And EventGadget=5 And EventType() = #PB_EventType_LeftClick
SetGadgetAttribute(0, 35, 0)
EndIf
If Event=#PB_Event_Gadget And EventGadget=6 And EventType() = #PB_EventType_LeftClick
DisableGadget(0, #False)
EndIf
If Event=#PB_Event_Gadget And EventGadget=7 And EventType() = #PB_EventType_LeftClick
If GetWindowLong_(GadgetID(0), #GWL_STYLE) & #WS_DISABLED : Debug "Disabled" : Else : Debug "Enabled" : EndIf
EndIf
Until Event=#PB_Event_CloseWindow
EndIf
D disables the horizontal scrollbar. S sets the attribute and E enables the scrollbar. ? should output whether the scrollbar is enabled or not.
I'm not seeing the behavior you're seeing. I click D to disable the scrollbar and then S to set the attribute as you say and the scrollbar is still disabled.
So...? Is that not how you're doing it?
You changed your last post/question since I was writing this one. I'm testing your code now..
This is what I said:
What I ultimately want (and hopefully I'm not trying to reinvent the wheel here) is a scrollbar area where the scrollbars are disabled instead of hidden if the window is resized large than the scroll area.
Here is my current project file. Please forgive the mess. I don't clean my code until I've got it working the way I want it.
When you run this example and you'll see that I have a scrollbar area gadget, two overriding scrollbars, and an overriding resize area in the corner. If you drag the bottom scrollbar you'll see that I can only update the scrollbar area on mouse up because that's the only event returned by WindowEvent.
The whole disabling thing has to do with how the scrollbars are disabled when the window size is larger than the scrollbar area in particular dimension. When I resize the disabled scrollbar as the window is resized I have to disable it again, so it would help to know if it's already in a disabled state. Otherwise I have to track their state in a unique variable for each scrollbar.
This is what I said:
What I ultimately want (and hopefully I'm not trying to reinvent the wheel here) is a scrollbar area where the scrollbars are disabled instead of hidden if the window is resized large than the scroll area.
Here is my current project file. Please forgive the mess. I don't clean my code until I've got it working the way I want it.
When you run this example and you'll see that I have a scrollbar area gadget, two overriding scrollbars, and an overriding resize area in the corner. If you drag the bottom scrollbar you'll see that I can only update the scrollbar area on mouse up because that's the only event returned by WindowEvent.
The whole disabling thing has to do with how the scrollbars are disabled when the window size is larger than the scrollbar area in particular dimension. When I resize the disabled scrollbar as the window is resized I have to disable it again, so it would help to know if it's already in a disabled state. Otherwise I have to track their state in a unique variable for each scrollbar.
Code: Select all
Removed by author
Last edited by Mistrel on Wed Sep 19, 2007 7:26 am, edited 2 times in total.
Here is an example of the behavior I'm talking about. I don't know where you came up with "35" as an attribute.I'm not seeing the behavior you're seeing. I click D to disable the scrollbar and then S to set the attribute as you say and the scrollbar is still disabled.
Code: Select all
If OpenWindow(0, 0, 0, 305, 140, "ScrollBarGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0))
ScrollBarGadget (0, 10, 42, 250, 20, 0, 100, 30)
DisableGadget(0,1)
SetGadgetAttribute(0,#PB_ScrollBar_PageLength,50)
Repeat
Event=WaitWindowEvent()
Until Event=#PB_Event_CloseWindow
EndIf
Oh. Try this as a replacement for SetGadgetAttribute() - but only for your scrollbars.
(Edited: Try the code again, please. I forgot also allowing for enabled scrollbars and changing the lParam to Handle - old code
)
Code: Select all
Procedure SetScrollAttribute(Gadget.l, Attribute.l, Value.l)
;
Protected Handle.l
;
Protected HoldInfo.SCROLLINFO
;
Protected IsDisabled.l
;
If GadgetType(Gadget) <> #PB_GadgetType_ScrollBar : ProcedureReturn : EndIf
;
Handle = GadgetID(Gadget)
;
IsDisabled = GetWindowLong_(Handle, #GWL_STYLE) & #WS_DISABLED
;
HoldInfo\cbSize = SizeOf(SCROLLINFO)
;
HoldInfo\fMask = #SIF_ALL
;
GetScrollInfo_(Handle, #SB_CTL, @HoldInfo)
;
If Attribute = #PB_ScrollBar_Minimum
;
HoldInfo\nMin = Value
;
ElseIf Attribute = #PB_ScrollBar_Maximum
;
HoldInfo\nMax = Value
;
ElseIf Attribute = #PB_ScrollBar_PageLength
;
HoldInfo\nPage = Value
;
Else
;
ProcedureReturn
;
EndIf
;
If IsDisabled : SetScrollInfo_(Handle, #SB_CTL, @HoldInfo, #False) : Else : SetScrollInfo_(Handle, #SB_CTL, @HoldInfo, #True) : EndIf
;
EndProcedure

Thank you for your help. I have one more question regarding your callback example.
I need to know which gadget has been activated. I tried outputting the handle.l that is used within TestCallback but it doesn't match the GadgetID() of either scroll bar.
How can the callback be used to return the gadget number or gadget id of the active scrollbar?
I would also like to change the number of pixels/lines moved while pressing one of the directional arrows. By default my scrollbars are only moving one pixel at a time.
I don't see an attribute for this in the SCROLLINFO structure but I'll keep looking.
I need to know which gadget has been activated. I tried outputting the handle.l that is used within TestCallback but it doesn't match the GadgetID() of either scroll bar.
How can the callback be used to return the gadget number or gadget id of the active scrollbar?
I would also like to change the number of pixels/lines moved while pressing one of the directional arrows. By default my scrollbars are only moving one pixel at a time.
I don't see an attribute for this in the SCROLLINFO structure but I'll keep looking.
Do you see the two lines in the callback that look like this...
Just above that, add this line...
And that will tell you which Gadget ID is using the callback currently. lParam will contain the handle to the scrollbar for the scroll events. You can handle it by testing with "If lParam..." or "If GetDlgCtrlID_(...." and that's up to your coding style.
You can certainly adjust the amount you scroll by changing the values within this block...
Adjust the amounts like "HoldInfo\nPos + 10" or whatever value you like under the #SB_...... constants. Hopefully those make sense for you.
Remember that there are two events - #WM_HSCROLL and #WM_VSCROLL and you need to handle both in a similar way.
Hope that helps!
Code: Select all
If lParam = GadgetID(1)
Code: Select all
Debug "PB Gadget ID: "+Str(GetDlgCtrlID_(lParam))
You can certainly adjust the amount you scroll by changing the values within this block...
Code: Select all
If wParam & $FFFF = #SB_THUMBTRACK
HoldInfo\nPos = HoldInfo\nTrackPos
ElseIf wParam & $FFFF = #SB_LINERIGHT
HoldInfo\nPos + 1
ElseIf wParam & $FFFF = #SB_LINELEFT
HoldInfo\nPos - 1
ElseIf wParam & $FFFF = #SB_PAGERIGHT
HoldInfo\nPos + 3
ElseIf wParam & $FFFF = #SB_PAGELEFT
HoldInfo\nPos - 3
Else
; The scroll message is unhandled.
AllowScroll = #False
; Do not allow the user to scroll.
EndIf
Remember that there are two events - #WM_HSCROLL and #WM_VSCROLL and you need to handle both in a similar way.
Hope that helps!
It does! I've almost got it working perfectly but I ran into another problem.
Change line 313 from this
to this
The scroll area gadget is stealing focus from my scrollbars even though it's supposed to be behind them. I don't know what to do about this. 
Change line 313 from this
Code: Select all
ResizeGadget(scroll_area,0,0,WindowWidth(main_window)-25,WindowHeight(main_window)-25)
Code: Select all
ResizeGadget(scroll_area,0,0,WindowWidth(main_window),WindowHeight(main_window))

Code: Select all
Removed by author
Last edited by Mistrel on Thu Sep 20, 2007 2:19 am, edited 1 time in total.
Lack of sleep is making my brain dull. What do you mean exactly by "The scroll area gadget is stealing focus from my scrollbars even though it's supposed to be behind them. I don't know what to do about this." ?
More precisely "supposed to be behind them" ? Maybe if I knew the purpose of the application I'd be able to fully grasp what is going on.
More precisely "supposed to be behind them" ? Maybe if I knew the purpose of the application I'd be able to fully grasp what is going on.
I made a post about it here
http://www.purebasic.fr/english/viewtopic.php?t=28802
I've solved that problem with help some some people on the forum but I'm still working on getting rid of a few other bugs.
http://www.purebasic.fr/english/viewtopic.php?t=28802
I've solved that problem with help some some people on the forum but I'm still working on getting rid of a few other bugs.
It's finished! Thank you very much for helping me with this, Xombie. I've learned a lot from working with your code. 
http://www.purebasic.fr/english/viewtop ... 834#210834

http://www.purebasic.fr/english/viewtop ... 834#210834