TurtlePower Posted September 5 Share Posted September 5 Hi Autoit Forum I'm working on a project for managing designs where I have two listboxes, and I need them to always scroll together. Basically, when one listbox is scrolled vertically, the other should match it and scroll by the same amount. I've been digging around but can't seem to figure out how to sync the vertical scrolling between the two.. Has anyone done this before or have any tips on how I can achieve this? Any help or examples would be greatly appreciated Link to comment Share on other sites More sharing options...
Nine Posted September 6 Share Posted September 6 Never tried it, but I suppose it could be possible thru WM_VSCROLL. When you receive this message, you could send the same message to the other listbox. If you need further help, provide a runable script with those 2 listboxes so we do not have to create them on our own. “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
pixelsearch Posted September 6 Share Posted September 6 (edited) I succeeded, but in 2 separate scripts. 1) One script is simple, testing... _GUICtrlListBox_GetTopIndex() ...from the 1st listbox in main loop, then setting the same index in the 2nd list box This first script is 100% accurate... only when using the mouse wheel or keyboard (up, down, pgup, pgdn, home, end) 2) 2nd script is a bit more complicated and gives 100% accuracy when using the scrollbar, its thumbtrack etc... It requires to subclass the listbox (see what @LarsJ wrote here and let's apply it to LB instead of LV), then inside the subclassing proc we can intercept $WM_VSCROLL, but I also needed to test things like this : Local $iScrollRequest = BitAND($wParam, 0xFFFF) ; LoWord Local $iScrollPos = BitShift($wParam, 16) ; HiWord If $iScrollRequest = $SB_THUMBTRACK Or $iScrollRequest = $SB_THUMBPOSITION Then .... That's strange, though I can intercept $WM_MOUSEWHEEL too inside the subclassing function, results are not as good as the 1st script. Anyway, it's nearly finished. I'll try to combine both scripts, though I'm pretty sure someone else will bring a working solution before I'm done Edit: combine done a few hours ago, final script is functional. Waiting for OP's answer to @Nine before posting. Edited September 6 by pixelsearch typo Link to comment Share on other sites More sharing options...
Solution pixelsearch Posted September 20 Solution Share Posted September 20 Ok, so here is my solution to scroll both listbox in parallel, when they got the same number of items : expandcollapse popup#include <GUIConstantsEx.au3> #include <GuiListBox.au3> #include <ScrollBarConstants.au3> #include <WinAPIShellEx.au3> #include <WindowsConstants.au3> OnAutoItExitRegister('OnAutoItExit') Opt("MustDeclareVars", 1) ;0=no, 1=require pre-declaration Global $g_hListBox[2], $g_hDll[2], $g_pDll[2], $g_idSubClass[2] = [9999, 9998], $g_iTopIndexOld = -1 Example() Func Example() Local $iLeft[2] = [50, 300], $sFormat[2] = ["%02d", "A - %02d"], $sFunction[2] = ['_SubclassProc_0', '_SubclassProc_1'] GUICreate("Sync scrolling V2 (mouse wheel / scrollbar / keyboard)", 550, 400) For $i = 0 To 1 $g_hListBox[$i] = GUICtrlGetHandle(GUICtrlCreateList("", $iLeft[$i], 50, 200, 300)) _GUICtrlListBox_BeginUpdate($g_hListBox[$i]) For $iRow = 0 To 99 _GUICtrlListBox_AddString($g_hListBox[$i], StringFormat($sFormat[$i], $iRow)) Next _GUICtrlListBox_EndUpdate($g_hListBox[$i]) ; Create a listbox callback function (to catch scrollbar messages, as listbox scrollbars are child windows of listbox controls) $g_hDll[$i] = DllCallbackRegister($sFunction[$i], 'lresult', 'hwnd;uint;wparam;lparam;uint_ptr;dword_ptr') $g_pDll[$i] = DllCallbackGetPtr($g_hDll[$i]) ; Install the listbox subclass callback (to handle messages related to listbox scrollbars) _WinAPI_SetWindowSubclass($g_hListBox[$i], $g_pDll[$i], $g_idSubClass[$i], 0) Next GUISetState() ; main loop takes care of mouse wheel & keyboard (up, down, pgup, pgdn, home, end) Local $iTopIndex = 0 Do For $i = 0 To 1 $iTopIndex = _GUICtrlListBox_GetTopIndex($g_hListBox[$i]) _CompareIndex($iTopIndex, $i) Next Until GUIGetMsg() = $GUI_EVENT_CLOSE EndFunc ;==>Example ;============================================== Func _CompareIndex($iTopIndex, $iListBox) If $iTopIndex <> $g_iTopIndexOld Then _GUICtrlListBox_SetTopIndex($g_hListBox[Not $iListBox], $iTopIndex) ; [Not 0] => [1] , [Not 1] => [0] $g_iTopIndexOld = $iTopIndex EndIf EndFunc ;==>_CompareIndex ;============================================== Func _SubclassProc_0($hWnd, $iMsg, $wParam, $lParam, $iID, $pData) #forceref $iID, $pData Switch $iMsg Case $WM_VSCROLL Local $iScrollRequest = BitAND($wParam, 0xFFFF) ; LoWord Local $iScrollPos = BitShift($wParam, 16) ; HiWord Local $iTopIndex = ($iScrollRequest = $SB_THUMBTRACK Or $iScrollRequest = $SB_THUMBPOSITION) _ ? $iScrollPos _ : _GUICtrlListBox_GetTopIndex($g_hListBox[0]) _CompareIndex($iTopIndex, 0) EndSwitch ; Call next function in subclass chain Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>_SubclassProc_0 ;============================================== Func _SubclassProc_1($hWnd, $iMsg, $wParam, $lParam, $iID, $pData) #forceref $iID, $pData Switch $iMsg Case $WM_VSCROLL Local $iScrollRequest = BitAND($wParam, 0xFFFF) ; LoWord Local $iScrollPos = BitShift($wParam, 16) ; HiWord Local $iTopIndex = ($iScrollRequest = $SB_THUMBTRACK Or $iScrollRequest = $SB_THUMBPOSITION) _ ? $iScrollPos _ : _GUICtrlListBox_GetTopIndex($g_hListBox[1]) _CompareIndex($iTopIndex, 1) EndSwitch ; Call next function in subclass chain Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>_SubclassProc_1 ;============================================== Func OnAutoItExit() For $i = 1 To 0 Step - 1 ; Remove the listbox subclass callback _WinAPI_RemoveWindowSubclass($g_hListBox[$i], $g_pDll[$i], $g_idSubClass[$i]) ; Frees a previously created handle created with DllCallbackRegister DllCallbackFree($g_hDll[$i]) Next EndFunc ;==>OnAutoItExit In case someone is interested, I scripted 2 others : 1) Synchronize selections too (when both listbox got the same number of items) 2) Take care of listboxes that don't have the same number of items. ioa747 1 Link to comment Share on other sites More sharing options...
TurtlePower Posted September 20 Author Share Posted September 20 4 hours ago, pixelsearch said: Ok, so here is my solution to scroll both listbox in parallel, when they got the same number of items : expandcollapse popup#include <GUIConstantsEx.au3> #include <GuiListBox.au3> #include <ScrollBarConstants.au3> #include <WinAPIShellEx.au3> #include <WindowsConstants.au3> OnAutoItExitRegister('OnAutoItExit') Opt("MustDeclareVars", 1) ;0=no, 1=require pre-declaration Global $g_hListBox[2], $g_hDll[2], $g_pDll[2], $g_idSubClass[2] = [9999, 9998], $g_iTopIndexOld = -1 Example() Func Example() Local $iLeft[2] = [50, 300], $sFormat[2] = ["%02d", "A - %02d"], $sFunction[2] = ['_SubclassProc_0', '_SubclassProc_1'] GUICreate("Sync scrolling V2 (mouse wheel / scrollbar / keyboard)", 550, 400) For $i = 0 To 1 $g_hListBox[$i] = GUICtrlGetHandle(GUICtrlCreateList("", $iLeft[$i], 50, 200, 300)) _GUICtrlListBox_BeginUpdate($g_hListBox[$i]) For $iRow = 0 To 99 _GUICtrlListBox_AddString($g_hListBox[$i], StringFormat($sFormat[$i], $iRow)) Next _GUICtrlListBox_EndUpdate($g_hListBox[$i]) ; Create a listbox callback function (to catch scrollbar messages, as listbox scrollbars are child windows of listbox controls) $g_hDll[$i] = DllCallbackRegister($sFunction[$i], 'lresult', 'hwnd;uint;wparam;lparam;uint_ptr;dword_ptr') $g_pDll[$i] = DllCallbackGetPtr($g_hDll[$i]) ; Install the listbox subclass callback (to handle messages related to listbox scrollbars) _WinAPI_SetWindowSubclass($g_hListBox[$i], $g_pDll[$i], $g_idSubClass[$i], 0) Next GUISetState() ; main loop takes care of mouse wheel & keyboard (up, down, pgup, pgdn, home, end) Local $iTopIndex = 0 Do For $i = 0 To 1 $iTopIndex = _GUICtrlListBox_GetTopIndex($g_hListBox[$i]) _CompareIndex($iTopIndex, $i) Next Until GUIGetMsg() = $GUI_EVENT_CLOSE EndFunc ;==>Example ;============================================== Func _CompareIndex($iTopIndex, $iListBox) If $iTopIndex <> $g_iTopIndexOld Then _GUICtrlListBox_SetTopIndex($g_hListBox[Not $iListBox], $iTopIndex) ; [Not 0] => [1] , [Not 1] => [0] $g_iTopIndexOld = $iTopIndex EndIf EndFunc ;==>_CompareIndex ;============================================== Func _SubclassProc_0($hWnd, $iMsg, $wParam, $lParam, $iID, $pData) #forceref $iID, $pData Switch $iMsg Case $WM_VSCROLL Local $iScrollRequest = BitAND($wParam, 0xFFFF) ; LoWord Local $iScrollPos = BitShift($wParam, 16) ; HiWord Local $iTopIndex = ($iScrollRequest = $SB_THUMBTRACK Or $iScrollRequest = $SB_THUMBPOSITION) _ ? $iScrollPos _ : _GUICtrlListBox_GetTopIndex($g_hListBox[0]) _CompareIndex($iTopIndex, 0) EndSwitch ; Call next function in subclass chain Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>_SubclassProc_0 ;============================================== Func _SubclassProc_1($hWnd, $iMsg, $wParam, $lParam, $iID, $pData) #forceref $iID, $pData Switch $iMsg Case $WM_VSCROLL Local $iScrollRequest = BitAND($wParam, 0xFFFF) ; LoWord Local $iScrollPos = BitShift($wParam, 16) ; HiWord Local $iTopIndex = ($iScrollRequest = $SB_THUMBTRACK Or $iScrollRequest = $SB_THUMBPOSITION) _ ? $iScrollPos _ : _GUICtrlListBox_GetTopIndex($g_hListBox[1]) _CompareIndex($iTopIndex, 1) EndSwitch ; Call next function in subclass chain Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>_SubclassProc_1 ;============================================== Func OnAutoItExit() For $i = 1 To 0 Step - 1 ; Remove the listbox subclass callback _WinAPI_RemoveWindowSubclass($g_hListBox[$i], $g_pDll[$i], $g_idSubClass[$i]) ; Frees a previously created handle created with DllCallbackRegister DllCallbackFree($g_hDll[$i]) Next EndFunc ;==>OnAutoItExit In case someone is interested, I scripted 2 others : 1) Synchronize selections too (when both listbox got the same number of items) 2) Take care of listboxes that don't have the same number of items. Thanks a ton! Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now