Jump to content

Need help synchronizing MDI (WS_EX_MDICHILD) window with Child Window (WS_CHILD)


Go to solution Solved by pixelsearch,

Recommended Posts

Posted

Thanks to @pixelsearch for not letting me give up, I am getting very close to being able to create a thread for the project over in the AutoIt Projects and Collaboration section. My intention is to open up the project so that anyone here in the forum can participate if they would like it. The general idea is "Files Au3" which is basically a File Explorer in AutoIt.

Before I do that, can anyone please test the script from the attached FilesAu3.zip archive to ensure that it is functioning in the most basic of terms. My only goal right now is that the GUI frames resize without flickering and same goes for the ListView functionality. I did not want to go too deep into any features until I got the flickering under control. That was a deal-breaker for me. But on my end, everything is about as smooth as possible.

Please let me know how it goes as far as resizing and flickering go. There is still a lot to do though. It is a bare-bones file viewer at the moment. 

FilesAu3.zip

Posted
33 minutes ago, WildByDesign said:

It is a bare-bones file viewer at the moment. 

I think that the GUI and the searching should be separated/forked.
When listing something slow, like a network share with lots of folders/subfolders, the GUI is "not responsive".

Other than that, nice looking.

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted
4 minutes ago, argumentum said:

When listing something slow, like a network share with lots of folders/subfolders, the GUI is "not responsive".

For those network shares, do they eventually show the items and the GUI becomes responsive after?

The TreeListExplorer UDF that I use has a built-in callback mechanism for a progress control. I wonder if that may be beneficial for this type of scenario.

Also, I've thought about multi-process as a possibility here as well to prevent the GUI from becoming not responsive. I will have to look into this a bit more.

9 minutes ago, argumentum said:

I think that the GUI and the searching should be separated/forked.

Are you referring to the Input box at the top?

That isn't intended for searching. It's just a simple box to display the current path. But you can also enter valid path there and press Enter to navigate to it.

Thank you for giving it a test. :)

Posted (edited)
7 minutes ago, WildByDesign said:

For those network shares, do they eventually show the items and the GUI becomes responsive after?

Yes, eventually shows the items. Not after.

7 minutes ago, WildByDesign said:

Are you referring to the Input box at the top?

No. The reason for forking the process that gives the data to the treeview, is to avoid unresponsiveness of the GUI.

But you'll have to look into it.
It is quite responsive if the system returns the data fast.

Edited by argumentum

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted
2 hours ago, WildByDesign said:

Good catch, thank you. This will be an easy fix.

It turns out that I was wrong about this being an easy fix. I thought it would be as easy as resizing the header items. But I'm not sure how to resize the header control itself. If anyone knows how to resize it, please let me know.

Posted

Hey everybody :)
@WildByDesign I hadn't time to test your scripts yet (glad argumentum and ioa747 are helping you for the tests) because I really wanted to improve 2 functionalities of the "detached" header control, which are :

1) Dragging the divider between 2 header items to enlarge a column :
I wanted the listview columns to be enlarged at same time (as in a native listview) which wasn't the case in our preceding scripts. To do this I used the $HDN_TRACK notification + $tagNMHEADER + $tagHDITEM to finally reach $tHDITEM.XY which indicated in real time what was the width of the header item being enlarged. This value varies constantly during the tracking. Without this, I wouldn't have made it at all !

2) Dragging and dropping a header item elsewhere :
Notification $HDN_ENDDRAG was used here, with a global variable $g_bHeaderEndDrag, no adlib/timer at all.
Glad you found the 3-way steps "remove LVS_NOCOLUMNHEADER from listview" => reorder LV columns => "add LVS_NOCOLUMNHEADER back to listview".
But I don't know how secure is this 3-way because, from time to time, the script hangs on my computer, exactly at the time when a header item is dropped elsewhere to reorder columns.
Also, if someone knows why both LV scrollbars aren't redrawn correctly after a header item is dropped elsewhere, please indicate your solution. Actually, clicking at the blank place where they are supposed to appear make them immediately visible, that's strange, maybe some window to refresh after the reorder part ?

3) LV horizontal scrolling :
no change from the precedent script : $LVN_ENDSCROLL notification is used to check the horizontal scrolling in real-time and have LV columns scroll horizontally while the horizontal scrollbar is moved, thanks to $tNMLVSCROLL.dy !
The scrolling may be a bit different from a "native" LV but it works and that's the good part, especially we didn't install a ListView subclass callback to handle messages related to both Scrollbars controls.

