Queso

keep program running while the GUI is moved

6 posts in this topic

I have a GUI program that communicates with piece of equipment via serial port communications.   The problem I'm having is that when the GUI window is moved around on the screen, or even when the user clicks and holds the window, the program pauses.  This is a problem because the if the equipment goes for more than a couple of seconds without getting a query from the program it shuts down.  So I need a way to either keep the program running while the GUI is moved by the user or a method of making repeated calls to another background program while the _Main() program is paused.  However, I'm not sure how to accomplish this.  

Alternatively, would it be better to write a "new" main function that runs in the background?  Then have this new main function create the GUI and monitor when it is being moved.  Then when it is moved make calls to the background program?

Any help would be greatly appreciated.

 

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <EditConstants.au3>
#include <GuiComboBoxEx.au3>
#include <Date.au3>

Global $g_hCombo_MODE
Global $g_hCombo_CMD
Global $g_sCode = ""

_Main()

Func _Main()
  Local $GUI_Title = "Temp"
  Local $hGUI = GUICreate($GUI_Title, 400, 200,-1,-1)
  Local $idInput_STATUS  = GUICtrlCreateInput(" ",    120, 50, 200, 21,$ES_READONLY)
  Local $ts = TimerInit()
  Local $td = TimerDiff($ts)
  local $sText = ""

  $g_hCombo_MODE  = _GUICtrlComboBox_Create($hGUI, "MODE 1|MODE 2|MODE 3|MODE 4", 10, 50, 100, 21,$CBS_DROPDOWNLIST)
  $g_hCombo_CMD = _GUICtrlComboBox_Create($hGUI, "CMD 1|CMD 2|CMD 3", 10, 100, 100, 21,$CBS_DROPDOWNLIST)

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

  While 1
    $idMsg = GUIGetMsg()
    Select
      Case $idMsg = $GUI_EVENT_CLOSE
        ExitLoop
    EndSelect
    Select
      Case $g_sCode = "UPDATE MODE"
        ; Get Item Text
        _GUICtrlComboBoxEx_GetItemText($g_hCombo_MODE, _GUICtrlComboBox_GetCurSel($g_hCombo_MODE), $sText)
        GUICtrlSetData($idInput_STATUS,"Command Sent "&$sText)
        ;Code to send command to instrument goes here
        $g_sCode = ""
        $ts = TimerInit()
      Case $g_sCode = "UPDATE CMD"
        _GUICtrlComboBoxEx_GetItemText($g_hCombo_CMD, _GUICtrlComboBox_GetCurSel($g_hCombo_CMD), $sText)
        GUICtrlSetData($idInput_STATUS,"Command Sent "&$sText)
        ;Code to send command to instrument goes here
        $g_sCode = ""
        $ts = TimerInit()
      Case $g_sCode <> "WAIT"
          $td = TimerDiff($ts)
          If $td > 500 Then
            ;code to ask the status of the instrument including its current mode goes here
            ;For this example I will just set the mode to 'MODE 1', CMD to 'CMD 1' and display the elapsed time
            GUICtrlSetData($idInput_STATUS,StringFormat("Status Received: %#.6g ms", $td))
            _GUICtrlComboBox_SetCurSel( $g_hCombo_MODE,0)
            _GUICtrlComboBox_SetCurSel( $g_hCombo_CMD,0)
            $ts = TimerInit()
          EndIf
    EndSelect
  WEnd
  Exit
EndFunc   ;==>Main

Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
  #forceref $hWnd, $iMsg
  Local $hWndFrom, $iIDFrom, $iCode
  $hWndFrom = $lParam
  $iIDFrom = BitAND($wParam, 0xFFFF) ; Low Word
  $iCode = BitShift($wParam, 16) ; Hi Word
  Switch $hWndFrom
    Case $g_hCombo_MODE
      Switch $iCode
        Case $CBN_CLOSEUP ; Sent when the list box of a combo box has been closed
          $g_sCode = "UPDATE MODE"
        Case $CBN_DROPDOWN; Sent when the list box of a combo box is about to be made visible
          $g_sCode = "WAIT"
      EndSwitch
    Case $g_hCombo_CMD
      Switch $iCode
        Case $CBN_CLOSEUP ; Sent when the list box of a combo box has been closed
          $g_sCode = "UPDATE CMD"
        Case $CBN_DROPDOWN; Sent when the list box of a combo box is about to be made visible
          $g_sCode = "WAIT"
      EndSwitch
  EndSwitch
  Return $GUI_RUNDEFMSG
