Jump to content

How to clear queued msg


czardas
 Share

Recommended Posts

I was wondering if there is an easy command to clear queued messages sent to GUI controls whilst another process is busy. If I interrupt a long process, I just want the program to return to a ready state. However all the buttons I may have clicked whilst the process was running are in a queue, waiting to execute. Is there a simple function I can use to clear these messages?

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

Local $hGUI = GUICreate("Stop Process", 300, 170)

$fInterrupt = 0

$Go = GUICtrlCreateButton("Go", 10, 10, 70, 20)
$Stop = GUICtrlCreateButton("Stop", 100, 10, 70, 20)
$helloWorld = GUICtrlCreateButton("Hello World", 190, 10, 100, 20)

GUISetState()

GUIRegisterMsg($WM_COMMAND, "_Stop")

While 1
    $msg = GUIGetMsg()
    If $msg = $GUI_EVENT_CLOSE Then ExitLoop
    If $msg = $Go Then _infiniteProc()
    If $msg = $helloWorld Then MsgBox(0, "", "Hello World")
WEnd

Func _infiniteProc()
    While $fInterrupt = 0
        ; infinite process
    WEnd
    $fInterrupt = 0
    Return $GUI_RUNDEFMSG
EndFunc

Func _Stop($hWnd, $Msg, $wParam)
    If BitAND($wParam, 0x0000FFFF) = $Stop Then $fInterrupt = 1
EndFunc
Edited by czardas
Link to comment
Share on other sites

  • Moderators

czardas,

Just run GUIGetMsg in a loop until you get 0 as a return - that has worked for me in the past. :)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Just run GUIGetMsg in a loop until you get 0 as a return - that has worked for me in the past. ;)

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

Local $hGUI = GUICreate("Stop Process", 300, 170)

$fInterrupt = 0

$Go = GUICtrlCreateButton("Go", 10, 10, 70, 20)
$Stop = GUICtrlCreateButton("Stop", 100, 10, 70, 20)
$helloWorld = GUICtrlCreateButton("Hello World", 190, 10, 100, 20)

GUISetState()

GUIRegisterMsg($WM_COMMAND, "_Stop")

While 1
    $msg = GUIGetMsg()
    If $msg = $GUI_EVENT_CLOSE Then ExitLoop
    If $msg = $Go Then
        _infiniteProc()
        While GUIGetMsg() <> 0
            $msg = GUIGetMsg()
        WEnd
    EndIf
    If $msg = $helloWorld Then MsgBox(0, "", "Hello World")
WEnd

Func _infiniteProc()
    While $fInterrupt = 0
        ; infinite process
    WEnd
    $fInterrupt = 0
    Return $GUI_RUNDEFMSG
EndFunc

Func _Stop($hWnd, $Msg, $wParam)
    If BitAND($wParam, 0x0000FFFF) = $Stop Then $fInterrupt = 1
EndFunc

Hehe, so easy when you know how. Thanks! :)

Link to comment
Share on other sites

Looping until you get 0 is a hack. Here is how it should be handled. Simply disable the buttons so you don't get messages from them when they are clicked. It is both more obvious to the user as it is in the code.

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

Local $hGUI = GUICreate("Stop Process", 300, 170)

$fInterrupt = 0

$Go = GUICtrlCreateButton("Go", 10, 10, 70, 20)
$Stop = GUICtrlCreateButton("Stop", 100, 10, 70, 20)
GUICtrlSetState(-1, $GUI_DISABLE)
$helloWorld = GUICtrlCreateButton("Hello World", 190, 10, 100, 20)

GUISetState()

GUIRegisterMsg($WM_COMMAND, "_Stop")

While 1
    $exit = DoEvents()
    If $exit Then
        ExitLoop
    EndIf
WEnd