On 12/1/2025 at 3:35 PM, WildByDesign said:

Also, I need to get the height of the header control because it is different depending on the DPI that the user has set. I will probably look into using _GUICtrlHeader_GetItemRect for that but have not tried yet.

I used _WinAPI_GetWindowHeight($g_hHeader) in the script and it seems to work : the LV is placed immediately under the header after you use its value in your LV vertical coords.

Ok here is the code, time to rest a bit (a lot !) after these efforts.
Have a great evening everybody :bye:

#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <StructureConstants.au3>
#include <WinAPISysWin.au3>
#include <WindowsConstants.au3>

; DPI
DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext" , "HWND", "DPI_AWARENESS_CONTEXT" -2)

Opt("MustDeclareVars", 1) ;0=no, 1=require pre-declaration

Global $g_hGUI, $g_hChild, $g_hHeader, $g_hListview, $g_bHeaderEndDrag

Example()

Func Example()
    $g_hGUI = GUICreate("Example", 400, 400, -1, -1, $WS_OVERLAPPEDWINDOW, $WS_EX_COMPOSITED)
    GUISetBkColor(0x202020)

    GUISetState(@SW_SHOW, $g_hGUI)

    $g_hChild = GUICreate("ChildWindow", 320, 320, 40, 40, $WS_CHILD, -1, $g_hGUI)
    GUISetBkColor(0x606060)

    $g_hHeader = _GUICtrlHeader_Create($g_hChild)
    Local $iHeaderHeight = _WinAPI_GetWindowHeight($g_hHeader)
    For $i = 0 To 3
        _GUICtrlHeader_AddItem($g_hHeader, "Column" & $i, 100)
    Next

    Local $idListview = GUICtrlCreateListView("col0|col1|col2|col3", 0, $iHeaderHeight, 320, 320 - $iHeaderHeight, _
        BitOR($GUI_SS_DEFAULT_LISTVIEW, $LVS_NOCOLUMNHEADER), BitOR($LVS_EX_DOUBLEBUFFER, $LVS_EX_FULLROWSELECT))
    $g_hListview = GUICtrlGetHandle($idListview)

    _GUICtrlListView_BeginUpdate($idListview)
    For $i = 1 To 30
        GUICtrlCreateListViewItem("item" & $i & "-0|item" & $i  & "-1|item" & $i & "-2|item" & $i & "-3", $idListview)
    Next
    _GUICtrlListView_EndUpdate($idListview)

    ; resize listview columns to match header widths
    _resizeLVCols()

    GUISetState(@SW_SHOW, $g_hChild)

    ; get rid of dotted rectangle in listview, when an item got the focus
    GUICtrlSendMsg($idListview, $WM_CHANGEUISTATE, 65537, 0)

    GUIRegisterMsg($WM_NOTIFY, WM_NOTIFY)

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop
        EndSwitch

        If $g_bHeaderEndDrag Then
            $g_bHeaderEndDrag = False
            _reorderLVCols()
        EndIf
    WEnd

    _GUICtrlHeader_Destroy($g_hHeader)
    GUIDelete($g_hChild)
    GUIDelete($g_hGUI)
EndFunc   ;==>Example

;==============================================
Func _resizeHeaderItems()
    Local $aRect
    For $iCol = 0 To _GUICtrlListView_GetColumnCount($g_hListView) - 1
        If $iCol Then
            $aRect = _GUICtrlListView_GetSubItemRect($g_hListView, 0, $iCol)
        Else
            $aRect = _GUICtrlListView_GetItemRect($g_hListView, 0, 2) ; 2 = bounding rectangle of the item text
        EndIf
        _GUICtrlHeader_SetItemWidth( $g_hHeader, $iCol, $aRect[2] - (($aRect[0] > 0) ? $aRect[0] : 0) )
    Next
EndFunc   ;==>_resizeHeaderItems

;==============================================
Func _resizeLVCols()
    Local $aRect
    For $iCol = 0 To _GUICtrlListView_GetColumnCount($g_hListView) - 1
        $aRect = _GUICtrlHeader_GetItemRect($g_hHeader, $iCol)
        _GUICtrlListView_SetColumnWidth($g_hListview, $iCol, $aRect[2] - (($aRect[0] > 0) ? $aRect[0] : 0) )
    Next
EndFunc   ;==>_resizeLVCols