EndFunc;==>WM_COMMAND

Func Background_Program()
    ;code to keep communicating with instrument goes here
    ;For this example just print the time.
    ConsoleWrite("Running: " & _NowTime() & @LF)
    Sleep(10)
EndFunc;==>Background_Program

 

Share this post


Link to post
Share on other sites



The easy solution is to use a hook procedure:

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <EditConstants.au3>
#include <GuiComboBoxEx.au3>
#include <Date.au3>
#include <WinAPI.au3>

Global $g_hCombo_MODE, $idInput_STATUS
Global $g_hCombo_CMD
Global $g_sCode = ""

_Main()

Func _Main()
  Local $GUI_Title = "Temp"
  Local $hGUI = GUICreate($GUI_Title, 400, 200,-1,-1)
  $idInput_STATUS  = GUICtrlCreateInput(" ",    120, 50, 200, 21,$ES_READONLY)
  Local $ts = TimerInit()
  Local $td = TimerDiff($ts)
  local $sText = ""

  $g_hCombo_MODE  = _GUICtrlComboBox_Create($hGUI, "MODE 1|MODE 2|MODE 3|MODE 4", 10, 50, 100, 21,$CBS_DROPDOWNLIST)
  $g_hCombo_CMD = _GUICtrlComboBox_Create($hGUI, "CMD 1|CMD 2|CMD 3", 10, 100, 100, 21,$CBS_DROPDOWNLIST)

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

  ; Catch window messages
  Local $hMessageHandler = DllCallbackRegister( "MessageHandler", "long", "int;wparam;lparam" )
  Local $hMessageHook = _WinAPI_SetWindowsHookEx( $WH_GETMESSAGE, DllCallbackGetPtr( $hMessageHandler ), 0, _WinAPI_GetCurrentThreadId() )

  While 1
    $idMsg = GUIGetMsg()
    Select
      Case $idMsg = $GUI_EVENT_CLOSE
        ExitLoop
    EndSelect
    Select
      Case $g_sCode = "UPDATE MODE"
        ; Get Item Text
        _GUICtrlComboBoxEx_GetItemText($g_hCombo_MODE, _GUICtrlComboBox_GetCurSel($g_hCombo_MODE), $sText)
        GUICtrlSetData($idInput_STATUS,"Command Sent "&$sText)
        ;Code to send command to instrument goes here
        $g_sCode = ""
        $ts = TimerInit()
      Case $g_sCode = "UPDATE CMD"
        _GUICtrlComboBoxEx_GetItemText($g_hCombo_CMD, _GUICtrlComboBox_GetCurSel($g_hCombo_CMD), $sText)
        GUICtrlSetData($idInput_STATUS,"Command Sent "&$sText)
        ;Code to send command to instrument goes here
        $g_sCode = ""
        $ts = TimerInit()
      Case $g_sCode <> "WAIT"
          $td = TimerDiff($ts)
          If $td > 500 Then
            ;code to ask the status of the instrument including its current mode goes here
            ;For this example I will just set the mode to 'MODE 1', CMD to 'CMD 1' and display the elapsed time
            ;GUICtrlSetData($idInput_STATUS,StringFormat("Status Received: %#.6g ms", $td))
            _GUICtrlComboBox_SetCurSel( $g_hCombo_MODE,0)
            _GUICtrlComboBox_SetCurSel( $g_hCombo_CMD,0)
            $ts = TimerInit()
          EndIf
    EndSelect
  WEnd
  _WinAPI_UnhookWindowsHookEx( $hMessageHook )
  Exit
EndFunc   ;==>Main

Func MessageHandler( $nCode, $wParam, $lParam )
  Local Static $ts = TimerInit(), $y = 1
  Local $td = TimerDiff($ts)
  If $td > 500 Then
    ConsoleWrite("Hook message handler: " & $y & @CRLF)
    GUICtrlSetData($idInput_STATUS,StringFormat("Status Received: %#.6g ms", $td))
    $ts = TimerInit()
    $y += 1
  EndIf
