Jump to content

child GUI scrollbar breaks


Recommended Posts

I've modified a little rover's code and tested on windows XP (VM) and windows 7, both 32 bits (changing themes and backgrounds) and seems ok now:

The scroll bar is not being set to the original position, so the modifications you made still need some attention. I discovered that leaving the scroll bar set to zero seems to solve the problem with theme changes. Leaving the scroll bar at the starting position when changing the windows theme seems a small concession to make. I think we are nearly there. Thanks! Edited by czardas
Link to comment
Share on other sites

From rover's suggestion. Removing two lines from the function I wrote leaves the scroll bar set to zero which seems to solve the problem (as I mentioned in my last post). Thanks everyone for the help, I will be using this.

#AutoIt3Wrapper_au3check_parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <StructureConstants.au3>
#include <GUIScrollBars.au3>
#include <ScrollBarConstants.au3>

Opt("MustDeclareVars", 1)

Global Const $WM_THEMECHANGED = 0x031A
Global $cRefresh

_Main()

Func _Main()
    Local $nFileMenu, $nExititem, $GUIMsg, $button, $hGUI, $h_cGUI

    $hGUI = GUICreate("ScrollBar Example", 400, 400, -1, -1)

    $cRefresh = GUICtrlCreateDummy() ;for on-event and message loop modes

    $nFileMenu = GUICtrlCreateMenu("File")
    $nExititem = GUICtrlCreateMenuItem("Exit", $nFileMenu)
    $button = GUICtrlCreateButton("Test", 300, 10, 80, 30)

    $h_cGUI = GUICreate("Child GUI", 200, 260, 10, 10, $WS_CHILD, Default, $hGUI)
    For $i = 0 to 39 Step 2
        GUICtrlCreateCheckbox("Check " & $i + 1,  10, 10 + 20 * $i/2, 90, 20)
        GUICtrlCreateCheckbox("Check " & $i + 2, 110, 10 + 20 * $i/2, 90, 20)
    Next
    GUISetState(@SW_SHOW)
    GUICtrlSetResizing($h_cGUI, $GUI_DOCKALL)

    GUISwitch($hGUI)

    GUIRegisterMsg($WM_VSCROLL, "WM_VSCROLL")
    GUIRegisterMsg($WM_THEMECHANGED, "WM_THEMECHANGED")

    _GUIScrollBars_Init($h_cGUI)
    _GUIScrollBars_ShowScrollBar($h_cGUI,  $SB_HORZ, False)
    _GUIScrollBars_SetScrollInfoMax($h_cGUI, $SB_VERT, 25)

    GUISetState()

    While 1
        $GUIMsg = GUIGetMsg()

        Switch $GUIMsg
            Case $cRefresh
                _Refresh($h_cGUI)
            Case $GUI_EVENT_CLOSE, $nExititem
                ExitLoop
            Case $button
                MsgBox(0, "Test", "")
        EndSwitch

    WEnd

    Exit
EndFunc   ;==>_Main


Func WM_THEMECHANGED($hWnd, $Msg, $wParam, $lParam)
    #forceref $hWnd, $Msg, $wParam, $lParam
    GUICtrlSendToDummy($cRefresh)
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_THEMECHANGED


Func _Refresh($hWnd)
    ;Local $nPos = _GUIScrollBars_GetScrollPos($hWnd, $SB_VERT) ; Get current position ; >>>>>>> REMOVED
    _GUIScrollBars_SetScrollInfoPos($hWnd, $SB_VERT, 0) ; Set the scroll to zero

    Local $tSCROLLINFO = _GUIScrollBars_GetScrollInfoEx($hWnd, $SB_VERT)
    _GUIScrollBars_ShowScrollBar($hWnd,  $SB_HORZ, False)
    _GUIScrollBars_SetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO)
    ;_GUIScrollBars_SetScrollInfoPos($hWnd, $SB_VERT, $nPos) ; >>>>>>> REMOVED
EndFunc


