Jump to content

[solved] CheckBox in StatusBar (SetParent) - how to catch its event


Zedna
 Share

Go to solution Solved by Zedna,

Recommended Posts

When I have CheckBox in StatusBar using SetParent API then there is problem because you can't catch its event by standard GUIGetMsg().

I need help how to catch Check/UnCheck event in this case.

#AutoIt3Wrapper_UseX64=n
#NoTrayIcon

#include <GUIConstants.au3>
#include <GuiStatusBar.au3>

$Form1 = GUICreate("StatusBar Checkbox", 400, 300, -1, -1, BitOR($GUI_SS_DEFAULT_GUI,$WS_MAXIMIZEBOX,$WS_SIZEBOX))
$cbx1 = GUICtrlCreateCheckbox("Sum 1", 10, 100, 120, 20)
GUICtrlSetResizing($cbx1, $GUI_DOCKLEFT+$GUI_DOCKTOP+$GUI_DOCKWIDTH+$GUI_DOCKHEIGHT)
$cbx2 = GUICtrlCreateCheckbox("Sum 2", 3, 3, 58, 15)
GUICtrlSetResizing($cbx2, $GUI_DOCKALL)
$StatusBar1 = _GUICtrlStatusBar_Create($Form1)
Dim $sb1_PartsWidth[3] = [62, 200, -1]
_GUICtrlStatusBar_SetParts($StatusBar1, $sb1_PartsWidth)
_GuiCtrlStatusBar_Resize($StatusBar1)
_SetParent($cbx2, $StatusBar1) ; after this Checkbox doesn't fire event in GUIGetMsg()
GUISetState(@SW_SHOW)
GUIRegisterMsg($WM_SIZE, "WM_SIZE")

While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $cbx1
            MsgBox(64, 'cbx1', 'Checked: ' & IsChecked($cbx1)) ; OK
        Case $cbx2
            MsgBox(64, 'cbx2', 'Checked: ' & IsChecked($cbx2)) ; never fired
    EndSwitch
WEnd

Func WM_SIZE($hWnd, $Msg, $wParam, $lParam)
    _GuiCtrlStatusBar_Resize($StatusBar1)
    Return $GUI_RUNDEFMSG
EndFunc

Func _SetParent($ctrl_child, $ctrl_parent)
;~  $ctrl_parent = GUICtrlGetHandle($ctrl_parent)
    $ctrl_child = GUICtrlGetHandle($ctrl_child)
    DllCall("user32.dll", "hwnd", "SetParent", "hwnd", $ctrl_child, "hwnd", $ctrl_parent)
EndFunc

Func IsChecked($control)
    Return BitAnd(GUICtrlRead($control),$GUI_CHECKED) = $GUI_CHECKED
EndFunc

 

EDIT: Maybe some WM_COMMAND / WM_NOTIFY or SubClassing?

Edited by Zedna
solved
Link to comment
Share on other sites

Probably not the answer your looking for but, you could use ControlCommand and Adlibregister

Global $g_bCbx2 = False
;~ ...
AdlibRegister("_IsChecked")
;~ ...
Func _IsChecked()
    Local $bCbx2 = ControlCommand($Form1, "", $cbx2, "IsChecked") ? True : False
    If $g_bCbx2 <> $bCbx2 Then
        MsgBox(64, 'cbx2', 'Checked: ' & $bCbx2)
        $g_bCbx2 = $bCbx2
    EndIf
EndFunc

 

Link to comment
Share on other sites

I'm very close to solution.

Basically this works, but it's not complete yet (see commented lines):

#AutoIt3Wrapper_UseX64=n
#NoTrayIcon

#include <GUIConstants.au3>
#include <GuiStatusBar.au3>

Global $hTab, $hDll, $pDll, $hProc

$Form1 = GUICreate("StatusBar Checkbox", 400, 300, -1, -1, BitOR($GUI_SS_DEFAULT_GUI,$WS_MAXIMIZEBOX,$WS_SIZEBOX))
$cbx1 = GUICtrlCreateCheckbox("Sum 1", 10, 100, 120, 20)
GUICtrlSetResizing($cbx1, $GUI_DOCKLEFT+$GUI_DOCKTOP+$GUI_DOCKWIDTH+$GUI_DOCKHEIGHT)
$cbx2 = GUICtrlCreateCheckbox("Sum 2", 3, 3, 58, 15)
$hcbx2 = GUICtrlGetHandle($cbx2)
GUICtrlSetResizing($cbx2, $GUI_DOCKALL)
$StatusBar1 = _GUICtrlStatusBar_Create($Form1)
Dim $sb1_PartsWidth[3] = [62, 200, -1]
_GUICtrlStatusBar_SetParts($StatusBar1, $sb1_PartsWidth)
_GuiCtrlStatusBar_Resize($StatusBar1)
_SetParent($cbx2, $StatusBar1) ; after this Checkbox doesn't fire event in GUIGetMsg()
GUISetState(@SW_SHOW)
GUIRegisterMsg($WM_SIZE, "WM_SIZE")