EndFunc

Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
  #forceref $hWnd, $iMsg
  Local $hWndFrom, $iIDFrom, $iCode
  $hWndFrom = $lParam
  $iIDFrom = BitAND($wParam, 0xFFFF) ; Low Word
  $iCode = BitShift($wParam, 16) ; Hi Word
  Switch $hWndFrom
    Case $g_hCombo_MODE
      Switch $iCode
        Case $CBN_CLOSEUP ; Sent when the list box of a combo box has been closed
          $g_sCode = "UPDATE MODE"
        Case $CBN_DROPDOWN; Sent when the list box of a combo box is about to be made visible
          $g_sCode = "WAIT"
      EndSwitch
    Case $g_hCombo_CMD
      Switch $iCode
        Case $CBN_CLOSEUP ; Sent when the list box of a combo box has been closed
          $g_sCode = "UPDATE CMD"
        Case $CBN_DROPDOWN; Sent when the list box of a combo box is about to be made visible
          $g_sCode = "WAIT"
      EndSwitch
  EndSwitch
  Return $GUI_RUNDEFMSG
EndFunc;==>WM_COMMAND

Func Background_Program()
    ;code to keep communicating with instrument goes here
    ;For this example just print the time.
    ConsoleWrite("Running: " & _NowTime() & @LF)
    Sleep(10)
EndFunc;==>Background_Program

 

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

You can use also the SetTimer function:

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <EditConstants.au3>
#include <GuiComboBoxEx.au3>
#include <Date.au3>

Global $g_hCombo_MODE
Global $g_hCombo_CMD
Global $g_sCode = ""

_Main()

Func _Main()
  Local $GUI_Title = "Temp"
  Local $hGUI = GUICreate($GUI_Title, 400, 200,-1,-1)
  Local $idInput_STATUS  = GUICtrlCreateInput(" ",    120, 50, 200, 21,$ES_READONLY)
  Local $ts = TimerInit()
  Local $td = TimerDiff($ts)
  local $sText = ""

  $g_hCombo_MODE  = _GUICtrlComboBox_Create($hGUI, "MODE 1|MODE 2|MODE 3|MODE 4", 10, 50, 100, 21,$CBS_DROPDOWNLIST)
  $g_hCombo_CMD = _GUICtrlComboBox_Create($hGUI, "CMD 1|CMD 2|CMD 3", 10, 100, 100, 21,$CBS_DROPDOWNLIST)

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

    GUIRegisterMsg($WM_TIMER, "Background_Program") ;$WM_TIMER = 0x0113
    Local $iTimer = 100 ;100 ms
    DllCall("user32.dll", "int", "SetTimer", "hwnd", $hGUI, "int", 0, "int", $iTimer, "int", 0)

  While 1
    $idMsg = GUIGetMsg()
    Select
        Case $idMsg = $GUI_EVENT_CLOSE
            GUIRegisterMsg($WM_TIMER, "")
        ExitLoop
    EndSelect
    Select
      Case $g_sCode = "UPDATE MODE"
        ; Get Item Text
        _GUICtrlComboBoxEx_GetItemText($g_hCombo_MODE, _GUICtrlComboBox_GetCurSel($g_hCombo_MODE), $sText)
        GUICtrlSetData($idInput_STATUS,"Command Sent "&$sText)
        ;Code to send command to instrument goes here
        $g_sCode = ""
        $ts = TimerInit()
      Case $g_sCode = "UPDATE CMD"
        _GUICtrlComboBoxEx_GetItemText($g_hCombo_CMD, _GUICtrlComboBox_GetCurSel($g_hCombo_CMD), $sText)
        GUICtrlSetData($idInput_STATUS,"Command Sent "&$sText)
        ;Code to send command to instrument goes here
        $g_sCode = ""
        $ts = TimerInit()
      Case $g_sCode <> "WAIT"
          $td = TimerDiff($ts)
          If $td > 500 Then
            ;code to ask the status of the instrument including its current mode goes here
            ;For this example I will just set the mode to 'MODE 1', CMD to 'CMD 1' and display the elapsed time
            GUICtrlSetData($idInput_STATUS,StringFormat("Status Received: %#.6g ms", $td))
            _GUICtrlComboBox_SetCurSel( $g_hCombo_MODE,0)
            _GUICtrlComboBox_SetCurSel( $g_hCombo_CMD,0)
            $ts = TimerInit()
          EndIf
    EndSelect
  WEnd
  Exit
