Improved ScrollBarGadget

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
User avatar
charvista
Addict
Addict
Posts: 949
Joined: Tue Sep 23, 2008 11:38 pm
Location: Belgium

Re: Improved ScrollBarGadget

Post by charvista »

Indeed, I must admit with your proof that it makes quite a large difference when narrowing to the events to save CPU usage. :wink:
So I agree that narrowing is necessary.
- Narrowing to the Scrollbar Gadget is of course mandatory. :mrgreen:
- Narrowing to #WM_HSCROLL and #WM_VSCROLL is clever. :D
- Alas, narrowing to ScrollCode is nonsense. :cry: Because the number of events between #WM_HSCROLL (or #WM_VSCROLL) is the same or the difference is extremely low.

However, we still need ScrollCode! :twisted: Now you are really puzzled :mrgreen:
Yes, if you examine the code, you will see that I embedded #WM_HSCROLL with the ScrollCode to get a halt in the events if the GetGadgetState() has changed compared with the kept state in the last WindowCallback! (=variables Hstate/Vstate)
It is rather complex, but it is the compromise between speed and having the image completely and nicely at the left or right side (or completely at the top/bottom).
There is no flickering nor erratic movements with large images.

I would like to thank you for your cooperation involving this problem, Shardik. :P :wink:

If you use the free software Paint.NET, you can compare the image scrolling there: open a large jpg file, do a "Save As" in jpg format, give a new name, and then you will get a window to adjust the jpeg quality, together with a scrollable image. PureBasic can do that now too! :wink:

Note: please adjust the LoadImage() to open a large image.

Code: Select all

;(c) Shardik 2011-05-25
;(c) Charvista 2011-12-28

EnableExplicit

Enumeration
    #Image     ; loaded image
    #ImageBis  ; duplicate image
    #Gadget    ; image gadget
    #Window    ; window
    #ScbGadH   ; scrollbar gadget horizontal
    #ScbGadV   ; scrollbar gadget vertical
EndEnumeration

Define.i WinWidth,WinHeight,HMarge,VMarge,GWidth,GHeight,ScrollCode

Procedure WindowCallback(WindowHandle.i,Msg.i,wParam.i,lParam.i)
    Static.i MsgCount1,MsgCount2,MsgCount3,Hstate,Vstate
    Shared GWidth,GHeight,ScrollCode
    If lParam=GadgetID(#ScbGadH) Or lParam=GadgetID(#ScbGadV)
        MsgCount1+1
        ScrollCode.i=WParam & $FFFF
        If (Msg=#WM_HSCROLL And ScrollCode<>#SB_THUMBPOSITION And ScrollCode<>#SB_ENDSCROLL) Or GetGadgetState(#ScbGadH)<>Hstate Or (Msg=#WM_VSCROLL And ScrollCode<>#SB_THUMBPOSITION And ScrollCode<>#SB_ENDSCROLL) Or GetGadgetState(#ScbGadV)<>Vstate
            ; with #WM_HSCROLL/#WM_VSCROLL, it will only update if the cursor is ON the scrollbar
            ; if used here and scrollbar is moved to start or end too quickly, will show some "latency" when the mouse button is released
            MsgCount2+1
            ;ScrollCode.i=WParam & $FFFF
            ;If ScrollCode<>#SB_THUMBPOSITION And ScrollCode<>#SB_ENDSCROLL
                ;MsgCount3+1
                Hstate=GetGadgetState(#ScbGadH)
                Vstate=GetGadgetState(#ScbGadV)
                GrabImage(#Image,#ImageBis,Hstate,Vstate,GWidth,GHeight)
                SetGadgetState(#Gadget,ImageID(#ImageBis))
                Debug "Redraws for messages generated by ScrollBarGadget: " + Str(MsgCount1)
                Debug "Redraws with filtering of #WM_HSCROLL: " + Str(MsgCount2)
                Debug "Redraws with filtering of #WM_HSCROLL and ScrollCode: " + Str(MsgCount3)
            ;EndIf
        EndIf
    EndIf
    ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

UsePNGImageDecoder()
UseJPEGImageDecoder()
LoadImage(#Image,"c:/users/myname/pictures/aVeryLargeImage.png")  ;#PB_Compiler_Home+"/examples/3D/Data/Water/Foam.png")
WinWidth=390;200
WinHeight=320;200
OpenWindow(#Window,0,0,WinWidth,WinHeight,"Image scrolling",#PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_SizeGadget)
HMarge=5
VMarge=5
GWidth=WinWidth-(2*HMarge)-20; marge left & right
GHeight=WinHeight-(2*VMarge)-20; marge top & bottom
ImageGadget(#Gadget,HMarge,VMarge,GWidth,GHeight,0,#PB_Image_Border)
; never use ImageWidth() as width for ImageGadget() because this will automatically replace the width of the ImageGadget() with the width of the image!
; so if you want a fixed ImageGadget width, use a fixed value => here GWidth used.
; same rule applies for ImageHeight().

ScrollBarGadget(#ScbGadH,HMarge,WindowHeight(#Window)-20,GWidth,15,0,ImageWidth(#Image),GWidth)
ScrollBarGadget(#ScbGadV,WindowWidth(#Window)-20,VMarge,15,GHeight,0,ImageHeight(#Image),GHeight,#PB_ScrollBar_Vertical)
GrabImage(#Image,#ImageBis,0,0,GWidth,GHeight)
SetGadgetState(#Gadget,ImageID(#ImageBis))
SetWindowCallback(@WindowCallback(),#Window)

Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
- Windows 11 Home 64-bit
- PureBasic 6.10 LTS (x64)
- 64 Gb RAM
- 13th Gen Intel(R) Core(TM) i9-13900K 3.00 GHz
- 5K monitor with DPI @ 200%
Post Reply