Func DoEvents()
    $msg = GUIGetMsg()
    If $msg = $GUI_EVENT_CLOSE Then Return True
    If $msg = $Go Then 
        GUICtrlSetState($Go, $GUI_DISABLE)
        GUICtrlSetState($Stop, $GUI_ENABLE)
        GUICtrlSetState($helloWorld, $GUI_DISABLE)
        _infiniteProc()
        GUICtrlSetState($Go, $GUI_ENABLE)
        GUICtrlSetState($Stop, $GUI_DISABLE)
        GUICtrlSetState($helloWorld, $GUI_ENABLE)
    EndIf
    If $msg = $helloWorld Then 
        MsgBox(0, "", "Hello World")
    EndIf
    Return False
EndFunc

Func _infiniteProc()
    While $fInterrupt = 0
        DoEvents()
        ; infinite process
    WEnd
    $fInterrupt = 0
EndFunc

Func _Stop($hWnd, $Msg, $wParam)
    If BitAND($wParam, 0x0000FFFF) = $Stop Then $fInterrupt = 1
EndFunc
Edited by Manadar
Link to comment
Share on other sites

It had occured to me, but there will be such a varied number of buttons (and GUI's), that it would make life so hard. I'll still consider it as a more complicated alternative.

Actually nearly all the buttons will be array elements, so I could loop through them. I don't see what advantage looping through disabling buttons or GUIGetMsg will or won't have. It seems to be easier to just clear the messages.

Edited by czardas
Link to comment
Share on other sites

Doing things right is far more important than a few extra lines of code. You can use a lot of techniques to reduce the lines of code, if you really have to write hundreds of lines of extra code that are all similar. Wrap the toggling of the buttons to a function, or do something like this:

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

Local $hGUI = GUICreate("Stop Process", 300, 170)

$fInterrupt = 0

$Go = GUICtrlCreateButton("Go", 10, 10, 70, 20)
$Stop = GUICtrlCreateButton("Stop", 100, 10, 70, 20)
GUICtrlSetState(-1, $GUI_DISABLE)
$helloWorld = GUICtrlCreateButton("Hello World", 190, 10, 100, 20)

Local $toggleButtons[3] = [$Go, $Stop, $helloWorld]

GUISetState()

GUIRegisterMsg($WM_COMMAND, "_Stop")

While 1
    $exit = DoEvents()
    If $exit Then
        ExitLoop
    EndIf
WEnd

Func DoEvents()
    $msg = GUIGetMsg()
    If $msg = $GUI_EVENT_CLOSE Then Return True
    If $msg = $Go Then 
        _toggleButtons()
        _infiniteProc()
        _toggleButtons()
    EndIf
    If $msg = $helloWorld Then 
        MsgBox(0, "", "Hello World")
    EndIf
    Return False
EndFunc

Func _toggleButtons()
    For $n = 0 to UBound($toggleButtons)-1
        $button = $toggleButtons[$n]
        If BitAnd(GUICtrlGetState($button), $GUI_ENABLE) Then
            GUICtrlSetState($button, $GUI_DISABLE)
        Else
            GUICtrlSetState($button, $GUI_ENABLE)
        EndIf
    Next
EndFunc

Func _infiniteProc()
    While $fInterrupt = 0
        $exit = DoEvents()
        If $exit Then
            $fInterrupt = 1
        EndIf
        ; infinite process
    WEnd
    $fInterrupt = 0
EndFunc

Func _Stop($hWnd, $Msg, $wParam)
    If BitAND($wParam, 0x0000FFFF) = $Stop Then $fInterrupt = 1
EndFunc

A much more elegant solution that is readable, understandable, maintainable, and does not have any hack-value. Oh I love my signature.

Edited by Manadar
Link to comment
Share on other sites

  • Moderators

Manadar,

I know it is a hack, but it does work - at least in MessageLoop mode! ;)

Do you happen to know if there is a limit to the size of the message queue which would cause problems if the user went berzerk and clicked on the various controls umpteen times while the process was running? :)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Manadar,

I know it is a hack, but it does work - at least in MessageLoop mode! ;)

Do you happen to know if there is a limit to the size of the message queue which would cause problems if the user went berzerk and clicked on the various controls umpteen times while the process was running? :)

M23

Yes, and your hack answered the original question exactly as it was asked. There could be a limit on the size of the message queue, but it is a theoretical limit. Windows will notify the user that the window is unresponsive and then Windows stops additional windows messages being sent to the window.