; Register StatusBar window proc
$hDll = DllCallbackRegister('_SBWinProc', 'ptr', 'hwnd;uint;wparam;lparam')
$pDll = DllCallbackGetPtr($hDll)
$hProc = _WinAPI_SetWindowLong($StatusBar1, $GWL_WNDPROC, $pDll)

While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $cbx1
            MsgBox(64, 'cbx1', 'Checked: ' & IsChecked($cbx1)) ; OK
        Case $cbx2
            MsgBox(64, 'cbx2', 'Checked: ' & IsChecked($cbx2)) ; never fired
    EndSwitch
WEnd

_WinAPI_SetWindowLong($StatusBar1, $GWL_WNDPROC, $hProc)
DllCallbackFree($hDll)

Func WM_SIZE($hWnd, $Msg, $wParam, $lParam)
    _GuiCtrlStatusBar_Resize($StatusBar1)
    Return $GUI_RUNDEFMSG
EndFunc

Func _SetParent($ctrl_child, $ctrl_parent)
;~  $ctrl_parent = GUICtrlGetHandle($ctrl_parent)
    $ctrl_child = GUICtrlGetHandle($ctrl_child)
    DllCall("user32.dll", "hwnd", "SetParent", "hwnd", $ctrl_child, "hwnd", $ctrl_parent)
EndFunc

Func IsChecked($control)
    Return BitAnd(GUICtrlRead($control),$GUI_CHECKED) = $GUI_CHECKED
EndFunc

Func _SBWinProc($hWnd, $iMsg, $wParam, $lParam)
;~     Local $i_code = BitAND($wparam, 0xFFFF)
;~     Local $i_notify = BitShift($wparam, 16)

    If $hWnd = $StatusBar1 Then
        Switch $iMsg
            Case $WM_COMMAND
                If $wParam = $cbx2 Then MsgBox(64, 'cbx2', 'Checked: ' & IsChecked($cbx2))
;~              If $i_code = $cbx2 And $i_notify = $NM_CLICK Then MsgBox(64, 'cbx2', 'Checked: ' & IsChecked($cbx2))
        EndSwitch
    EndIf
    Return _WinAPI_CallWindowProc($hProc, $hWnd, $iMsg, $wParam, $lParam)
EndFunc

 

EDIT: Explanation

By default WM_COMMAND event/message from checkbox is delivered to main GUI form (and can be catch in main GUI loop) because it is its parent.

Now when we change parent of checkbox to StatusBar then WM_COMMAND event/message from checkbox is delivered to StatusBar as its parent.

So we have to register window procedure of StatusBar and catch WM_COMMAND (from our checkbox) there.

This works but the only one remaining problem is how to distinguish notification code in this case (I want to react only to NM_CLICK), because in my example $i_notify is always zero.

This problem is only cosmetic, because my checkbox generate only one WM_COMMAND (when clicked) so it works fine even if I don't do testing of NOTIFY/NM_CLICK.

Edited by Zedna
Link to comment
Share on other sites

What about this solution?

#AutoIt3Wrapper_UseX64=n
#NoTrayIcon
#include <Array.au3>
#include <GUIConstants.au3>
#include <GuiStatusBar.au3>

$Form1 = GUICreate("StatusBar Checkbox", 400, 300, -1, -1, BitOR($GUI_SS_DEFAULT_GUI,$WS_MAXIMIZEBOX,$WS_SIZEBOX))
$cbx1 = GUICtrlCreateCheckbox("Sum 1", 10, 100, 120, 20)
GUICtrlSetResizing($cbx1, $GUI_DOCKLEFT+$GUI_DOCKTOP+$GUI_DOCKWIDTH+$GUI_DOCKHEIGHT)
$cbx2 = GUICtrlCreateCheckbox("Sum 2", 3, 3, 58, 15)
$hCbx2 = GUICtrlGetHandle($cbx2)
GUICtrlSetResizing($cbx2, $GUI_DOCKALL)
$StatusBar1 = _GUICtrlStatusBar_Create($Form1)
Dim $sb1_PartsWidth[3] = [62, 200, -1]
_GUICtrlStatusBar_SetParts($StatusBar1, $sb1_PartsWidth)
_GuiCtrlStatusBar_Resize($StatusBar1)
_SetParent($cbx2, $StatusBar1) ; after this Checkbox doesn't fire event in GUIGetMsg()
GUISetState(@SW_SHOW)
GUIRegisterMsg($WM_SIZE, "WM_SIZE")
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
Global $iDummy = GUICtrlCreateDummy()