EndFunc   ;==>Main

Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
  #forceref $hWnd, $iMsg
  Local $hWndFrom, $iIDFrom, $iCode
  $hWndFrom = $lParam
  $iIDFrom = BitAND($wParam, 0xFFFF) ; Low Word
  $iCode = BitShift($wParam, 16) ; Hi Word
  Switch $hWndFrom
    Case $g_hCombo_MODE
      Switch $iCode
        Case $CBN_CLOSEUP ; Sent when the list box of a combo box has been closed
          $g_sCode = "UPDATE MODE"
        Case $CBN_DROPDOWN; Sent when the list box of a combo box is about to be made visible
          $g_sCode = "WAIT"
      EndSwitch
    Case $g_hCombo_CMD
      Switch $iCode
        Case $CBN_CLOSEUP ; Sent when the list box of a combo box has been closed
          $g_sCode = "UPDATE CMD"
        Case $CBN_DROPDOWN; Sent when the list box of a combo box is about to be made visible
          $g_sCode = "WAIT"
      EndSwitch
  EndSwitch
  Return $GUI_RUNDEFMSG
EndFunc;==>WM_COMMAND

Func Background_Program()
    ;code to keep communicating with instrument goes here
    ;For this example just print the time.
    ConsoleWrite("Running: " & _NowTime() & @LF)
    ;Sleep(10)
EndFunc;==>Background_Program

 

@LarsJ: learned something new! Thx.

Edited by UEZ

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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

Thank you both  @LarsJ  and @UEZ for your insights and taking the time to respond.  (I kind of figured it was going to take the use of DLL calls.)  However there is still one issue.  The background program is called repeatedly not only when there is a pause in the execution of the main while loop.  The reason this is an issue, is when I add the serial port communication to Background_Program the commands that it issues start to conflict with the serial commands coming from the main while loop.  Is there a way to make it so that the program or at least the ConsoleWrite command is only executed if the if the main while loop hasn't run in a few seconds?

 

 

Share this post


Link to post
Share on other sites
7 hours ago, Queso said:

Is there a way to make it so that the program or at least the ConsoleWrite command is only executed if the if the main while loop hasn't run in a few seconds?

Well, a loop is a loop that means that your main loop runs continuously. You have to redesign the main loop either to run the serial port communication or console write function.


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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

Thanks, @UEZ.  I think that rewriting the main loop is probably the best way to go.    However I was able to get it to work using @LarsJ example.  Basically when the GUI window is moved $lParam is decreased by 2356.  So if I check $lParam every time the message handler is called, I can have it send a dummie serial commands to the instrument in order to keep communication open whenever ($lParam == $lParam_init - 2356) and do nothing otherwise so that my normal communication can continue.  I'll have to try it with the full program, but I think this will offer at least a short term solution.  Thanks again both of you for your help.

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <EditConstants.au3>
#include <GuiComboBoxEx.au3>
#include <Date.au3>
#include <WinAPI.au3>

Global $g_hCombo_MODE, $idInput_STATUS
Global $g_hCombo_CMD
Global $g_sCode = ""
Global $lParam_init = 0

_Main()