That is another problem that my solution solves. The app remains responsive the whole time to all windows messages, which is almost a requirement that Windows puts on applications.

This is the same code as above but I implemented the close button being clicked while the infinite loop is active, which instead of closing the GUI, stops the infinite process using the $fInterrupt flag.

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

Local $hGUI = GUICreate("Stop Process", 300, 170)

$fInterrupt = 0

$Go = GUICtrlCreateButton("Go", 10, 10, 70, 20)
$Stop = GUICtrlCreateButton("Stop", 100, 10, 70, 20)
GUICtrlSetState(-1, $GUI_DISABLE)
$helloWorld = GUICtrlCreateButton("Hello World", 190, 10, 100, 20)

Local $toggleButtons[3] = [$Go, $Stop, $helloWorld]

GUISetState()

GUIRegisterMsg($WM_COMMAND, "_Stop")

While 1
    $exit = DoEvents()
    If $exit Then
        ExitLoop
    EndIf
WEnd

Func DoEvents()
    $msg = GUIGetMsg()
    If $msg = $GUI_EVENT_CLOSE Then Return True
    If $msg = $Go Then 
        _toggleButtons()
        _infiniteProc()
        _toggleButtons()
    EndIf
    If $msg = $helloWorld Then 
        MsgBox(0, "", "Hello World")
    EndIf
    Return False
EndFunc

Func _toggleButtons()
    For $n = 0 to UBound($toggleButtons)-1
        $button = $toggleButtons[$n]
        If BitAnd(GUICtrlGetState($button), $GUI_ENABLE) Then
            GUICtrlSetState($button, $GUI_DISABLE)
        Else
            GUICtrlSetState($button, $GUI_ENABLE)
        EndIf
    Next
EndFunc

Func _infiniteProc()
    While $fInterrupt = 0
        $exit = DoEvents()
        If $exit Then
            $fInterrupt = 1
        EndIf
        ; infinite process
    WEnd
    $fInterrupt = 0
EndFunc

Func _Stop($hWnd, $Msg, $wParam)
    If BitAND($wParam, 0x0000FFFF) = $Stop Then $fInterrupt = 1
EndFunc
Edited by Manadar
Link to comment
Share on other sites

While I agree that Disabling the buttons (like Manadar showed) is the better way, if you refuse to do that then stick GUIGetMsg in a loop (end when no events) in a adlib that runs every 500ms or so.

That way you wont pile shitloads of events on each other. Much better than the Melba idea I think.

Edit: added last sentence.

Edited by AdmiralAlkex
Link to comment
Share on other sites

How do I disable the [x] close button in the top right hand corner. It seems as if either Melba's method or both must be used. Or have the button on a different GUI and just disable the whole thing.

You can't disable the close button, but why would you want to? You can just ignore it being pressed by not handling the message: As long as you get it. See my code for details.
Link to comment
Share on other sites

How do I disable the [x] close button in the top right hand corner. It seems as if either Melba's method or both must be used. Or have the button on a different GUI and just disable the whole thing.

Ignore the $GUI_EVENT_CLOSE ? :)
Link to comment
Share on other sites

To add to the complication of disabling buttons, I would also have to keep account of the buttons that are already disabled. I would also have to disable the menus. While the correct proceedure is preferable, it sucks.

Nick, did you even read my code? I have already showed you how to solve that problem. It works for anything that accepts $GUI_ENABLE and $GUI_DISABLE: This includes menus. Edited by Manadar
Link to comment
Share on other sites

Nick, did you even read my code? I have already showed you how to solve that problem. It works for anything that accepts $GUI_ENABLE and $GUI_DISABLE: This includes menus.

Sorry I was interrupted, I'll take a good look at it all now. I can see the problem with stacking too many messages. I'll give all options good consideration. Thanks.
Link to comment
Share on other sites