While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $cbx1
            MsgBox(64, 'cbx1', 'Checked: ' & IsChecked($cbx1)) ; OK
        Case $iDummy
            MsgBox(64, 'cbx2', 'Checked: ' & IsChecked($cbx2)) ; never fired
    EndSwitch
WEnd

Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg, $iwParam
    Local $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    Switch $tNMHDR.hWndFrom
        Case $hCbx2
            Local $aMPos = GUIGetCursorInfo($hWnd)
            Switch $aMPos[4]
                Case $cbx2
                    If $aMPos[2] Then
                        While GUIGetCursorInfo($hWnd)[2]
                        WEnd
                        GUICtrlSendToDummy($iDummy)
                        Return 0
                    EndIf
            EndSwitch
    EndSwitch
    Return "GUI_RUNDEFMSG"
EndFunc

Func WM_SIZE($hWnd, $Msg, $wParam, $lParam)
    _GuiCtrlStatusBar_Resize($StatusBar1)
    Return $GUI_RUNDEFMSG
EndFunc

Func _SetParent($ctrl_child, $ctrl_parent)
;~  $ctrl_parent = GUICtrlGetHandle($ctrl_parent)
    $ctrl_child = GUICtrlGetHandle($ctrl_child)
    DllCall("user32.dll", "hwnd", "SetParent", "hwnd", $ctrl_child, "hwnd", $ctrl_parent)
EndFunc

Func IsChecked($control)
    Return BitAnd(GUICtrlRead($control),$GUI_CHECKED) = $GUI_CHECKED
EndFunc

 

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

  • Solution

Thanks all for alternative solutions.

 

My final working solution:

#AutoIt3Wrapper_UseX64=n
#NoTrayIcon

#include <GUIConstants.au3>
#include <GuiStatusBar.au3>

$Form1 = GUICreate("StatusBar Checkbox", 400, 300, -1, -1, BitOR($GUI_SS_DEFAULT_GUI,$WS_MAXIMIZEBOX,$WS_SIZEBOX))
$cbx1 = GUICtrlCreateCheckbox("Sum 1", 10, 100, 120, 20)
GUICtrlSetResizing($cbx1, $GUI_DOCKLEFT+$GUI_DOCKTOP+$GUI_DOCKWIDTH+$GUI_DOCKHEIGHT)
$cbx2 = GUICtrlCreateCheckbox("Sum 2", 3, 3, 58, 15)
$hcbx2 = GUICtrlGetHandle($cbx2)
GUICtrlSetResizing($cbx2, $GUI_DOCKALL)
$cbx2_dummy = GUICtrlCreateDummy()
$StatusBar1 = _GUICtrlStatusBar_Create($Form1)
Dim $sb1_PartsWidth[3] = [62, 200, -1]
_GUICtrlStatusBar_SetParts($StatusBar1, $sb1_PartsWidth)
_GuiCtrlStatusBar_Resize($StatusBar1)
_SetParent($cbx2, $StatusBar1)
GUISetState(@SW_SHOW)
GUIRegisterMsg($WM_SIZE, "WM_SIZE")

; Register StatusBar window proc
Global $hDll, $pDll, $hProc
$hDll = DllCallbackRegister('_SBWinProc', 'ptr', 'hwnd;uint;wparam;lparam')
$pDll = DllCallbackGetPtr($hDll)
$hProc = _WinAPI_SetWindowLong($StatusBar1, $GWL_WNDPROC, $pDll)

While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $cbx1
            MsgBox(64, 'cbx1', 'Checked: ' & IsChecked($cbx1))
        Case $cbx2_dummy
            MsgBox(64, 'cbx2', 'Checked: ' & IsChecked($cbx2))
    EndSwitch
WEnd

_WinAPI_SetWindowLong($StatusBar1, $GWL_WNDPROC, $hProc)
DllCallbackFree($hDll)

Func WM_SIZE($hWnd, $Msg, $wParam, $lParam)
    _GuiCtrlStatusBar_Resize($StatusBar1)
    Return $GUI_RUNDEFMSG
EndFunc

Func _SetParent($ctrl_child, $ctrl_parent)
;~  $ctrl_parent = GUICtrlGetHandle($ctrl_parent)
    $ctrl_child = GUICtrlGetHandle($ctrl_child)
    DllCall("user32.dll", "hwnd", "SetParent", "hwnd", $ctrl_child, "hwnd", $ctrl_parent)
EndFunc

Func IsChecked($control)
    Return BitAnd(GUICtrlRead($control),$GUI_CHECKED) = $GUI_CHECKED
EndFunc

Func _SBWinProc($hWnd, $iMsg, $wParam, $lParam)
    If $hWnd = $StatusBar1 And $iMsg = $WM_COMMAND And $wParam = $cbx2 Then GUICtrlSendToDummy($cbx2_dummy)
    Return _WinAPI_CallWindowProc($hProc, $hWnd, $iMsg, $wParam, $lParam)
EndFunc

 

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