Func WM_VSCROLL($hWnd, $Msg, $wParam, $lParam)
    #forceref $Msg, $wParam, $lParam
    Local $nScrollCode = BitAND($wParam, 0x0000FFFF)
    Local $index = -1, $yChar, $yPos
    Local $Min, $Max, $Page, $Pos, $TrackPos

    For $x = 0 To UBound($aSB_WindowInfo) - 1
        If $aSB_WindowInfo[$x][0] = $hWnd Then
            $index = $x
            $yChar = $aSB_WindowInfo[$index][3]
            ExitLoop
        EndIf
    Next
    If $index = -1 Then Return 0


    ; Get all the vertial scroll bar information
    Local $tSCROLLINFO = _GUIScrollBars_GetScrollInfoEx($hWnd, $SB_VERT)
    $Min = DllStructGetData($tSCROLLINFO, "nMin")
    $Max = DllStructGetData($tSCROLLINFO, "nMax")
    $Page = DllStructGetData($tSCROLLINFO, "nPage")
    ; Save the position for comparison later on
    $yPos = DllStructGetData($tSCROLLINFO, "nPos")
    $Pos = $yPos
    $TrackPos = DllStructGetData($tSCROLLINFO, "nTrackPos")

    Switch $nScrollCode
        Case $SB_TOP ; user clicked the HOME keyboard key
            DllStructSetData($tSCROLLINFO, "nPos", $Min)

        Case $SB_BOTTOM ; user clicked the END keyboard key
            DllStructSetData($tSCROLLINFO, "nPos", $Max)

        Case $SB_LINEUP ; user clicked the top arrow
            DllStructSetData($tSCROLLINFO, "nPos", $Pos - 1)

        Case $SB_LINEDOWN ; user clicked the bottom arrow
            DllStructSetData($tSCROLLINFO, "nPos", $Pos + 1)

        Case $SB_PAGEUP ; user clicked the scroll bar shaft above the scroll box
            DllStructSetData($tSCROLLINFO, "nPos", $Pos - $Page)

        Case $SB_PAGEDOWN ; user clicked the scroll bar shaft below the scroll box
            DllStructSetData($tSCROLLINFO, "nPos", $Pos + $Page)

        Case $SB_THUMBTRACK ; user dragged the scroll box
            DllStructSetData($tSCROLLINFO, "nPos", $TrackPos)
    EndSwitch

;~    // Set the position and then retrieve it.  Due to adjustments
;~    //   by Windows it may not be the same as the value set.

    DllStructSetData($tSCROLLINFO, "fMask", $SIF_POS)
    _GUIScrollBars_SetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO)
    _GUIScrollBars_GetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO)
    ;// If the position has changed, scroll the window and update it
    $Pos = DllStructGetData($tSCROLLINFO, "nPos")

    If ($Pos <> $yPos) Then
        _GUIScrollBars_ScrollWindow($hWnd, 0, $yChar * ($yPos - $Pos))
        $yPos = $Pos
    EndIf

    Return $GUI_RUNDEFMSG

EndFunc   ;==>WM_VSCROLL
Edited by czardas
Link to comment
Share on other sites

That's very helpful, thanks. However the problem still seems to occur when switching from Windows XP theme to Windows Classic theme. I have been trying to figure it out, but it's strange because it appears to work when switching back to the Windows XP theme.

I can just imagine a user discovering this bug by accident and not being able to reproduce the circumstances that caused it. :mellow:

Another issue to troubleshoot courtesy of our tormentor MicroSoft

_GUIScrollBars_ShowScrollBar() solves the issue with turning off the theme engine when the classic theme is selected (themes off),

so scroll position is now retained after theme change.

The themechanged message is sent when themes are turned off

whereas the message occurs after the old theme is removed and the new theme is set when switching between themes

so perhaps the message order/inclusion of painting/erasing is different because of this?

@taietel

Using _GUIScrollBars_ShowScrollBar(), all code can once more be shoved into message events handlers instead of being polled.

Edit: typo, rewording

Edit2: just read the posts after czardas post I quoted above, issue with scroll position in taietel's code already addressed by czardas

#AutoIt3Wrapper_au3check_parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <StructureConstants.au3>
#include <GUIScrollBars.au3>
#include <ScrollBarConstants.au3>

Opt("MustDeclareVars", 1)

Global Const $WM_THEMECHANGED = 0x031A
Global $cRefresh

_Main()

Func _Main()
    Local $nFileMenu, $nExititem, $GUIMsg, $button, $hGUI, $h_cGUI

    $hGUI = GUICreate("ScrollBar Example", 400, 400, -1, -1)

    $cRefresh = GUICtrlCreateDummy() ;for on-event and message loop modes

    $nFileMenu = GUICtrlCreateMenu("File")
    $nExititem = GUICtrlCreateMenuItem("Exit", $nFileMenu)
    $button = GUICtrlCreateButton("Test", 300, 10, 80, 30)

    $h_cGUI = GUICreate("Child GUI", 200, 260, 10, 10, $WS_CHILD, Default, $hGUI)
    For $i = 0 to 39 Step 2
        GUICtrlCreateCheckbox("Check " & $i + 1,  10, 10 + 20 * $i/2, 90, 20)
        GUICtrlCreateCheckbox("Check " & $i + 2, 110, 10 + 20 * $i/2, 90, 20)
    Next
    GUISetState(@SW_SHOW)
    GUICtrlSetResizing($h_cGUI, $GUI_DOCKALL)

    GUISwitch($hGUI)

    GUIRegisterMsg($WM_VSCROLL, "WM_VSCROLL")
    GUIRegisterMsg($WM_THEMECHANGED, "WM_THEMECHANGED")


    _GUIScrollBars_Init($h_cGUI)
    _GUIScrollBars_ShowScrollBar($h_cGUI,  $SB_HORZ, False)
    _GUIScrollBars_SetScrollInfoMax($h_cGUI, $SB_VERT, 25)

    GUISetState()

    While 1
        $GUIMsg = GUIGetMsg()

        Switch $GUIMsg
            Case $cRefresh
                _Refresh($h_cGUI)
            Case $GUI_EVENT_CLOSE, $nExititem
                ExitLoop
            Case $button
                MsgBox(0, "Test", "")
        EndSwitch

    WEnd

    Exit
