MilesAhead Posted April 25, 2011 Share Posted April 25, 2011 (edited) Here's a simple technique I came up with to empty the TrayGetMsg queue on return from a blocking function. A small demo script is shown below. Let's say you have a Tray hotkey app where a window pops up when the user double clicks the tray icon, or hits a hotkey. The hotkey can easily be screened out by using a flag on entry to the blocking function. In the code below I use a global $windowOpen as the flag to tell me the blocking function is active. Could be a popup gui that's open or an about box. The problem lies when you have double click on the icon set to do the same thing. Just checking the flag won't work because when you pop down your window or about box, you set the flag to False. The TrayGetMsg has the mouse events queued up. So next time through the loop, $openWindow is False, it keeps popping up the window or about dialog for every double click that happened while the function blocked. I used to avoid this by disabling the tray icon and using a delay to avoid double clicking what moved to the position vacated by the tray icon. This is messy and a bit disconcerting to the user. Now I just leave the tray icon alone and drain the event queue as shown in the loop. expandcollapse popup;================================================================= ; ; AboutDemo - demonstrates drain of TrayGetMsg queue on ; return from blocking funciton. ; ; MilesAhead ;================================================================= #include <Constants.au3> AutoItSetOption("TrayMenuMode", 3) $aboutitem = TrayCreateItem("About Demo") TrayCreateItem("") $exititem = TrayCreateItem("Quit") TrayItemSetState($aboutitem, $TRAY_DEFAULT) TraySetState() Global $windowOpen = False Global $demoHotKey = "{F8}" HotKeySet($demoHotKey, "_About") While 1 $msg = TrayGetMsg() Select Case $msg = $aboutitem _About() ; on return from blocking function, drain the queue Do $msg = TrayGetMsg() Until $msg = 0 ContinueLoop Case $msg = $exititem Exit EndSelect WEnd Func _About() If $windowOpen Then Return $windowOpen = True MsgBox(0x1040, "About Demo", "Dummy Message") $windowOpen = False EndFunc ;==>_About Edited April 25, 2011 by MilesAhead My Freeware Page Link to comment Share on other sites More sharing options...
Moderators Melba23 Posted April 25, 2011 Moderators Share Posted April 25, 2011 (edited) MilesAhead,I used to use your suggested technique from time to time on both GUIGetMsg and TrayGetMsg, but with experience I have found that it is much better coding practice to disable the affected controls/HotKeys while the blocking function is running - if for no other reason than it makes clear what is going on. Your code would then look like this:#include <Constants.au3> Opt("TrayMenuMode", 3) $aboutitem = TrayCreateItem("About Demo") TrayCreateItem("") $exititem = TrayCreateItem("Quit") TrayItemSetState($aboutitem, $TRAY_DEFAULT) TraySetState() Global $demoHotKey = "{F8}" HotKeySet($demoHotKey, "_About") While 1 $msg = TrayGetMsg() Select Case $msg = $aboutitem _About() Case $msg = $exititem Exit EndSelect WEnd Func _About() TrayItemSetState($aboutitem, $TRAY_DISABLE) ; <<<<<<<<<<<<<<<<< HotKeySet($demoHotKey) ; <<<<<<<<<<<<<<<<< MsgBox(0x1040, "About Demo", "Dummy Message") TrayItemSetState($aboutitem, $TRAY_ENABLE) ; <<<<<<<<<<<<<<<<< HotKeySet($demoHotKey, "_About") ; <<<<<<<<<<<<<<<<< EndFunc ;==>_AboutIf you need to disable/enable a number of controls/keys then a function setting the requried state for them all would make the coding easier. M23Edit: Rereading this I fear you could take it as simply belittling your example. I did not mean to do that - just to offer an alternative which has, over the years, proved to be a better way to do things. Edited April 25, 2011 by Melba23 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 columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area Link to comment Share on other sites More sharing options...
MilesAhead Posted April 26, 2011 Author Share Posted April 26, 2011 (edited) I tried using TrayItemSetState but it doesn't work for the default item since the system will queue up mouse double-clicks while the function is blocking. I also tried changing the state before calling the function, and restoring it on return. Didn't work for me. The Tray Menu did not update. afa the hotkey disable, I did that in the past. But there's no need since it will interrupt what's going on and therefore all I need is a flag ($windowOpen.) If the window is already open just return. Seems simpler and neater to do it my way. But we are programmers because we want to do it our own way. If you have a system modal window popped up in the middle of the screen and the user is trying to execute other commands in the menu, to me that's just trying to break code where a double-click may be inadvertent. Also, other than the $windowOpen flag, my method centralizes the queue emptying code in the msg loop handling instead of scattering it all over functions. Another item in your About example, I tend to cut & paste about and ini read write functions from app to app, just changing the particulars. I don't like to enable and disable hotkeys inside the function the hotkey is calling. I like to have each function as stand-alone as possible. A test for a global $windowOpen and a reset at the end of the func is pretty reusable if I have a global $windowOpen in each app. Again easier to cut & paste. To me the problem is simplest as draining the queue. Not rerouting the program flow just so the queue won't accumulate events while the app is busy. Kind of cart before the horse to my philosophy. edit: For your purposes you may prefer your method. However my utilities tend to have 3 or 4 dialogs, change the hotkey, about box, main program interface etc., where I only want one to be showing. Also I may have 3 or 4 hotkeys for the one app. Using the flag technique to ensure only one window is open at a time I think is cleaner for my use. I don't have to disable several hotkeys and menu commands only to enable them again a bit later. But I would also admit either method is preferable to the way I was doing it.. hiding the Tray Icon. Having the icons jump around in the tray is bad news. I'm going to fix all my old utilities that used that method eventually to use the event queue drain instead. There's usually several ways to skin the cat and I appreciate your comments. Edited April 27, 2011 by MilesAhead My Freeware Page Link to comment Share on other sites More sharing options...
MilesAhead Posted April 28, 2011 Author Share Posted April 28, 2011 After more work it turns out I didn't implement this correctly. The problem with draining the Tray Icon event queue inside the loop is that the flag $windowOpen is set to False on return from blocking functions. The offending mouse double click can still work its way into the mischief. The alternative I came up with is a function to drain the queue to be called just before setting $windowOpen flag to False in each function. I've added it to my file of general purpose functions. For this demo I pasted the function at the bottom. expandcollapse popup;================================================================= ; ; AboutDemo - demonstrates _EmptyTrayQ() function and ; $windowOpen flag to avoid reentering blocking functions ; due to Tray Icon queueing of events. ; ; MilesAhead ;================================================================= #include <Constants.au3> AutoItSetOption("TrayMenuMode", 3) $aboutitem = TrayCreateItem("About Demo") TrayCreateItem("") $exititem = TrayCreateItem("Quit") TrayItemSetState($aboutitem, $TRAY_DEFAULT) TraySetState() Global $windowOpen = False Global $demoHotKey = "{F8}" HotKeySet($demoHotKey, "_About") While 1 $msg = TrayGetMsg() Select Case $msg = $aboutitem _About() Case $msg = $exititem Exit EndSelect WEnd Func _About() If $windowOpen Then Return $windowOpen = True MsgBox(0x1040, "About Demo", "Dummy Message") ; drain the tray icon queue before setting flag to False _EmptyTrayQ() $windowOpen = False EndFunc ;==>_About ; Empty Tray Icon Queue of events Func _EmptyTrayQ() Local $m = 0 Do $m = TrayGetMsg() Until $m = 0 EndFunc ;==>_EmptyTrayQ My Freeware Page Link to comment Share on other sites More sharing options...
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