Func _Main()
  Local $GUI_Title = "Temp"
  Local $hGUI = GUICreate($GUI_Title, 400, 200,-1,-1)
  $idInput_STATUS  = GUICtrlCreateInput(" ",    120, 50, 200, 21,$ES_READONLY)
  Local $ts = TimerInit()
  Local $td = TimerDiff($ts)
  local $sText = ""

  $g_hCombo_MODE  = _GUICtrlComboBox_Create($hGUI, "MODE 1|MODE 2|MODE 3|MODE 4", 10, 50, 100, 21,$CBS_DROPDOWNLIST)
  $g_hCombo_CMD = _GUICtrlComboBox_Create($hGUI, "CMD 1|CMD 2|CMD 3", 10, 100, 100, 21,$CBS_DROPDOWNLIST)

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

  ; Catch window messages
  Local $hMessageHandler = DllCallbackRegister( "MessageHandler", "long", "int;wparam;lparam" )
  Local $hMessageHook = _WinAPI_SetWindowsHookEx( $WH_GETMESSAGE, DllCallbackGetPtr( $hMessageHandler ), 0, _WinAPI_GetCurrentThreadId() )

  While 1
    $idMsg = GUIGetMsg()
    Select
      Case $idMsg = $GUI_EVENT_CLOSE
        ExitLoop
    EndSelect
    Select
      Case $g_sCode = "UPDATE MODE"
        ; Get Item Text
        _GUICtrlComboBoxEx_GetItemText($g_hCombo_MODE, _GUICtrlComboBox_GetCurSel($g_hCombo_MODE), $sText)
        GUICtrlSetData($idInput_STATUS,"Command Sent "&$sText)
        ;Code to send command to instrument goes here
        $g_sCode = ""
        $ts = TimerInit()
      Case $g_sCode = "UPDATE CMD"
        _GUICtrlComboBoxEx_GetItemText($g_hCombo_CMD, _GUICtrlComboBox_GetCurSel($g_hCombo_CMD), $sText)
        GUICtrlSetData($idInput_STATUS,"Command Sent "&$sText)
        ;Code to send command to instrument goes here
        $g_sCode = ""
        $ts = TimerInit()
      Case $g_sCode <> "WAIT"
          $td = TimerDiff($ts)
          If $td > 500 Then
            ;code to ask the status of the instrument including its current mode goes here
            ;For this example I will just set the mode to 'MODE 1', CMD to 'CMD 1' and display the elapsed time
            ;GUICtrlSetData($idInput_STATUS,StringFormat("Status Received: %#.6g ms", $td))
            _GUICtrlComboBox_SetCurSel( $g_hCombo_MODE,0)
            _GUICtrlComboBox_SetCurSel( $g_hCombo_CMD,0)
            $ts = TimerInit()
          EndIf
    EndSelect
  WEnd
  _WinAPI_UnhookWindowsHookEx( $hMessageHook )
  Exit
EndFunc   ;==>Main

Func MessageHandler( $nCode, $wParam, $lParam )
  Local Static $ts = TimerInit(), $y = 1
  Local $td = TimerDiff($ts)

  ;Run frst time through the loop to get the nominal value of $lParm (There is probably a better way to to do this.
  If $lParam_init = 0 Then $lParam_init = $lParam

  If $td > 500 Then
     If $lParam == $lParam_init - 2356 Then
        ConsoleWrite("Hook message handler: " & $y  & "  : " & $lParam_init & "  : " & $lParam & "  : " & $lParam_init -2356 & @CRLF)
     EndIf
     GUICtrlSetData($idInput_STATUS,StringFormat("Status Received: %#.6g ms", $td))
     $ts = TimerInit()
     $y += 1
  EndIf
EndFunc

Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
  #forceref $hWnd, $iMsg
  Local $hWndFrom, $iIDFrom, $iCode
  $hWndFrom = $lParam
  $iIDFrom = BitAND($wParam, 0xFFFF) ; Low Word
  $iCode = BitShift($wParam, 16) ; Hi Word
  Switch $hWndFrom
    Case $g_hCombo_MODE
      Switch $iCode
        Case $CBN_CLOSEUP ; Sent when the list box of a combo box has been closed
          $g_sCode = "UPDATE MODE"
        Case $CBN_DROPDOWN; Sent when the list box of a combo box is about to be made visible
          $g_sCode = "WAIT"
      EndSwitch
    Case $g_hCombo_CMD
      Switch $iCode
        Case $CBN_CLOSEUP ; Sent when the list box of a combo box has been closed
          $g_sCode = "UPDATE CMD"
        Case $CBN_DROPDOWN; Sent when the list box of a combo box is about to be made visible
          $g_sCode = "WAIT"
      EndSwitch
  EndSwitch
  Return $GUI_RUNDEFMSG
EndFunc;==>WM_COMMAND

Func Background_Program()
    ;code to keep communicating with instrument goes here
    ;For this example just print the time.
    ConsoleWrite("Running: " & _NowTime() & @LF)
    Sleep(10)
EndFunc;==>Background_Program

 

Share this post


Link to post
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