EndFunc   ;==>_Main


Func WM_THEMECHANGED($hWnd, $Msg, $wParam, $lParam)
    #forceref $hWnd, $Msg, $wParam, $lParam
    GUICtrlSendToDummy($cRefresh)
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_THEMECHANGED


Func _Refresh($hWnd)
    ;Local $aRet = DllCall('uxtheme.dll', 'int', 'IsThemeActive')
    ;If @error = 0 And $aRet[0] = 0 Then
        _GUIScrollBars_ShowScrollBar($hWnd, $SB_BOTH, True)
    ;EndIf
    Local $nPos = _GUIScrollBars_GetScrollPos($hWnd, $SB_VERT) ; Get current position
    _GUIScrollBars_SetScrollInfoPos($hWnd, $SB_VERT, 0) ; Set the scroll to zero

    Local $tSCROLLINFO = _GUIScrollBars_GetScrollInfoEx($hWnd, $SB_VERT)
    _GUIScrollBars_ShowScrollBar($hWnd,  $SB_HORZ, False)
    _GUIScrollBars_SetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO)
    _GUIScrollBars_SetScrollInfoPos($hWnd, $SB_VERT, $nPos)
EndFunc


Func WM_VSCROLL($hWnd, $Msg, $wParam, $lParam)
    #forceref $Msg, $wParam, $lParam
    Local $nScrollCode = BitAND($wParam, 0x0000FFFF)
    Local $index = -1, $yChar, $yPos
    Local $Min, $Max, $Page, $Pos, $TrackPos

    For $x = 0 To UBound($aSB_WindowInfo) - 1
        If $aSB_WindowInfo[$x][0] = $hWnd Then
            $index = $x
            $yChar = $aSB_WindowInfo[$index][3]
            ExitLoop
        EndIf
    Next
    If $index = -1 Then Return 0


    ; Get all the vertial scroll bar information
    Local $tSCROLLINFO = _GUIScrollBars_GetScrollInfoEx($hWnd, $SB_VERT)
    $Min = DllStructGetData($tSCROLLINFO, "nMin")
    $Max = DllStructGetData($tSCROLLINFO, "nMax")
    $Page = DllStructGetData($tSCROLLINFO, "nPage")
    ; Save the position for comparison later on
    $yPos = DllStructGetData($tSCROLLINFO, "nPos")
    $Pos = $yPos
    $TrackPos = DllStructGetData($tSCROLLINFO, "nTrackPos")

    Switch $nScrollCode
        Case $SB_TOP ; user clicked the HOME keyboard key
            DllStructSetData($tSCROLLINFO, "nPos", $Min)

        Case $SB_BOTTOM ; user clicked the END keyboard key
            DllStructSetData($tSCROLLINFO, "nPos", $Max)

        Case $SB_LINEUP ; user clicked the top arrow
            DllStructSetData($tSCROLLINFO, "nPos", $Pos - 1)

        Case $SB_LINEDOWN ; user clicked the bottom arrow
            DllStructSetData($tSCROLLINFO, "nPos", $Pos + 1)

        Case $SB_PAGEUP ; user clicked the scroll bar shaft above the scroll box
            DllStructSetData($tSCROLLINFO, "nPos", $Pos - $Page)

        Case $SB_PAGEDOWN ; user clicked the scroll bar shaft below the scroll box
            DllStructSetData($tSCROLLINFO, "nPos", $Pos + $Page)

        Case $SB_THUMBTRACK ; user dragged the scroll box
            DllStructSetData($tSCROLLINFO, "nPos", $TrackPos)
    EndSwitch

;~    // Set the position and then retrieve it.  Due to adjustments
;~    //   by Windows it may not be the same as the value set.

    DllStructSetData($tSCROLLINFO, "fMask", $SIF_POS)
    _GUIScrollBars_SetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO)
    _GUIScrollBars_GetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO)
    ;// If the position has changed, scroll the window and update it
    $Pos = DllStructGetData($tSCROLLINFO, "nPos")

    If ($Pos <> $yPos) Then
        _GUIScrollBars_ScrollWindow($hWnd, 0, $yChar * ($yPos - $Pos))
        $yPos = $Pos
    EndIf

    Return $GUI_RUNDEFMSG

EndFunc   ;==>WM_VSCROLL
Edited by rover

I see fascists...

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...