Jump to content

Sync two Editbox scroll


Terenz
 Share

Recommended Posts

I have made an attempt with RichEdit, the scrollbar aren't syncronized...some pixel of difference without any reason and sometime not work

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiRichEdit.au3>

Global $sText = "", $hGUI, $hRichEdit1, $hRichEdit2

For $i = 1 To 50
    $sText &= "TEST_" & $i & @CRLF
Next

$hGUI = GUICreate("TEST", 350, 300, -1, -1)
$hRichEdit1 = __GUICtrlRichEdit_Create($hGUI, $sText, 10, 10, 160, 220, BitOR($ES_MULTILINE, $WS_VSCROLL, $WS_HSCROLL))
_GUICtrlRichEdit_SetEventMask($hRichEdit1, BitOR($ENM_KEYEVENTS, $ENM_SCROLL, $ENM_SCROLLEVENTS))
$hRichEdit2 = __GUICtrlRichEdit_Create($hGUI, $sText, 180, 10, 160, 220, BitOR($ES_MULTILINE, $WS_VSCROLL, $WS_HSCROLL))
_GUICtrlRichEdit_SetEventMask($hRichEdit2, BitOR($ENM_KEYEVENTS, $ENM_SCROLL, $ENM_SCROLLEVENTS))

GUISetState(@SW_SHOW)
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")

_GUICtrlRichEdit_SetScrollPos($hRichEdit1, 0, 0)
_GUICtrlRichEdit_SetScrollPos($hRichEdit2, 0, 0)

While True
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            _GUICtrlRichEdit_Destroy($hRichEdit1)
            _GUICtrlRichEdit_Destroy($hRichEdit2)
            Exit
    EndSwitch
WEnd