;==============================================
Func _reorderLVCols()
    ; remove LVS_NOCOLUMNHEADER from listview
    __WinAPI_Set_Window_Style($g_hListView, $LVS_NOCOLUMNHEADER, False, False)
    ; reorder listview columns order to match header items order
    Local $aOrder = _GUICtrlHeader_GetOrderArray($g_hHeader)
    _GUICtrlListView_SetColumnOrderArray($g_hListview, $aOrder)
    ; add LVS_NOCOLUMNHEADER back to listview
    __WinAPI_Set_Window_Style($g_hListView, $LVS_NOCOLUMNHEADER, True, False)
    _resizeHeaderItems() ; avoid a bad behavior if header item on the left is dropped elsewhere when horizontal scrollbar had been moved.

EndFunc   ;==>_reorderLVCols

;==============================================
Func __WinAPI_Set_Window_Style($hWnd, $i_Style, $b_Add, $b_exStyle = False) ; compacted code (from Kafu's original)
    If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
    Local $iIndex = $b_exStyle ? $GWL_EXSTYLE : $GWL_STYLE ; $iIndex as named by msdn & help file
    Local $i_Style_Old = _WinAPI_GetWindowLong($hWnd, $iIndex)

    If $b_Add Then
        If BitAND($i_Style_Old, $i_Style) Then Return ; style already applied
        _WinAPI_SetWindowLong($hWnd, $iIndex, BitOR($i_Style_Old, $i_Style))
    Else ; remove
        If Not BitAND($i_Style_Old, $i_Style) Then Return ; style not set
        _WinAPI_SetWindowLong($hWnd, $iIndex, BitXOR($i_Style_Old, $i_Style))
    EndIf

    Local $iRet = _WinAPI_SetWindowPos($hWnd, $HWND_TOP, 0, 0, 0, 0, BitOR($SWP_FRAMECHANGED, $SWP_NOACTIVATE, $SWP_NOMOVE, $SWP_NOSIZE, $SWP_NOZORDER)) ; +++
    If Not $iRet Then MsgBox($MB_TOPMOST, "_WinAPI_SetWindowPos", "Error = " & _WinAPI_GetLastError() & "   Message = " & _WinAPI_GetLastErrorMessage())
EndFunc   ;==>__WinAPI_Set_Window_Style

;==============================================
Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam

    Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    Local $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    Local $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $g_hHeader
            Switch $iCode
                Case $HDN_TRACK, $HDN_TRACKW
                    Local $tNMHEADER = DllStructCreate($tagNMHEADER, $lParam)
                    Local $iHeaderItem = $tNMHEADER.Item
                    Local $tHDITEM = DllStructCreate($tagHDITEM, $tNMHEADER.pItem)
                    Local $iHeaderItemWidth = $tHDITEM.XY
                    _GUICtrlHeader_SetItemWidth($g_hHeader, $iHeaderItem, $iHeaderItemWidth)
                    _resizeLVCols()
                    Return False ; to continue tracking the divider

                Case $HDN_ENDDRAG
                    $g_bHeaderEndDrag = True
                    Return False ; to allow the control to automatically place and reorder the item
            EndSwitch

        Case $g_hListView
            Switch $iCode
                Case $LVN_ENDSCROLL
                    Local Static $tagNMLVSCROLL = $tagNMHDR & ";int dx;int dy"
                    Local $tNMLVSCROLL = DllStructCreate($tagNMLVSCROLL, $lParam)
                    If $tNMLVSCROLL.dy = 0 Then ; ListView horizontal scrolling
                        _resizeHeaderItems()
                    EndIf
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

 

"I think you are searching a bug where there is no bug... don't listen to bad advice."

Posted

for changing the size of the window I put this,
but for GUIFrame_  I couldn't find where to put it

While True
    Local $iMsg = GUIGetMsg()
    Switch $iMsg
        Case -3 ;$GUI_EVENT_CLOSE
            __TreeListExplorer_Shutdown()
            Exit
        Case  -12 ;$GUI_EVENT_RESIZED
            Local $aClientSize = WinGetClientSize($hChildLV)
            ConsoleWrite("SetWindowPos=" & _WinAPI_SetWindowPos($g_hHeader, 0, 0, 0, $aClientSize[0], 25, BitOR($SWP_NOZORDER, $SWP_NOACTIVATE)) & @CRLF)
    EndSwitch
WEnd

 

I know that I know nothing

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
×
×
  • Create New...