WildByDesign Posted July 8 Posted July 8 I have a need for my GUI to be black (black background, light text) for applying Windows 11 backdrop materials. I use a script from @pixelsearch that allows customizing the colors of the statusbar and everything works beautifully. Until recently, I also had a need for using _GUICtrlStatusBar_EmbedControl to embed a combobox on the statusbar. I also realized that adding text with labels to the statusbar with _GUICtrlStatusBar_EmbedControl gave better control over fonts, DPI scaling, etc. Anyway, statusbar Part 0 is as expected with black background. Part 1 is just an example with a smaller sized label showing how the embed changes the coloring (font and background). Parts 2 and 3 are label and stretched. I have tried making the labels transparent or setting specific colors, but the _GUICtrlStatusBar_EmbedControl automatically reverts those colors. If anybody has any ideas or solutions for this problem, please let me know. Thank you so much. Script: Spoiler expandcollapse popup#include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <GuiStatusBar.au3> #include <StaticConstants.au3> #include <WinAPIGdi.au3> #include <WinAPIRes.au3> #include <WinAPISysWin.au3> #include <WinAPITheme.au3> #include <WindowsConstants.au3> #include <ComboConstants.au3> #include <EditConstants.au3> #include <GuiComboBox.au3> #include <FontConstants.au3> Opt("MustDeclareVars", 1) Global $hGUI, $g_hSizebox, $g_hOldProc, $g_hStatus, $g_iHeight, $g_aText, $g_aRatioW, $g_iBkColor, $g_iTextColor, $g_hDots ; Global $g_hBrush ; no need, as _GUICtrlStatusBar_SetBkColor() placed after _WinAPI_SetWindowTheme() does the job correctly Global $idInput, $idComboBox Example() ;============================================== Func Example() _GDIPlus_Startup() Local Const $SBS_SIZEBOX = 0x08, $SBS_SIZEGRIP = 0x10 Local $iW = 800, $iH = 600 Dim $g_iBkColor = 0x00000000, $g_iTextColor = 0xFFFFFF $hGUI = GUICreate("Resize corner", $iW, $iH, -1, -1) GUISetBkColor($g_iBkColor) GUICtrlSetDefColor(0xffffff) GUISetFont(9, $FW_NORMAL, $GUI_FONTNORMAL, "Segoe UI") ;----------------- ; Create a sizebox window (Scrollbar class) BEFORE creating the StatusBar control $g_hSizebox = _WinAPI_CreateWindowEx(0, "Scrollbar", "", $WS_CHILD + $WS_VISIBLE + $SBS_SIZEBOX, _ 0, 0, 0, 0, $hGUI) ; $SBS_SIZEBOX or $SBS_SIZEGRIP ; Subclass the sizebox (by changing the window procedure associated with the Scrollbar class) Local $hProc = DllCallbackRegister('ScrollbarProc', 'lresult', 'hwnd;uint;wparam;lparam') $g_hOldProc = _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, DllCallbackGetPtr($hProc)) Local $hCursor = _WinAPI_LoadCursor(0, $OCR_SIZENWSE) _WinAPI_SetClassLongEx($g_hSizebox, -12, $hCursor) ; $GCL_HCURSOR = -12 ; $g_hBrush = _WinAPI_CreateSolidBrush($g_iBkColor) ;----------------- $g_hStatus = _GUICtrlStatusBar_Create($hGUI, -1, "", $WS_CLIPSIBLINGS) ; ClipSiblings style +++ Local $aParts[4] = [200, 400, 600, -1] If $aParts[Ubound($aParts) - 1] = -1 Then $aParts[Ubound($aParts) - 1] = $iW ; client width size _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts) Dim $g_aText[Ubound($aParts)] = ["Part 0", "", "", ""] Dim $g_aRatioW[Ubound($aParts)] For $i = 0 To UBound($g_aText) - 1 _GUICtrlStatusBar_SetText($g_hStatus, "", $i, $SBT_OWNERDRAW) ; _GUICtrlStatusBar_SetText($g_hStatus, "", $i, $SBT_OWNERDRAW + $SBT_NOBORDERS) ; interesting ? $g_aRatioW[$i] = $aParts[$i] / $iW Next ; to allow the setting of StatusBar BkColor at least under Windows 10 _WinAPI_SetWindowTheme($g_hStatus, "", "") ; Set status bar background color _GUICtrlStatusBar_SetBkColor($g_hStatus, $g_iBkColor) $g_iHeight = _GUICtrlStatusBar_GetHeight($g_hStatus) + 3 ; change the constant (+3) if necessary $g_hDots = CreateDots($g_iHeight, $g_iHeight, 0xFF000000 + $g_iBkColor, 0xFF000000 + $g_iTextColor) ;Local $idInput = GUICtrlCreateInput("embed", 0, 0) ;Local $hInput = GUICtrlGetHandle($idInput) $idComboBox = GUICtrlCreateCombo("Install", 10, 10, 185, 20, $CBS_DROPDOWNLIST) GUICtrlSetState(-1, $GUI_HIDE) ;Local $hidComboBox = GUICtrlGetHandle($idComboBox) ;GUICtrlSetData($idComboBox, "Uninstall") $idInput = GUICtrlCreateInput("Startup Task ▼", 20, 40, 340, 20, $ES_READONLY, 0) ;Local $idPart0 = GUICtrlCreateLabel("Part 0", 0, 0, -1, -1) GUICtrlSetColor(-1, 0xffffff) Local $idPart1 = GUICtrlCreateLabel("Part 1", 0, 0, -1, -1) Local $idPart2 = GUICtrlCreateLabel("Part 2", 0, 0, -1, -1) ;Local $hInput = GUICtrlGetHandle($idInput) _GUICtrlStatusBar_EmbedControl($g_hStatus, 3, GUICtrlGetHandle($idComboBox), 4) _GUICtrlStatusBar_EmbedControl($g_hStatus, 3, GUICtrlGetHandle($idInput), 4) _GUICtrlStatusBar_EmbedControl($g_hStatus, 2, GUICtrlGetHandle($idPart2), 4) _GUICtrlStatusBar_EmbedControl($g_hStatus, 1, GUICtrlGetHandle($idPart1), 1 + 2) ;_GUICtrlStatusBar_EmbedControl($g_hStatus, 0, GUICtrlGetHandle($idPart0), 1) GUIRegisterMsg($WM_SIZE, "WM_SIZE") GUIRegisterMsg($WM_MOVE, "WM_MOVE") GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM") GUIRegisterMsg($WM_COMMAND, "ED_WM_COMMAND") GUICtrlSendMsg( $idComboBox, $WM_CHANGEUISTATE, 65537, 0 ) GUISetState() While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $idComboBox ;GUICtrlSetData($idInput, GUICtrlRead($idComboBox)) Local $comboread = GUICtrlRead($idComboBox) If $comboread = "Install" Then ConsoleWrite("you choose to install task" & @CRLF) GUICtrlSetData($idComboBox, "") GUICtrlSetData($idComboBox, "Uninstall") GUICtrlSetData($idPart2, "installed") EndIf If $comboread = "Uninstall" Then ConsoleWrite("you choose to uninstall task" & @CRLF) GUICtrlSetData($idComboBox, "") GUICtrlSetData($idComboBox, "Install") GUICtrlSetData($idPart2, "not installed") EndIf EndSwitch WEnd _GDIPlus_BitmapDispose($g_hDots) _GUICtrlStatusBar_Destroy($g_hStatus) _WinAPI_DestroyCursor($hCursor) ; _WinAPI_DeleteObject($g_hBrush) _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, $g_hOldProc) DllCallbackFree($hProc) _GDIPlus_Shutdown() EndFunc ;==>Example ;============================================== Func ScrollbarProc($hWnd, $iMsg, $wParam, $lParam) ; Andreik If $iMsg = $WM_PAINT Then Local $tPAINTSTRUCT Local $hDC = _WinAPI_BeginPaint($hWnd, $tPAINTSTRUCT) Local $iWidth = DllStructGetData($tPAINTSTRUCT, 'rPaint', 3) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 1) Local $iHeight = DllStructGetData($tPAINTSTRUCT, 'rPaint', 4) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 2) Local $hGraphics = _GDIPlus_GraphicsCreateFromHDC($hDC) _GDIPlus_GraphicsDrawImageRect($hGraphics, $g_hDots, 0, 0, $iWidth, $iHeight) _GDIPlus_GraphicsDispose($hGraphics) _WinAPI_EndPaint($hWnd, $tPAINTSTRUCT) Return 0 EndIf Return _WinAPI_CallWindowProc($g_hOldProc, $hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>ScrollbarProc ;============================================== Func CreateDots($iWidth, $iHeight, $iBackgroundColor, $iDotsColor) ; Andreik Local $iDotSize = Int($iHeight / 10) Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight) Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap) Local $hBrush = _GDIPlus_BrushCreateSolid($iDotsColor) _GDIPlus_GraphicsClear($hGraphics, $iBackgroundColor) Local $a[6][2] = [[2,6], [2,4], [2,2], [4,4], [4,2], [6,2]] For $i = 0 To UBound($a) - 1 _GDIPlus_GraphicsFillRect($hGraphics, $iWidth - $iDotSize * $a[$i][0], $iHeight - $iDotSize * $a[$i][1], $iDotSize, $iDotSize, $hBrush) Next _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hGraphics) Return $hBitmap EndFunc ;==>CreateDots ;============================================== Func _MyGUICtrlStatusBar_SetParts($hWnd, $aPartEdge) ; Pixelsearch If Not IsArray($aPartEdge) Then Return False Local $iParts = UBound($aPartEdge) Local $tParts = DllStructCreate("int[" & $iParts & "]") For $i = 0 To $iParts - 1 DllStructSetData($tParts, 1, $aPartEdge[$i], $i + 1) Next DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", $SB_SETPARTS, "wparam", $iParts, "struct*", $tParts) _GUICtrlStatusBar_Resize($hWnd) Return True EndFunc ;==>_MyGUICtrlStatusBar_SetParts ;============================================== Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) ; Pixelsearch #forceref $iMsg, $wParam, $lParam If $hWnd = $hGUI Then Local Static $bIsSizeBoxShown = True Local $aSize = WinGetClientSize($hGUI) Local $aGetParts = _GUICtrlStatusBar_GetParts($g_hStatus) Local $aParts[$aGetParts[0]] For $i = 0 To $aGetParts[0] - 1 $aParts[$i] = Int($aSize[0] * $g_aRatioW[$i]) Next If BitAND(WinGetState($hGUI), $WIN_STATE_MAXIMIZED) Then _GUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until GUI right border (AutoIt function forces it) _WinAPI_ShowWindow($g_hSizebox, @SW_HIDE) $bIsSizeBoxShown = False Else If $g_aRatioW[UBound($aParts) -1] <> 1 Then $aParts[UBound($aParts) -1] = $aSize[0] - $g_iHeight ; right size of right part stuck on sizebox (no gap) _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until sizebox (see preceding line) or until GUI right border WinMove($g_hSizebox, "", $aSize[0] - $g_iHeight, $aSize[1] - $g_iHeight, $g_iHeight, $g_iHeight) If Not $bIsSizeBoxShown Then _WinAPI_ShowWindow($g_hSizebox, @SW_SHOW) $bIsSizeBoxShown = True EndIf EndIf EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_SIZE ;============================================== Func WM_MOVE($hWnd, $iMsg, $wParam, $lParam) #forceref $iMsg, $wParam, $lParam If $hWnd = $hGUI Then _WinAPI_RedrawWindow($g_hSizebox) EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_MOVE ;============================================== Func WM_DRAWITEM($hWnd, $iMsg, $wParam, $lParam) ; Kafu #forceref $hWnd, $iMsg, $wParam Local Static $tagDRAWITEM = "uint CtlType;uint CtlID;uint itemID;uint itemAction;uint itemState;hwnd hwndItem;handle hDC;long rcItem[4];ulong_ptr itemData" Local $tDRAWITEM = DllStructCreate($tagDRAWITEM, $lParam) If $tDRAWITEM.hwndItem <> $g_hStatus Then Return $GUI_RUNDEFMSG ; only process the statusbar Local $itemID = $tDRAWITEM.itemID ; status bar part number : 0 if simple bar (or 0, 1, 2... if multi parts) Local $hDC = $tDRAWITEM.hDC Local $tRect = DllStructCreate("long left;long top;long right;long bottom", DllStructGetPtr($tDRAWITEM, "rcItem")) ; _WinAPI_FillRect($hDC, DllStructGetPtr($tRect), $g_hBrush) ; backgound color _WinAPI_SetTextColor($hDC, $g_iTextColor) ; text color _WinAPI_SetBkMode($hDC, $TRANSPARENT) DllStructSetData($tRect, "top", $tRect.top + 1) DllStructSetData($tRect, "left", $tRect.left + 1) _WinAPI_DrawText($hDC, $g_aText[$itemID], $tRect, $DT_LEFT) Return $GUI_RUNDEFMSG EndFunc ;==>WM_DRAWITEM Func ED_WM_COMMAND($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg Local $iCode = BitShift($wParam, 16) Switch $lParam Case GUICtrlGetHandle($idInput) Switch $iCode Case $EN_SETFOCUS ;GUICtrlSetData($hLabel, "Edit has focus") ConsoleWrite("Edit has focus" & @CRLF) _GUICtrlComboBox_ShowDropDown($idComboBox, True) ControlFocus($hGUI, "", $idComboBox) Case $EN_KILLFOCUS ;GUICtrlSetData($hLabel, "Edit does not have focus") ConsoleWrite("Edit does not have focus" & @CRLF) EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>ED_WM_COMMAND
pixelsearch Posted July 9 Posted July 9 Hi, I opened the include file GuiStatusBar.au3 to have a look at the code in _GUICtrlStatusBar_EmbedControl() If you look at the code, it simply computes the position and size of the embedded control, relative to the status bar part. At the very end of the function, we find this : _WinAPI_SetParent($hControl, $hWnd) _WinAPI_MoveWindow($hControl, $iConX, $iConY, $iConW, $iConH) So it seems that changing the parent of a control doesn't display the original colors of the control (?) If we create a simpler example, it confirms this behavior : #include <ButtonConstants.au3> #include <GUIConstantsEx.au3> #include <WinAPIGdi.au3> #include <WinAPISysWin.au3> $hGUI = GUICreate("Test", 340, 200) $idButton1 = GUICtrlCreateButton("Button 1 line", 30, 10, 80, 30) ; GUICtrlSetStyle(-1, 0) ; for fun, the easiest way to make the preceding button non tabbable $idButton2 = GUICtrlCreateButton("Button" & @CRLF & "2 lines", 130, 10, 80, 40, $BS_MULTILINE) $idLabel = GUICtrlCreateLabel("Label here", 230, 10, 80, 50) $hLabel = GUICtrlGetHandle($idLabel) GUICtrlSetBkColor(-1, 0xFF0000) ; red... when its parent is $hGUI GUISetState() While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE Exit Case $idButton1 _WinAPI_SetParent($hLabel, GUICtrlGetHandle($idButton1)) _WinAPI_MoveWindow($hLabel, 3, 3, 30, 24) Case $idButton2 _WinAPI_SetParent($hLabel, $hGUI) EndSwitch WEnd 1) A click on button 1 changes the parent of the label control : now button 1 is the parent, the label lost its red background color and is displayed at new coords relative to the top left corner of button 1, its new parent. 2) A click on button 2 reverts the parent to the original $hGUI, the red background reappears and the position / size of the label corresponds to the last coords assigned to the label (now relative to the client part of the GUI) So if someone knows how to force colors to reappear just after a parent change, please indicate how to do it, thanks ! Let's hope there is some kind of redrawing that can solve it. For the record, _WinAPI_SetBkColor didn't make it. @WildByDesign if noone offers a solution, then maybe you could try to bypass _WinAPI_SetParent and place your control(s) directly at their final coords in the status bar. I tested it by placing a copy of _GUICtrlStatusBar_EmbedControl (renamed) in the script, just to return the coords computed by the function (commenting out the 2 last lines of the function) etc... The colors were here of course. 6 hours ago, WildByDesign said: I also realized that adding text with labels to the statusbar with _GUICtrlStatusBar_EmbedControl gave better control over fonts, DPI scaling, etc. So this could mean that you have to use _WinAPI_SetParent after all, to display better controls in your case (?) Good luck WildByDesign 1 "I think you are searching a bug where there is no bug... don't listen to bad advice."
WildByDesign Posted July 9 Author Posted July 9 Thank you for the deep dive into this issue, @pixelsearch. You always have a way of providing concise code examples to identify whatever it is that needs to be identified. 6 hours ago, pixelsearch said: So it seems that changing the parent of a control doesn't display the original colors of the control (?) If we create a simpler example, it confirms this behavior : Indeed, yes. You've confirmed that the theming issue comes from the _WinAPI_SetParent. That helps narrow things down. I was reading the Remarks section (SetParent function (winuser.h) - Win32 apps | Microsoft Learn) of the msdn info for SetParent. But I honestly don't have a very good understanding of it. My assumption is that it is essentially undoing the ownerdrawn parts that you had initially helped to create. I tried position the _GUICtrlStatusBar_EmbedControl lines before the ownerdrawn parts section hoping that it might keep the theming created from there, but no luck. 6 hours ago, pixelsearch said: maybe you could try to bypass _WinAPI_SetParent and place your control(s) directly at their final coords in the status bar. I tested it by placing a copy of _GUICtrlStatusBar_EmbedControl (renamed) in the script, just to return the coords computed by the function (commenting out the 2 last lines of the function) etc... The colors were here of course. I tried this right now by create a renamed version of that function within my script and commenting out the _WinAPI_SetParent line. I kept the _WinAPI_MoveWindow line to move the controls to the correct locations of the statusbar parts. The only problem is that it put them all at the top of the GUI window but it did space them apart correctly. I tried manually adding the lower coordinate of the status bar like this: _WinAPI_MoveWindow($hControl, $iConX, 574, $iConW, $iConH) This did actually place all of the controls to the right locations on the statusbar. Everything appeared perfect, visually. However, for whatever reason, the input box and combobox both became non-functional. I confirmed with System Information (Window details) that the controls were indeed all exactly where they were intended to be. But the input box was still not clickable on the statusbar when moved manually like this. But when _WinAPI_SetParent was being used, the input/combo controls were functional. So I am not sure what the problem is with this method. Here is the current example. Run the script as-is and everything works properly, particularly try the Startup Task combo/input in the status bar. Now, at the very bottom of the script, comment out both _WinAPI_SetParent and _WinAPI_MoveWindow and then uncomment the _WinAPI_MoveWindow line that has the 574 coordinate in it. Run the script again and see that the statusbar looks correct visually but notice that the Startup Task combo/input no longer works. Script: Spoiler expandcollapse popup#include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <GuiStatusBar.au3> #include <StaticConstants.au3> #include <WinAPIGdi.au3> #include <WinAPIRes.au3> #include <WinAPISysWin.au3> #include <WinAPITheme.au3> #include <WindowsConstants.au3> #include <ComboConstants.au3> #include <EditConstants.au3> #include <GuiComboBox.au3> #include <FontConstants.au3> Opt("MustDeclareVars", 1) Global $hGUI, $g_hSizebox, $g_hOldProc, $g_hStatus, $g_iHeight, $g_aText, $g_aRatioW, $g_iBkColor, $g_iTextColor, $g_hDots ; Global $g_hBrush ; no need, as _GUICtrlStatusBar_SetBkColor() placed after _WinAPI_SetWindowTheme() does the job correctly Global $idInput, $idComboBox Example() ;============================================== Func Example() _GDIPlus_Startup() Local Const $SBS_SIZEBOX = 0x08, $SBS_SIZEGRIP = 0x10 Local $iW = 800, $iH = 600 Dim $g_iBkColor = 0x000000, $g_iTextColor = 0xFFFFFF $hGUI = GUICreate("Resize corner", $iW, $iH, -1, -1) GUISetBkColor($g_iBkColor) GUICtrlSetDefColor(0xffffff) GUISetFont(9, $FW_NORMAL, $GUI_FONTNORMAL, "Segoe UI") ;----------------- ; Create a sizebox window (Scrollbar class) BEFORE creating the StatusBar control $g_hSizebox = _WinAPI_CreateWindowEx(0, "Scrollbar", "", $WS_CHILD + $WS_VISIBLE + $SBS_SIZEBOX, _ 0, 0, 0, 0, $hGUI) ; $SBS_SIZEBOX or $SBS_SIZEGRIP ; Subclass the sizebox (by changing the window procedure associated with the Scrollbar class) Local $hProc = DllCallbackRegister('ScrollbarProc', 'lresult', 'hwnd;uint;wparam;lparam') $g_hOldProc = _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, DllCallbackGetPtr($hProc)) Local $hCursor = _WinAPI_LoadCursor(0, $OCR_SIZENWSE) _WinAPI_SetClassLongEx($g_hSizebox, -12, $hCursor) ; $GCL_HCURSOR = -12 ; $g_hBrush = _WinAPI_CreateSolidBrush($g_iBkColor) ;----------------- $g_hStatus = _GUICtrlStatusBar_Create($hGUI, -1, "", $WS_CLIPSIBLINGS) ; ClipSiblings style +++ Local $aParts[4] = [200, 400, 600, -1] If $aParts[Ubound($aParts) - 1] = -1 Then $aParts[Ubound($aParts) - 1] = $iW ; client width size _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts) Dim $g_aText[Ubound($aParts)] = ["Part 0", "", "", ""] Dim $g_aRatioW[Ubound($aParts)] For $i = 0 To UBound($g_aText) - 1 _GUICtrlStatusBar_SetText($g_hStatus, "", $i, $SBT_OWNERDRAW) ; _GUICtrlStatusBar_SetText($g_hStatus, "", $i, $SBT_OWNERDRAW + $SBT_NOBORDERS) ; interesting ? $g_aRatioW[$i] = $aParts[$i] / $iW Next ; to allow the setting of StatusBar BkColor at least under Windows 10 _WinAPI_SetWindowTheme($g_hStatus, "", "") ; Set status bar background color _GUICtrlStatusBar_SetBkColor($g_hStatus, $g_iBkColor) $g_iHeight = _GUICtrlStatusBar_GetHeight($g_hStatus) + 3 ; change the constant (+3) if necessary $g_hDots = CreateDots($g_iHeight, $g_iHeight, 0xFF000000 + $g_iBkColor, 0xFF000000 + $g_iTextColor) ;Local $idInput = GUICtrlCreateInput("embed", 0, 0) ;Local $hInput = GUICtrlGetHandle($idInput) $idComboBox = GUICtrlCreateCombo("Install", 0, 0, 185, 20, $CBS_DROPDOWNLIST) GUICtrlSetState(-1, $GUI_HIDE) ;Local $hidComboBox = GUICtrlGetHandle($idComboBox) ;GUICtrlSetData($idComboBox, "Uninstall") $idInput = GUICtrlCreateInput("Startup Task ▼", 0, 0, 340, 20, $ES_READONLY, 0) GUICtrlSetBkColor(-1, 0x000000) Local $idPart0 = GUICtrlCreateLabel("Part 0", 0, 0, -1, -1) GUICtrlSetColor(-1, 0xffffff) Local $idPart1 = GUICtrlCreateLabel("Part 1", 0, 0, -1, -1) Local $idPart2 = GUICtrlCreateLabel("Part 2", 0, 0, -1, -1) ;Local $hInput = GUICtrlGetHandle($idInput) _GUICtrlStatusBar_EmbedControlEx($g_hStatus, 3, GUICtrlGetHandle($idComboBox), 4) _GUICtrlStatusBar_EmbedControlEx($g_hStatus, 3, GUICtrlGetHandle($idInput), 4) _GUICtrlStatusBar_EmbedControlEx($g_hStatus, 2, GUICtrlGetHandle($idPart2), 4) _GUICtrlStatusBar_EmbedControlEx($g_hStatus, 1, GUICtrlGetHandle($idPart1), 4) _GUICtrlStatusBar_EmbedControlEx($g_hStatus, 0, GUICtrlGetHandle($idPart0), 4) GUIRegisterMsg($WM_SIZE, "WM_SIZE") GUIRegisterMsg($WM_MOVE, "WM_MOVE") GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM") GUIRegisterMsg($WM_COMMAND, "ED_WM_COMMAND") GUICtrlSendMsg( $idComboBox, $WM_CHANGEUISTATE, 65537, 0 ) GUISetState() While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $idComboBox ;GUICtrlSetData($idInput, GUICtrlRead($idComboBox)) Local $comboread = GUICtrlRead($idComboBox) If $comboread = "Install" Then ConsoleWrite("you choose to install task" & @CRLF) GUICtrlSetData($idComboBox, "") GUICtrlSetData($idComboBox, "Uninstall") GUICtrlSetData($idPart2, "installed") EndIf If $comboread = "Uninstall" Then ConsoleWrite("you choose to uninstall task" & @CRLF) GUICtrlSetData($idComboBox, "") GUICtrlSetData($idComboBox, "Install") GUICtrlSetData($idPart2, "not installed") EndIf EndSwitch WEnd _GDIPlus_BitmapDispose($g_hDots) _GUICtrlStatusBar_Destroy($g_hStatus) _WinAPI_DestroyCursor($hCursor) ; _WinAPI_DeleteObject($g_hBrush) _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, $g_hOldProc) DllCallbackFree($hProc) _GDIPlus_Shutdown() EndFunc ;==>Example ;============================================== Func ScrollbarProc($hWnd, $iMsg, $wParam, $lParam) ; Andreik If $iMsg = $WM_PAINT Then Local $tPAINTSTRUCT Local $hDC = _WinAPI_BeginPaint($hWnd, $tPAINTSTRUCT) Local $iWidth = DllStructGetData($tPAINTSTRUCT, 'rPaint', 3) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 1) Local $iHeight = DllStructGetData($tPAINTSTRUCT, 'rPaint', 4) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 2) Local $hGraphics = _GDIPlus_GraphicsCreateFromHDC($hDC) _GDIPlus_GraphicsDrawImageRect($hGraphics, $g_hDots, 0, 0, $iWidth, $iHeight) _GDIPlus_GraphicsDispose($hGraphics) _WinAPI_EndPaint($hWnd, $tPAINTSTRUCT) Return 0 EndIf Return _WinAPI_CallWindowProc($g_hOldProc, $hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>ScrollbarProc ;============================================== Func CreateDots($iWidth, $iHeight, $iBackgroundColor, $iDotsColor) ; Andreik Local $iDotSize = Int($iHeight / 10) Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight) Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap) Local $hBrush = _GDIPlus_BrushCreateSolid($iDotsColor) _GDIPlus_GraphicsClear($hGraphics, $iBackgroundColor) Local $a[6][2] = [[2,6], [2,4], [2,2], [4,4], [4,2], [6,2]] For $i = 0 To UBound($a) - 1 _GDIPlus_GraphicsFillRect($hGraphics, $iWidth - $iDotSize * $a[$i][0], $iHeight - $iDotSize * $a[$i][1], $iDotSize, $iDotSize, $hBrush) Next _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hGraphics) Return $hBitmap EndFunc ;==>CreateDots ;============================================== Func _MyGUICtrlStatusBar_SetParts($hWnd, $aPartEdge) ; Pixelsearch If Not IsArray($aPartEdge) Then Return False Local $iParts = UBound($aPartEdge) Local $tParts = DllStructCreate("int[" & $iParts & "]") For $i = 0 To $iParts - 1 DllStructSetData($tParts, 1, $aPartEdge[$i], $i + 1) Next DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", $SB_SETPARTS, "wparam", $iParts, "struct*", $tParts) _GUICtrlStatusBar_Resize($hWnd) Return True EndFunc ;==>_MyGUICtrlStatusBar_SetParts ;============================================== Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) ; Pixelsearch #forceref $iMsg, $wParam, $lParam If $hWnd = $hGUI Then Local Static $bIsSizeBoxShown = True Local $aSize = WinGetClientSize($hGUI) Local $aGetParts = _GUICtrlStatusBar_GetParts($g_hStatus) Local $aParts[$aGetParts[0]] For $i = 0 To $aGetParts[0] - 1 $aParts[$i] = Int($aSize[0] * $g_aRatioW[$i]) Next If BitAND(WinGetState($hGUI), $WIN_STATE_MAXIMIZED) Then _GUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until GUI right border (AutoIt function forces it) _WinAPI_ShowWindow($g_hSizebox, @SW_HIDE) $bIsSizeBoxShown = False Else If $g_aRatioW[UBound($aParts) -1] <> 1 Then $aParts[UBound($aParts) -1] = $aSize[0] - $g_iHeight ; right size of right part stuck on sizebox (no gap) _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until sizebox (see preceding line) or until GUI right border WinMove($g_hSizebox, "", $aSize[0] - $g_iHeight, $aSize[1] - $g_iHeight, $g_iHeight, $g_iHeight) If Not $bIsSizeBoxShown Then _WinAPI_ShowWindow($g_hSizebox, @SW_SHOW) $bIsSizeBoxShown = True EndIf EndIf EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_SIZE ;============================================== Func WM_MOVE($hWnd, $iMsg, $wParam, $lParam) #forceref $iMsg, $wParam, $lParam If $hWnd = $hGUI Then _WinAPI_RedrawWindow($g_hSizebox) EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_MOVE ;============================================== Func WM_DRAWITEM($hWnd, $iMsg, $wParam, $lParam) ; Kafu #forceref $hWnd, $iMsg, $wParam Local Static $tagDRAWITEM = "uint CtlType;uint CtlID;uint itemID;uint itemAction;uint itemState;hwnd hwndItem;handle hDC;long rcItem[4];ulong_ptr itemData" Local $tDRAWITEM = DllStructCreate($tagDRAWITEM, $lParam) If $tDRAWITEM.hwndItem <> $g_hStatus Then Return $GUI_RUNDEFMSG ; only process the statusbar Local $itemID = $tDRAWITEM.itemID ; status bar part number : 0 if simple bar (or 0, 1, 2... if multi parts) Local $hDC = $tDRAWITEM.hDC Local $tRect = DllStructCreate("long left;long top;long right;long bottom", DllStructGetPtr($tDRAWITEM, "rcItem")) ; _WinAPI_FillRect($hDC, DllStructGetPtr($tRect), $g_hBrush) ; backgound color _WinAPI_SetTextColor($hDC, $g_iTextColor) ; text color _WinAPI_SetBkMode($hDC, $TRANSPARENT) DllStructSetData($tRect, "top", $tRect.top + 1) DllStructSetData($tRect, "left", $tRect.left + 1) _WinAPI_DrawText($hDC, $g_aText[$itemID], $tRect, $DT_LEFT) Return $GUI_RUNDEFMSG EndFunc ;==>WM_DRAWITEM Func ED_WM_COMMAND($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg Local $iCode = BitShift($wParam, 16) Switch $lParam Case GUICtrlGetHandle($idInput) Switch $iCode Case $EN_SETFOCUS ;GUICtrlSetData($hLabel, "Edit has focus") ConsoleWrite("Edit has focus" & @CRLF) _GUICtrlComboBox_ShowDropDown($idComboBox, True) ControlFocus($hGUI, "", $idComboBox) Case $EN_KILLFOCUS ;GUICtrlSetData($hLabel, "Edit does not have focus") ConsoleWrite("Edit does not have focus" & @CRLF) EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>ED_WM_COMMAND ; #FUNCTION# ==================================================================================================================== ; Author ........: Paul Campbell (PaulIA) ; Modified.......: ; =============================================================================================================================== Func _GUICtrlStatusBar_EmbedControlEx($hWnd, $iPart, $hControl, $iFit = 4) Local $aRect = _GUICtrlStatusBar_GetRect($hWnd, $iPart) Local $iBarX = $aRect[0] Local $iBarY = $aRect[1] Local $iBarW = $aRect[2] - $iBarX Local $iBarH = $aRect[3] - $iBarY Local $iConX = $iBarX Local $iConY = $iBarY Local $iConW = _WinAPI_GetWindowWidth($hControl) Local $iConH = _WinAPI_GetWindowHeight($hControl) If $iConW > $iBarW Then $iConW = $iBarW If $iConH > $iBarH Then $iConH = $iBarH Local $iPadX = ($iBarW - $iConW) / 2 Local $iPadY = ($iBarH - $iConH) / 2 If $iPadX < 0 Then $iPadX = 0 If $iPadY < 0 Then $iPadY = 0 If BitAND($iFit, 1) = 1 Then $iConX = $iBarX + $iPadX If BitAND($iFit, 2) = 2 Then $iConY = $iBarY + $iPadY If BitAND($iFit, 4) = 4 Then $iPadX = _GUICtrlStatusBar_GetBordersRect($hWnd) $iPadY = _GUICtrlStatusBar_GetBordersVert($hWnd) $iConX = $iBarX If _GUICtrlStatusBar_IsSimple($hWnd) Then $iConX += $iPadX $iConY = $iBarY + $iPadY $iConW = $iBarW - ($iPadX * 2) $iConH = $iBarH - ($iPadY * 2) EndIf _WinAPI_SetParent($hControl, $hWnd) _WinAPI_MoveWindow($hControl, $iConX, $iConY, $iConW, $iConH) ;_WinAPI_MoveWindow($hControl, $iConX, 574, $iConW, $iConH) EndFunc ;==>_GUICtrlStatusBar_EmbedControlEx
WildByDesign Posted July 9 Author Posted July 9 I was testing a few things to see what options I have just in case this doesn't end up working. So I have a few observations. If I add the following right before GUISetState: _WinAPI_SetWindowTheme($g_hStatus, "Explorer") It themes the statusbar embedded parts well, including and importantly the combobox drop-down. Now, of course this destroys the nice ownerdrawn parts which therefore destroys the lovely dark statusbar. So I thought about trying the built-in Windows 10/11 statusbar dark mode. It looks like the screenshot here: Previously, you would enable dark mode statusbar with the following: _WinAPI_SetWindowTheme($g_hStatus, "DarkMode_Explorer", "Explorer") It used to work well, but of course with the thicker white border lines which were hard on the eyes. Light mode status bar used to be set with: _WinAPI_SetWindowTheme($g_hStatus, "Explorer", "Explorer") For whatever reason, on the latest stable channel Windows 11 24H2 with latest updates, both of these fail now when they used to work. The last argument "Explorer" is causing it to completely remove the statusbar theme now. It is essentially now equal to what you get with: _WinAPI_SetWindowTheme($g_hStatus, "", "") So now on latest Windows 11, you have to use it like this: _WinAPI_SetWindowTheme($g_hStatus, "DarkMode_Explorer") _WinAPI_SetWindowTheme($g_hStatus, "Explorer") However, both of those enable light mode themed statusbar only. It would seem that DarkMode statusbar has been removed from the latest Windows 11 updates. Either that, or the latest Windows 11 updates have completely changed how SetWindowTheme functions now.
WildByDesign Posted July 9 Author Posted July 9 (edited) I have also tried the unrestricted SetWindowTheme (_WinAPI_SetWindowTheme_unr) function from @argumentum and it also fails (or behaves differently) on latest Windows 11 stable channel. 24H2 Build 26100 .4652 Edited July 9 by WildByDesign
argumentum Posted July 9 Posted July 9 (edited) 3 hours ago, WildByDesign said: SetWindowTheme (_WinAPI_SetWindowTheme_unr) function from @argumentum and it also fails (or behaves differently) on latest Windows 11 stable channel. 24H2 Build 26100 .4652 My most awesome "_WinAPI_SetWindowTheme_unr()" is "_WinAPI_SetWindowTheme()" without the "child proofing", the rest is the standard WinAPI. If on 26100 .4652 things don't work, .. tell M$ ? The simple approach I gave you in the beginning was "fake it" and that's, what is in my vast ( or not ) knowledge of GUIs 🤯 Edited July 9 by argumentum English WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
WildByDesign Posted July 9 Author Posted July 9 33 minutes ago, argumentum said: The simple approach I gave you in the beginning was "fake it" and that's, what is in my vast ( or not ) knowledge of GUIs This is probably the best and maybe only approach for me now. I want to be able to release the GUI soon since it is very close to being done. This is really the main thing holding it back now. I am going to look over your previous “fake” status bar functions from the other thread now and get them to work with what I currently have. argumentum 1
WildByDesign Posted July 9 Author Posted July 9 (edited) 38 minutes ago, argumentum said: tell M$ ? This I agree with 100%. This should be the right way to go. However, after many past experiences of reporting things to M$, it is comparable to having a conversation with a goat. Edited July 9 by WildByDesign argumentum 1
argumentum Posted July 9 Posted July 9 ..I would not talk to them. Would be useless. They do what they do and we, ...we find a way around ¯\_(ツ)_/¯ WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
Solution pixelsearch Posted July 10 Solution Posted July 10 14 hours ago, WildByDesign said: This did actually place all of the controls to the right locations on the statusbar. Everything appeared perfect, visually. However, for whatever reason, the input box and combobox both became non-functional. I tried to add these 2 controls (combo & input box) to my script found in this post with good results, on a maximizable / resizable GUI : These are the lines modified / added to the script, so you can try them too : 1) Lines modified : ; Local $iW = 300, $iH = 100 Local $iW = 600, $iH = 200 ; Local $aParts[3] = [90, 180, 280] Local $aParts[3] = [200, 400, 580] ; Local $idChangeText = GUICtrlCreateLabel("Change Text", 110, 25, 80, 30, $SS_CENTER + $SS_CENTERIMAGE), $iInc Local $idChangeText = GUICtrlCreateLabel("Change Text", $iW / 2 - 40, 50, 80, 30, $SS_CENTER + $SS_CENTERIMAGE), $iInc 2) Lines added : #include <ComboConstants.au3> ... Local $idComboBox = GUICtrlCreateCombo("Install", 100, 180, 100, 18, $CBS_DROPDOWNLIST) GUICtrlSetData($idComboBox, "Uninstall") GUICtrlSetBkColor(-1, 0xFF0000) ; red _WinAPI_SetParent(GUICtrlGetHandle($idComboBox), $g_hGUI) Local $idInput = GUICtrlCreateInput("Input in part 1", 300, 181, 100, 18) GUICtrlSetBkColor(-1, 0x00FF00) ; green _WinAPI_SetParent(GUICtrlGetHandle($idInput), $g_hGUI) * Please create $idComboBox and $idInput just after the label $idChangeText * IIRC your StatusBar height got a higher value, so you'll probably have to lower a bit the Y coord of both controls * Lucky me, I tried the _WinAPI_SetParent() on each control (combo & input), indicating... the GUI as parent and it "woke" them up both. Without this instruction, they didn't react, as you indicated. Hope it will work on your side, fingers crossed argumentum, WildByDesign and ioa747 3 "I think you are searching a bug where there is no bug... don't listen to bad advice."
argumentum Posted July 10 Posted July 10 23 minutes ago, pixelsearch said: Hope it will work on your side, ...so, yes. It should work everywhere. When he claimed that something changed drastically ( not sure what ) I jumped into getting the latest to test and not make a fool of my self calling Bill to give him a piece of my mind !. Fortunately, I didn't have to 😇 pixelsearch and WildByDesign 2 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
WildByDesign Posted July 10 Author Posted July 10 6 hours ago, argumentum said: calling Bill to give him a piece of my mind !. Fortunately, I didn't have to 🤣 argumentum 1
WildByDesign Posted July 10 Author Posted July 10 (edited) 9 hours ago, pixelsearch said: Lucky me, I tried the _WinAPI_SetParent() on each control (combo & input), indicating... the GUI as parent and it "woke" them up both. Without this instruction, they didn't react, as you indicated. Hope it will work on your side, fingers crossed This did it. This solved my problem. It's funny, too, because _WinAPI_SetParent() was problematic at one point causing issues by destroying the theming. And now here comes _WinAPI_SetParent() to save the day by restoring the lovely theming. It blows my mind! Thank you so much for your help and for your time with this. I appreciate it, as always. You've saved me a few times now already. Now I can move on to the not-so-fun DPI awareness control sizing stuff. Edited July 10 by WildByDesign pixelsearch and argumentum 2
BugFix Posted July 11 Posted July 11 I've created a label based solution for a simple status bar. May be it's interesting 4u. https://github.com/BugFix/AutoIt-Scripts/blob/main/Statusbar/statusbar_small.md#gallery WildByDesign, pixelsearch and argumentum 3 Best Regards BugFix
WildByDesign Posted July 11 Author Posted July 11 (edited) 1 hour ago, BugFix said: I've created a label based solution for a simple status bar. May be it's interesting 4u. Your UDF is a nice option. Thanks for letting me know about it because I was not aware. It deserves more attention. By the way, is it possible to obtain a position on each of the parts? The reason why I ask is because I would like to be able to swap one or two of the parts with an input or combo control. Edited July 11 by WildByDesign
pixelsearch Posted July 11 Posted July 11 2 hours ago, BugFix said: I've created a label based solution for a simple status bar. Very interesting, thanks for sharing. "I think you are searching a bug where there is no bug... don't listen to bad advice."
BugFix Posted Saturday at 08:57 PM Posted Saturday at 08:57 PM On 7/11/2025 at 3:55 PM, WildByDesign said: By the way, is it possible to obtain a position on each of the parts? The reason why I ask is because I would like to be able to swap one or two of the parts with an input or combo control. By default, embedding other controls in my status bar is not provided. But some thoughts on this: The function "_StatusbarCreate" returns an array that contains, among other things, the IDs of all parts. The ID can be used to query the part's rectangle. One option would be to hide the original label and overlay it with another control at the determined position. Some optical corrections may still be necessary to achieve a uniform appearance. That is the solution I would choose. Good luck with your attempts. argumentum 1 Best Regards BugFix
WildByDesign Posted Saturday at 11:41 PM Author Posted Saturday at 11:41 PM I just found out the hard way that the _GUICtrlStatusBar_EmbedControl function has a terrible bug that renders it essentially useless. If you use the same example from (Function _GUICtrlStatusBar_EmbedControl), if you run the example, minimize the GUI and restore the GUI, the majority of the parts disappear and/or move to another area of the GUI. I wish that I noticed this a few days ago before I went all-in on it. 2 hours ago, BugFix said: The function "_StatusbarCreate" returns an array that contains, among other things, the IDs of all parts. The ID can be used to query the part's rectangle. One option would be to hide the original label and overlay it with another control at the determined position. Some optical corrections may still be necessary to achieve a uniform appearance. That is the solution I would choose. Good luck with your attempts. Thank you for this information. The fact that your UDF function provides an array with all of those details is fantastic. This might just save me from the broken statusbar situation that I currently have right now. I'm going to try your UDF now.
pixelsearch Posted Sunday at 12:46 AM Posted Sunday at 12:46 AM 59 minutes ago, WildByDesign said: just found out the hard way that the _GUICtrlStatusBar_EmbedControl function has a terrible bug that renders it essentially useless. If you use the same example from (Function _GUICtrlStatusBar_EmbedControl), if you run the example, minimize the GUI and restore the GUI, the majority of the parts disappear and/or move to another area of the GUI. I noticed that a couple of days ago but did not report, after we saw the issue in _GUICtrlStatusBar_EmbedControl which did not let you embed controls in your script, because of _WinAPI_SetParent() which change the parent of the embedded controls, then their background colors were not the ones you wanted. I'm sure other examples in the help file would need the same fix, e.g. to take care of the messages WM_SIZE / WM_MOVE when the GUI is resized, minimized etc... and calculate the position of these controls during the registered messages functions. WildByDesign 1 "I think you are searching a bug where there is no bug... don't listen to bad advice."
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