Okay I looked at the example, and I agree that I may have to use Manadar's option. Although I do still have some issues with the method. While the buttons are in a mixed state of available or not before running the process, the user may wish to review the settings by examining the status of the buttons. If at some point the user realizes that the wrong configuration has been set, then they may wish to stop the process. If I disable all the buttons, the user will have less information about the process being run. This effect was actually intended by design.

I know there are ways around this, but I haven't even began to write the process and it's now getting messy already. Maybe I could register all buttons to give a message saying "Please End process before you click me again!"

Edit

I think I know what I'll do. I'll forego the advantage of visual configuration and just disable the whole GUI. I can embed the STOP button on a second GUI to enable everything again. If it works. :)

Edited by czardas
Link to comment
Share on other sites

This seems to work in a funny kind of way.

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

Local $hGUI = GUICreate("Stop Process", 300, 170)

$fInterrupt = 0

$Go = GUICtrlCreateButton("Go", 10, 10, 70, 20)
$helloWorld = GUICtrlCreateButton("Hello World", 190, 10, 100, 20)

Local $hcGUI = GUICreate("Stop", 70, 20, 100, 10, $WS_POPUP, $WS_EX_MDICHILD, $hGUI)
$Stop = GUICtrlCreateButton("Stop", 0, 0, 70, 20)
GUISetState()
GUISwitch($hGUI)
GUISetState()

GUIRegisterMsg($WM_COMMAND, "_Stop")

While 1
    $msg = GUIGetMsg()
    If $msg = $GUI_EVENT_CLOSE Then ExitLoop
    If $msg = $Go Then
        _infiniteProc()
    EndIf
    If $msg = $helloWorld Then MsgBox(0, "", "Hello World")
WEnd

Func _infiniteProc()
    GUISetState(@SW_DISABLE, $hGUI)
    While $fInterrupt = 0
        ; infinite process
    WEnd
    $fInterrupt = 0
    GUISetState(@SW_ENABLE, $hGUI)
    Return $GUI_RUNDEFMSG
EndFunc

Func _Stop($hWnd, $Msg, $wParam)
    If BitAND($wParam, 0x0000FFFF) = $Stop Then $fInterrupt = 1
EndFunc
Edited by czardas
Link to comment
Share on other sites

What is wrong with the example I gave you? It seems to work and do everything what you asked for.

There's nothing wrong with it, apart from I can't tell which buttons have been disabled. I would probably use your method under most circumstances.

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

Local $hGUI = GUICreate("Stop Process", 300, 170)

;$fInterrupt = 0

$Go = GUICtrlCreateButton("Go", 10, 10, 70, 20)
$helloWorld = GUICtrlCreateButton("Hello World", 190, 10, 100, 20)
$disabled = GUICtrlCreateButton("Disabled", 10, 50, 100, 20)
GUICtrlSetState(-1, $GUI_DISABLE)

Local $hcGUI = GUICreate("Stop", 70, 20, 100, 10, $WS_POPUP, $WS_EX_MDICHILD, $hGUI)
$Stop = GUICtrlCreateButton("Stop", 0, 0, 70, 20)
GUISetState()
GUISwitch($hGUI)
GUISetState()

GUIRegisterMsg($WM_COMMAND, "_Stop")

While 1
    $msg = GUIGetMsg()
    If $msg = $GUI_EVENT_CLOSE Then ExitLoop
    $fInterrupt = 0 ; Always set this flag before running the process!
    If $msg = $Go Then
        _infiniteProc()
    EndIf
    If $msg = $helloWorld Then MsgBox(0, "", "Hello World")
WEnd

Func _infiniteProc()
    GUISetState(@SW_DISABLE, $hGUI)
    GUICtrlSetState($Stop, $GUI_FOCUS) ; This is optional, but helps to add clarity.
    While $fInterrupt = 0
        ; infinite process
    WEnd
    $fInterrupt = 0
    GUISetState(@SW_ENABLE, $hGUI)
    Return $GUI_RUNDEFMSG
EndFunc

Func _Stop($hWnd, $Msg, $wParam)
    If BitAND($wParam, 0x0000FFFF) = $Stop Then $fInterrupt = 1
EndFunc
Edited by czardas
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...