Func WM_NOTIFY($hWnd, $iMsg, $iWparam, $iLparam)
    #forceref $iMsg, $iWparam
    Local $hWndFrom, $iCode, $tNMHDR, $tMsgFilter, $hMenu, $tagEN_MSGFILTER = $tagNMHDR & ";uint msg;int wParam;int lParam;"
    $tNMHDR = DllStructCreate($tagNMHDR, $iLparam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $hRichEdit1
            Select
                Case $iCode = $EN_MSGFILTER
                    $tMsgFilter = DllStructCreate($tagEN_MSGFILTER, $iLparam)
                    Switch DllStructGetData($tMsgFilter, "msg")
                        Case 256, 257, 258
                            _GUICtrlRichEdit_SetText($hRichEdit2, _GUICtrlRichEdit_GetText($hRichEdit1))
                        Case 276
                            $aPos = _GUICtrlRichEdit_GetScrollPos($hRichEdit1)
                            _GUICtrlRichEdit_SetScrollPos($hRichEdit2, $aPos[0], $aPos[1])
                        Case 277
                            $aPos = _GUICtrlRichEdit_GetScrollPos($hRichEdit1)
                            _GUICtrlRichEdit_SetScrollPos($hRichEdit2, $aPos[0], $aPos[1])
                    EndSwitch
            EndSelect
        Case $hRichEdit2
            Select
                Case $iCode = $EN_MSGFILTER
                    $tMsgFilter = DllStructCreate($tagEN_MSGFILTER, $iLparam)
                    $aPos = _GUICtrlRichEdit_GetScrollPos($hRichEdit2)
                    Switch DllStructGetData($tMsgFilter, "msg")
                        Case 256, 257, 258
                            _GUICtrlRichEdit_SetText($hRichEdit2, _GUICtrlRichEdit_GetText($hRichEdit1))
                        Case 276
                            _GUICtrlRichEdit_SetScrollPos($hRichEdit1, $aPos[0], $aPos[1])
                        Case 277
                            _GUICtrlRichEdit_SetScrollPos($hRichEdit1, $aPos[0], $aPos[1])
                    EndSwitch
            EndSelect
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

Func __GUICtrlRichEdit_Create($hWnd, $sText, $iLeft, $iTop, $iWidth = 150, $iHeight = 150, $iStyle = -1, $iExStyle = -1)
    If Not IsHWnd($hWnd) Then Return SetError(1, 0, 0) ; Invalid Window handle for _GUICtrlRichEdit_Create 1st parameter
    If Not IsString($sText) Then Return SetError(2, 0, 0) ; 2nd parameter not a string for _GUICtrlRichEdit_Create

    If Not __GCR_IsNumeric($iWidth, ">0,-1") Then Return SetError(105, 0, 0)
    If Not __GCR_IsNumeric($iHeight, ">0,-1") Then Return SetError(106, 0, 0)
    If Not __GCR_IsNumeric($iStyle, ">=0,-1") Then Return SetError(107, 0, 0)
    If Not __GCR_IsNumeric($iExStyle, ">=0,-1") Then Return SetError(108, 0, 0)

    If $iWidth = -1 Then $iWidth = 150
    If $iHeight = -1 Then $iHeight = 150
    If $iStyle = -1 Then $iStyle = BitOR($ES_WANTRETURN, $ES_MULTILINE)

    If BitAND($iStyle, $ES_MULTILINE) <> 0 Then $iStyle = BitOR($iStyle, $ES_WANTRETURN)
    If $iExStyle = -1 Then $iExStyle = 0x200 ;  $DS_FOREGROUND

    $iStyle = BitOR($iStyle, $__UDFGUICONSTANT_WS_CHILD, $__UDFGUICONSTANT_WS_VISIBLE)
    If BitAND($iStyle, $ES_READONLY) = 0 Then $iStyle = BitOR($iStyle, $__RICHEDITCONSTANT_WS_TABSTOP)

    Local $nCtrlID = __UDF_GetNextGlobalID($hWnd)
    If @error Then Return SetError(@error, @extended, 0)

    __GCR_Init()

    Local $hRichEdit = _WinAPI_CreateWindowEx($iExStyle, $_GRE_sRTFClassName, "", $iStyle, $iLeft, $iTop, $iWidth, _
            $iHeight, $hWnd, $nCtrlID)
    If $hRichEdit = 0 Then Return SetError(700, 0, False)

    __GCR_SetOLECallback($hRichEdit)
    _SendMessage($hRichEdit, $__RICHEDITCONSTANT_WM_SETFONT, _WinAPI_GetStockObject($DEFAULT_GUI_FONT), True)
    _GUICtrlRichEdit_AppendText($hRichEdit, $sText)
    Return $hRichEdit
EndFunc   ;==>__GUICtrlRichEdit_Create

I am just about to leave and I'd hate to see it. I don't have the technical knowledge to continue with this...

Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Link to comment
Share on other sites

You implement the C# code (link in post 8) in this way:

#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPIShellEx.au3>

Example()

Func Example()
  GUICreate( "My GUI edit", 400, 200 )

  GUISetState( @SW_SHOW )

  Local $s = 1
  For $i = 2 To 100
    $s &= @CRLF & $i
  Next

  Local $idEdit1 = GUICtrlCreateEdit( $s, 10, 10, 185, 180, $ES_AUTOVSCROLL + $ES_WANTRETURN + $WS_VSCROLL )
  Local $hEdit1 = GUICtrlGetHandle( $idEdit1 )
  Send("{END}")

  Local $idEdit2 = GUICtrlCreateEdit( $s, 205, 10, 185, 180, $ES_AUTOVSCROLL + $ES_WANTRETURN + $WS_VSCROLL )
  Local $hEdit2 = GUICtrlGetHandle( $idEdit2 )
  Send("{END}")

  Local $pEditProc = DllCallbackGetPtr( DllCallbackRegister( "EditProc", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr" ) )
  _WinAPI_SetWindowSubclass( $hEdit1, $pEditProc, 1, $idEdit2 ) ; $iSubclassId = 1, $pData = $idEdit2
  _WinAPI_SetWindowSubclass( $hEdit2, $pEditProc, 1, $idEdit1 ) ; $iSubclassId = 1, $pData = $idEdit1

  While 1
    Switch GUIGetMsg()
      Case $GUI_EVENT_CLOSE
        ExitLoop
    EndSwitch
  WEnd

  _WinAPI_RemoveWindowSubclass( $hEdit1, $pEditProc, 1 )
  _WinAPI_RemoveWindowSubclass( $hEdit2, $pEditProc, 1 )
  GUIDelete()
EndFunc

Func EditProc( $hWnd, $iMsg, $wParam, $lParam, $iSubclassId, $pData )
  Local Static $bScrolling
  If Not $bScrolling And $iMsg = $WM_VSCROLL Then
    $bScrolling = True
    GUICtrlSendMsg( $pData, $iMsg, $wParam, $lParam )
    $bScrolling = False
  EndIf
  ; Call next function in subclass chain
  Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam )[0]
  #forceref $iSubclassId
EndFunc

 

Link to comment
Share on other sites

Lars...My Hero! Works very well! I have changes some things to make it compatible with my autoit version, added the wheel constant, horizontal scroll and _WinAPI_DefSubclassProc instead of the DllCall

#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPI.au3>
#include <GuiEdit.au3>

Global $MOUSE_WHEELSCROLL_EVENT = 0x20A

Example()

Func Example()
    GUICreate("My GUI edit", 400, 200)

    GUISetState(@SW_SHOW)

    Local $s = "THIS_IS_A_LONG_LINE_FOR_ENABLE_HORIZONTAL_SCROLLING"
    For $i = 2 To 100
        $s &= @CRLF & $i
    Next

    Local $idEdit1 = GUICtrlCreateEdit($s, 10, 10, 185, 180, $ES_AUTOVSCROLL + $ES_AUTOHSCROLL + $ES_WANTRETURN + $WS_VSCROLL + $WS_HSCROLL)
    Local $hEdit1 = GUICtrlGetHandle($idEdit1)

    Local $idEdit2 = GUICtrlCreateEdit($s, 205, 10, 185, 180, $ES_AUTOVSCROLL + $ES_AUTOHSCROLL + $ES_WANTRETURN + $WS_VSCROLL + $WS_HSCROLL)
    Local $hEdit2 = GUICtrlGetHandle($idEdit2)

    Local $pEditProc = DllCallbackGetPtr(DllCallbackRegister("EditProc", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr"))
    _WinAPI_SetWindowSubclass($hEdit1, $pEditProc, 1, $idEdit2) ; $iSubclassId = 1, $pData = $idEdit2
    _WinAPI_SetWindowSubclass($hEdit2, $pEditProc, 1, $idEdit1) ; $iSubclassId = 1, $pData = $idEdit1

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop
        EndSwitch
    WEnd

    _WinAPI_RemoveWindowSubclass($hEdit1, $pEditProc, 1)
    _WinAPI_RemoveWindowSubclass($hEdit2, $pEditProc, 1)
    GUIDelete()
EndFunc   ;==>Example

Func EditProc($hWnd, $iMsg, $wParam, $lParam, $iSubclassId, $pData)
    #forceref $iSubclassId
    Local Static $bScrolling
    If Not $bScrolling Then
        Switch $iMsg
            Case 257, 258, $WM_VSCROLL, $WM_HSCROLL, $MOUSE_WHEELSCROLL_EVENT
                $bScrolling = True
;~              $aPos = _GUICtrlEdit_GetSel($pData-1)
;~              ConsoleWrite("POS: " & $aPos[0] & $aPos[1] & @CRLF)
;~              _GUICtrlEdit_SetSel($pData, $aPos[0], $aPos[1])
                GUICtrlSendMsg($pData, $iMsg, $wParam, $lParam)
                $bScrolling = False
        EndSwitch
    EndIf
    ; Call next function in subclass chain
    Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>EditProc

Func _WinAPI_SetWindowSubclass($hWnd, $pSubclassProc, $idSubClass, $pData = 0)
    Local $aRet = DllCall('comctl32.dll', 'bool', 'SetWindowSubclass', 'hwnd', $hWnd, 'ptr', $pSubclassProc, 'uint_ptr', $idSubClass, _
            'dword_ptr', $pData)
    If @error Then Return SetError(@error, @extended, 0)
    Return $aRet[0]
EndFunc   ;==>_WinAPI_SetWindowSubclass

Func _WinAPI_RemoveWindowSubclass($hWnd, $pSubclassProc, $idSubClass)
    Local $aRet = DllCall('comctl32.dll', 'bool', 'RemoveWindowSubclass', 'hwnd', $hWnd, 'ptr', $pSubclassProc, 'uint_ptr', $idSubClass)
    If @error Then Return SetError(@error, @extended, False)
    Return $aRet[0]
EndFunc   ;==>_WinAPI_RemoveWindowSubclass

Func _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
    Local $aRet = DllCall('comctl32.dll', 'lresult', 'DefSubclassProc', 'hwnd', $hWnd, 'uint', $iMsg, 'wparam', $wParam, _
            'lparam', $lParam)
    If @error Then Return SetError(@error, @extended, 0)
    Return $aRet[0]
EndFunc   ;==>_WinAPI_DefSubclassProc

I have a couple of question:

Did you know how i can use _GetSel and _SetSel for syncronize the selection of both editbox? Or maybe the SendMsg?

Did you know why if i'm scroll with the down-up arrow or with the mouse selection the scrollbar is not updated?

Thanks again

Edited by Terenz

Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Link to comment
Share on other sites

The code in post 22 works only if you use the mouse on one of the scrollbars. If you want to scroll an edit box with the arrow keys, you have to implement the synchronization yourself. That is, you have to look for $EN_VSCROLL notifications and synchronize the other edit box with _GUICtrlEdit_Scroll. You also need to know if you are scrolling up or down.

You can use _GetSel and _SetSel to synchronize selections. You need to be able to detect when the user has finished his  selection. You can probably check for a mouse up event and a non-empty selection. Then you can get the selection with _GetSel and synchronize the other edit box with _SetSel.

Link to comment
Share on other sites

I have try LarsJ and partially work but sometime the line using arrow is not update with the current, i think i have make some mistake. About the mouse i don't know if the scrolling goes up or down so i don't have implementated yet. Please check it:

Func EditProc($hWnd, $iMsg, $wParam, $lParam, $iSubclassId, $pData)
    #forceref $iSubclassId
    Local Static $bScrolling, $VScrollPos = _GetScroll($hWnd, 1), $hGetSel = _GUICtrlEdit_GetSel($hWnd)
    ;ConsoleWrite($wParam & @CRLF)
    If Not $bScrolling Then
        Switch $wParam
            Case 38 ; ARROW UP
                If $VScrollPos <> _GetScroll($hWnd, 1) Then
                    $VScrollPos = _GetScroll($hWnd, 1)
                    _GUICtrlEdit_Scroll($pData, 0) ; $SB_LINEUP
                EndIf
            Case 40 ; ARROW DOWN
                If $VScrollPos <> _GetScroll($hWnd, 1) Then
                    $VScrollPos = _GetScroll($hWnd, 1)
                    _GUICtrlEdit_Scroll($pData, 1) ; $SB_LINEDOWN
                EndIf
        EndSwitch
        Switch $iMsg
            Case 257, 258, $WM_VSCROLL, $WM_HSCROLL, $MOUSE_WHEELSCROLL_EVENT
                If $hGetSel <> _GUICtrlEdit_GetSel($hWnd) Then
                    $hGetSel = _GUICtrlEdit_GetSel($hWnd)
                    _GUICtrlEdit_SetSel($pData, $hGetSel[0], $hGetSel[1])
                EndIf
                $bScrolling = True
                GUICtrlSendMsg($pData, $iMsg, $wParam, $lParam)
                $bScrolling = False
        EndSwitch
    EndIf
    ; Call next function in subclass chain
    Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>EditProc

Func _GetScroll($hFrom, $iType) ; 0 horiziontal, 1 vertical
    Local $iGetInfo, $iSetInfo, $tSCROLLINFO = DllStructCreate($tagSCROLLINFO)
    DllStructSetData($tSCROLLINFO, "cbSize", DllStructGetSize($tSCROLLINFO))
    DllStructSetData($tSCROLLINFO, "fMask", $_SCROLLBARCONSTANTS_SIF_ALL)
    $iGetInfo = _GUIScrollBars_GetScrollInfo($hFrom, $iType, $tSCROLLINFO)
    If $iGetInfo = False Then Return SetError(1, 0, 0)
    Return DllStructGetData($tSCROLLINFO, "nTrackPos")
EndFunc   ;==>_GetScroll

 

Edited by Terenz

Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Link to comment
Share on other sites

a way using _WinAPI_SetTimer
I think it's a worst way, anyway here it is:

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPISys.au3>
#include <GuiEdit.au3>


Global $hMyGUI = GUICreate("My GUI edit", 400, 200)

Local $s = "THIS_IS_A_LONG_LINE_FOR_ENABLE_HORIZONTAL_SCROLLING"
For $i = 2 To 100
    $s &= @CRLF & $i
Next

Global $idEdit1 = GUICtrlCreateEdit($s, 10, 10, 185, 180, $ES_AUTOVSCROLL + $ES_AUTOHSCROLL + $ES_WANTRETURN + $WS_VSCROLL + $WS_HSCROLL)
Global $idEdit2 = GUICtrlCreateEdit($s, 205, 10, 185, 180, $ES_AUTOVSCROLL + $ES_AUTOHSCROLL + $ES_WANTRETURN + $WS_VSCROLL + $WS_HSCROLL)
GUISetState(@SW_SHOW)

Local $hTimerProc = DllCallbackRegister('_CheckAlign', 'none', 'hwnd;uint;uint_ptr;dword')
Local $iTimerID = _WinAPI_SetTimer(0, 0, 100, DllCallbackGetPtr($hTimerProc))

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ExitLoop
    EndSwitch
WEnd

_WinAPI_KillTimer(0, $iTimerID)
DllCallbackFree($hTimerProc)
GUIDelete()

Func _CheckAlign($hWnd, $Msg, $iIDTimer, $dwTime)
    #forceref $hWnd , $Msg , $iIDTimer , $dwTime
    Local Static $iFirstVis1_old = 0
    Local Static $iFirstVis2_old = 0
    Local $iFirstVis1 = _GUICtrlEdit_GetFirstVisibleLine($idEdit1)
    Local $iFirstVis2 = _GUICtrlEdit_GetFirstVisibleLine($idEdit2)
    If $iFirstVis1 <> $iFirstVis1_old Then
        $iFirstVis1_old = $iFirstVis1
        $iFirstVis2_old = $iFirstVis1
        _GUICtrlEdit_LineScroll($idEdit2, 0, $iFirstVis1 - $iFirstVis2)
        ; EndIf
    ElseIf $iFirstVis2 <> $iFirstVis2_old Then
        $iFirstVis1_old = $iFirstVis2
        $iFirstVis2_old = $iFirstVis2
        _GUICtrlEdit_LineScroll($idEdit1, 0, $iFirstVis2 - $iFirstVis1)
    EndIf
EndFunc   ;==>_CheckAlign

 

Edited by Chimp

 

image.jpeg.9f1a974c98e9f77d824b358729b089b0.jpeg Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Link to comment
Share on other sites

All very interesting, so I will be keeping a copy of this.

I once synced three list controls, and it works reasonably well, but all you guys seem to be well in advance of my meager talent and knowledge. It was an attempt at a pretend three column Listview ... only because I didn't feel like reworking a whole lot of code for a genuine Listview, and the exercise interested me.

Make sure brain is in gear before opening mouth!
Remember, what is not said, can be just as important as what is said.

Spoiler

What is the Secret Key? Life is like a Donut

If I put effort into communication, I expect you to read properly & fully, or just not comment.
Ignoring those who try to divert conversation with irrelevancies.
If I'm intent on insulting you or being rude, I will be obvious, not ambiguous about it.
I'm only big and bad, to those who have an over-active imagination.

I may have the Artistic Liesense ;) to disagree with you. TheSaint's Toolbox (be advised many downloads are not working due to ISP screwup with my storage)

userbar.png

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...