I'm tring to prevent users to rapidly spam-click a button, which would freeze the app possibly for minutes while the code is being executed many times.
$searchBtn_clicked = {
$searchBtn.Enabled = $false
... some code that fills a listview from search result
$searchBtn.Enabled = $true
}
My problem is: the code above will be executed as many times as the button is clicked, no matter what. Disabling the button after a click changes nothing. I also tried adding a start-sleep 2 before Enabling it back.
First click triggers the code, subsequent clicks are onto the disabled button... and will still trigger the Click event, as soon as the button becomes Enabled again.
What is happening here? Some kind of asynchronous magic? All click events are somehow queued and only being processed after the button is Enabled again?
I'm new to PowerShell and very confused.
Add [System.Windows.Forms.Application]::DoEvents():
$searchBtn.Add_Click({
$this.Enabled = $false
# ... some code that fills a listview from search result
# flush out all pending events
[System.Windows.Forms.Application]::DoEvents()
$this.Enabled = $true
})
Hope that helps
Windows messages are queued and processed in order. If your code is busy, these messages (spam-clicks) are stored in that queue and processed when possible. DoEvents() tells the window to pocess all messages currently in the message queue, effectively flushing it.
Related
Could someone explain me, put an example or something about the difference between the triggers "Approve Action" and "Execute Action" of the LibreOffice buttons? Both trigger the same way when pressing the button. I read this on the libreoffice wiki but I cant really figure out.
Approve action
This event takes place before an action is triggered by clicking the control. For example, clicking a "Submit" button initiates a send action; however, the actual "send" process is started only when the When initiating event occurs. The Approve action event allows you to kill the process. If the linked method sends back FALSE, When initiating will not be executed.
Execute action
The Execute action event occurs when an action is started. For example, if you have a "Submit" button in your form, the send process represents the action to be initiated.
Presumably, as the text says, the Approve action could be used to conditionally cancel the event. If you never need to do that, then the Execute action will run your code when the button gets pressed, after the action is approved.
Most likely this will work as expected for buttons. However, I have worked with certain controls and events where returning False from an event handler fails to cancel the event. My suspicion for those cases is that canceling still can happen deeper in the LibreOffice code but is not exposed through the API.
I have a script which filters an excel sheet (schedule) and displays the result through Out-Gridview. When the user clicks "Cancel" it opens the excel sheet after closing the Out-Gridview. When the user clicks "Ok" it only closes the Out-Gridview. But these actions are not visible for the user. So can i rename the "Ok" and "Cancel" button of Out-Gridview to lets say "Close Schedule" and "Open Excelsheet"?
And also, is it possible to run the rest of the script without waiting for the response, but keep the buttons working?
I know that if i don't use an output mode the rest of the script runs without waiting, but with outputmode (which gives me buttons) it waits for the response.
I use this code to filter a schedule and it would be nice if i can use the rest of the program without shutting down the rest of the program, maybe by starting another instance of powershell or something?
$Schedule = $ResultsTable | Out-Gridview -OutputMode Single -Title "Schedule"
if ($Schedule -eq $Null) {
Start-Process "$Fileserver\Logistics_share\Planning_Alg\TS Delivery schedule rev2.0.xlsx"
}
If it can be done with only a visual overlay, it is ok by me (Buttons)
I have a script which uses asynchronous runspaces in order to display a XAML/WPF GUI while processing stuff in the background. When I click the button, it crashes, but only when in a specific state. Let me elaborate.
The script begins with pinging a long list of servers to ensure that they're up. After that, it runs through a few SQL queries, WMI calls, other logic, processes all of the data, and then updates my DataGrid in the other window one row at a time with the information.
The button simply brings up a WinForm confirmation:
#$Global:uihash is my synchronized hashtable.
$Global:uihash.Button.add_click({if([System.Windows.Forms.MessageBox]::Show `
("Yes or No?", "Question",[System.Windows.Forms.MessageBoxButtons]::OKCancel) -eq "OK")
{Do stuff back in main PS Window}
If I press the button while the script is pinging all of the devices, it works perfectly. If I click the button at any other time during the script, the PS Windows immediately flip to not responding and I have to kill them.
From the application event log:
The program PowerShell_ISE.exe version 10.0.10586.117 stopped
interacting with Windows and was closed.
I'm like 95% sure it's because pinging devices is the only part of the script which has absolutely zero interaction with the other window, I just don't know how to fix this, or even work around it.
I'm wondering if anybody has seen or experienced this or something similar before, and how you got around it. Any help would be greatly appreciated. Thanks!
I was never able to completely figure this out, but I did find a good workaround for me. I put the main chunk of my script in a Do-Until loop, and made the button click change a global variable I created. That broke it out of the loop, closed the window, and let all the finishing tasks run without crashing.
#$Global:uihash is my synchronized hashtable.
#Create synchronized hash table variable
$Global:uiHash.Add(“End”,$false)
#Create Click Event
$Global:uihash.Button.add_click({if([System.Windows.Forms.MessageBox]::Show
("Yes or No?", "Question",[System.Windows.Forms.MessageBoxButtons]::OKCancel) -eq "OK")
{$Global:uiHash.End = $true}
Do {A whole bunch of stuff}
Until ($global:uiHash.end -eq $true)
#Close the window
$Global:uiHash.Window.Dispatcher.Invoke([action]{$Global:uiHash.Window.close() },"Normal")
#Then process the rest of the script
During script execution a pop up won't go away, and it happens only through QTP(v12.02).
I am trying DOM to bypass the problem, the pop up event was on selection of a drop down value, so I used some code to find the correct index and use DOM to select the value
Browser().Page().WebList().Object.selectedIndex = itmindx
With this the pop up issue got resolved, but now to complete the process,I need to click the Save button which is disabled as the page didn't refreshed when the value was selected ( tried refreshing through QTP, tab out etc--didn't worked as it loads the previous value).So I used the fire event method
Browser().Page().WebList().Fireevent "onchange"
with this I ran in to the same issue of multiple pop ups. Used the following
Browser().Page().WebList().Object.onchange()
but then QTP won't executes the next line unless I hit enter externally on the pop up(multiple pop up is resovled but now QTP is stuck. I don't want to use RS.... Any solutions?
To enable the button
Browser().Page().WebButton().Object.disabled = false
Or
To hit enter for the popup
CreateObject("WScript.Shell").SendKeys("{ENTER}")
[ http://ss64.com/vb/sendkeys.html ]
Go for hitting the Enter button using SendKeys. It is not a good idea accessing DOM and change the state ourselves. There is a chance that you might miss potential defects!
I want to show a dialog box with an OK button that is disabled for a short period of time (perhaps 5 seconds). The other buttons would still need to be responsive during this time.
You need a GTK+ timeout for that. First let the button be disabled. The timeout will call a function to enable the button.
Please not that for usability reasons, it should be visible for the user that a timer is running. You can do this by counting down, like "OK (5)", "Ok (4)" etc. until you enable the button.
See here:
http://graphics.sci.ubu.ac.th/api/pygtk/tutorials/pygtk2tutorial/ch-TimeoutsIOAndIdleFunctions.html
The idea is to set the timeout to 1 second (1000 ms). Everytime the callback is called you change the button label and return TRUE. When your callback is called the 5th time, you enable it and return FALSE. This will remove the timeout.