AppleScript not looping all numbers when using repeat - loops

I am using this script to close all "Alerts" in my notification bar:
tell application "System Events"
tell process "NotificationCenter"
set numwins to (count windows)
repeat with i from numwins to 1 by -1
click button "Close" of window i
end repeat
end tell
end tell
However this doesn't close them all, even when there are no "Alert without Close button".
try catch didn't help. What's wrong?

I tested your script and it seemed to run correctly on my machine, but there is always a potential for problems when you use a repeat loop on a mutating list: in other words, a list that changes as the repeat loop progresses. Each time you close a window Notification Center changes its window list and updates the properties of the remaining windows; the script can simply lose track. I'm a little surprised it doesn't throw errors when this happens, but...
You can try this code and see if it works. rather than referring to windows by index it repeatedly tries to close the last window, ignoring any errors, and keeps on until the window count is zero or it loops 100 times (that last is to prevent an endless loop in case something goes wrong).
tell application "System Events"
tell process "NotificationCenter"
repeat 100 times
try
tell last window
click button "Close"
end tell
end try
if (count of its windows) = 0 then
exit repeat
end if
end repeat
end tell
end tell
EDIT
Per comments, the above doesn't work quite as advertised, so let's switch it over to AppleScriptObjC:
use framework "Foundation"
property NSUserNotificationCenter : class "NSUserNotificationCenter"
NSUserNotificationCenter's defaultUserNotificationCenter's removeAllDeliveredNotifications()
This seems to do the trick on my machine. Of course, NSUserNotificationCenter is deprecated as of 10.14, so this won't work forever — eventually you'll have to shift over to the notification's framework — but it should work for a few more OS versions.
EDIT 2
Per another comment, anyone working on os 10.14 or later (Mojave and Catalina, to date) can do an equivalent AppleScriptObjC routine using the UserNotifications framework, like so:
use framework "UserNotifications"
set notificationCenter to class "UNUserNotificationCenter"'s currentNotificationCenter
notificationCenter's removeAllDeliveredNotifications()
Note that I've used a slightly different syntax (merely calling class "UNUserNotificationCenter" rather than setting up a property). Both work; the property syntax is only preferable when you need to pass the class to handlers.

Related

In VB how do you display all strings in an array on a timer?

Ok, here's my use case. I have a form that pulls different parts of the form from a number of tables in a database. Each time I pull the info, I test to make sure there were no errors. Currently I'm using msgbox to show if there are errors, but I'm rewriting the app to instead display these messages in a "status" line area. It's just a label that I write the strings into on the form that flashes the error. This is working great in my single "You did this, and you got an error" forms. But in one of my forms it's about 6 things that could give errors, and it's on load. So it's not a single action, single error type deal.
My idea is to load any errors into an array, then display them one at a time for like 5 seconds each, then loop back and do it again, for at least 5 times. So in effect I want it to show each error, for 5 seconds, then show the next one for 5 seconds, then start over again, for 5 times, then stop.
Problem is, while I've got about 10 ideas on ways to maybe do this, they all seem really complicated and complex (and I don't want to spend 10 hours writing it only to figure out it's not going to work). I'm looking for the "best" way.
So.... Is an array even the best way? Or would a list or some other way be better? I'm looking for ideas here. How would YOU do it?
Eventually, you can use arrays for what you are trying to achieve. This could be done by following the steps :
When you are pulling the information from the tables, check for errors and if there is any, put it into an array.
Define a for loop which is going to loop 5 times
Define another nested loop to loop through the array to display the messages one by one
After each message display, put a sleep or delay of 5 seconds
If you follow these instructions, it just a matter of minutes into writing the codes
I ended up solving this by using a combobox and a list, then just having my combobox blink. On forms that can only throw one error, I use a label instead. Here is the lion's share of my code to do this:
Private Sub ErrorCheck()
If errorList.Count = 1 Then
ErrorComboBox.Visible = True
DismissErrorButton.Visible = True
For Each errors As String In errorList
ErrorComboBox.Text = (errors)
Next
ErrorBlinkTimer.Enabled = True
ElseIf errorList.Count > 1 Then
ErrorComboBox.Visible = True
DismissErrorButton.Visible = True
ErrorComboBox.Text = "There were errors, click drop down to view!"
For Each errors As String In errorList
ErrorComboBox.Items.Add(errors)
Next
Else
End If
End Sub
What I do is after each thing in a SUB that can throw errors, I have it collect the error and write it to errorList with errorList.add like so:
Catch ex As Exception
Dim errorStr = "An Error Occurred in " & Me.Name & " writing into the OpenEvents table " _
& "for setting the Alert radio button."
log(errorStr & " - " & ex.Message)
errorList.Add(errorStr)
the log function is a custom function for writing off to the log, but the rest is standard VB.net stuff. As you can see, if I get any exception (I do the same thing with each query too) it writes the error off to the errorList, then flashes the combobox with the error(s). I have some more logic to make it all nice and pretty, but you get the idea.
at the end of each sub that CAN throw errors, I just have it call:
ErrorCheck()
and like magic, if there were any errors a combobox list appears with bright red flashing text to let them know. If they click it, and there is more than one error, they can see them all in a nice list. Clicking it also makes it stop flashing, cause that would be annoying... LOL
This ended up working much better overall really, but it's not quite as pretty as my first way of doing it... but, no matter what I did, it caused issues on the form(s) to have it running through the flashing loop 5x's to display each error one after the other. I had found work arounds for most of it, but there was still a performance impact, so I dumped it for this. And it does the job well enough.

Breakable loop in Scratch?

How do you make a breakable loop in Scratch? I'm using Scratch 2.0 and can't find any good way to make a loop breakable, from inside of the loop itself.
Disclaimer:
There is no perfect way to do it. If you can possibly stand this true fact then feel free to continue.
There are a few different ways you could do it.
With repeat until
The first and most simple one follows this:
But this isn't technically part of the script - it's just repeating until some value returns true.
With a custom block (stop this script)
In order to do it inside of the script, you'll need to use a sneaky little trick with custom blocks.
Create a custom block called whatever you want - but probably along the lines of "breakable loop". Inside of it, create this script:
By using stop script we are breaking out of the script that is currently running - which, according to Scratch, is the custom block.
See the result! (as scratchblocks)
With broadcast and wait
You could also use a broadcast-and-wait method, very similar to above:
Though I highly suggest you don't use this method, as if any other sprites have breakable loops you'll need to rename each one, which can be tedious after using a lot of loops in a lot of sprites!
(Note this bug has been fixed in version 442 of the editor and such the following no longer applies.)
Help! My project is lagging a bunch now!
As #foi has noticed, if your code must be run inside of a frame you probably checked run without screen refresh. Unfortunately, due to a bug in the Scratch player, this causes the program to essentially break after the stop this script block has been activated. How can you handle this?
It follows the same principle you use when you use a run without screen refresh custom block inside of a forever loop - the loop doesn't use screen refresh while the inside does, allowing for instant animations whether or not one is using turbo mode.
Here's an example - the image is really too long to be embedded, so see it here instead.
You can make a variable inside or outside of the repeat and make your script like this:
repeat until [[my variable] = [e.g: 1]]
your code
your code
your code
your code
end of repeat until
For a "repeat until" block the simplest way would be to "or" your normal until condition with the break condition in the until.
By adding an incremeting loop counter variable in the loop you can use a "repeat until" to replicate the function of a "repeat n times" block
By using a "repeat until" block with only your break condition you get the equivalent of a "forever" block
If you need another script/ sprite to trigger the break then a public variable will let you break the loop from anywhere and let a single condition break loops for different sprites.
I'd post an image of the blocks but this is my first reply and the site won't let me!
good luck
You can use these few ways to do it...
conditional loop
stop this script
if then else, in the else section, put nothing
I would prefer to use the first method, as it requires less blocks and for the first method, you can still add in code that will be executed after the loop has stopped executing.
You can make it repeat x times or make it have a certain point where it stops, such as another variable changing.
Otherwise, I don't think there is a wat to do that.
Use the repeat until block. Then put in an equals block or whatever into the boolean part. Then inside that repeat until block, put a stop this script block.
Hope this helps :D

VisualBasic6 - read continuously a variable

I need read in an infinite loop some variables and in the case it changes the boolean status it must do something.
I tried to use a Do...Loop but the application crashes.
Is there a way in visual basic 6 to use an infinite loop without stunk?
My code:
Do
asd1 = readValue1
asd2 = readValue2
If asd1 <> asd1ex Then
Text1.Text = "yes"
End If
If asd2 <> asd2ex Then
Text1.Text = "no"
End If
Loop While True
Make a timer and on that timer check the status, instead of the loop.
Solved after comment that explained where the data was coming from (async COM component's property):
working with vb6 IDE on a realtime client-server project. I have to read some variables
and when one of these changes status it sends a socket message to
server. With the sleep it stuck equally
What did not help:
DoEvents and sleep
DoEvents
Sleep 100
might help, will need to refer to the windows function sleep. But VB6 is single thread (well one for UI and one for logic) so you should have a way to get out of the loop. What are you really trying to do? Can you describe at a top level?
Are you working on the VB6 IDE or in VBA code in Office?
For sleep to work declare:-
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
See this too https://stackoverflow.com/a/4540553/1643558
If your showing a form to the user to read value 1 and 2 then you can use a modal form and have a button to click when they are done, and hide the form only when you like the values. No need to have a loop then. Can show an error MsgBox on a modal form too.
See http://www.tek-tips.com/viewthread.cfm?qid=1117372
Maybe remove the sleep and only keep the DoEvents.
You could also make a timer and on that timer check the status, instead of the loop
It looks like you're trying to set up a sort of event handler. In effect, your loop is "listening" for a change to the variable. You don't explain how the variables get changed, and this is important . If whatever is changing the variables can also raise an event, then you're home free--you can get rid of your loop and use the event handler to send the socket message. (This is probably why Deanna asked how the variables change.) This is the preferred way to do what you want, so you should find ways to raise an event if the variables change.

Why does silverlight run into an endless loop when printing document longer than 1 page? .HasMorePages = true

My 1st question here on stackoverflow.
I am trying to print a long grid, which was dynamically generated.
pdoc.PrintPage += (p, args) =>
{
args.PageVisual = myGrid;
args.HasMorePages = false;
};
When I use args.HasMorePages = false;, it prints the first page of the grid as it should (although it takes some time, since it sends a 123MB big bitmap to the poor printer - thanks for silverlight 4's print feature implementation.).
However, when I enable printing more pages withargs.HasMorePages = true;, the printing job runs amok on the memory and sends endless copies of the first printing page of the document - effectively disabling my developer machine. Even if the grid is only 2 pages long.
Why does this happen?
What is a possible workaround here? All I found on the net is that SL handles printing badly, but not a real solution.
The HasMorePages property indicates to silverlight printing that you have a least one more page to print. The PrintPage page event fires for each page to be printed.
Hence when you set HasMorePages to true you will get another PrintPage event, if you always set it true (as your code appears to be doing) you are creating an infinite loop.
At some point the code has to leave HasMorePages set to false.
Ultimately its up to you the developer to perform all the pagination logic and decide what appears on each page, Silverlight does not automagically do that for you.

Show progress bar when sending pages to the printer (WPF)

I am creating printouts in WPF using flow documents. These printouts are set in separate window where DocumentViewer is placed.
When user clicks print I would like to show a progress bar that informs about current page that is sending to the printer. How can I do this?
I'm not sure exactly where your print code is, or where you want the progress bar, but I did something similar to this recently. This will be in VB.net.
First of all, create a new progressbar in the same class as the code you use to send the page to the printer. Then, we're going to take advantage of the "top-down" order in a block of code to change the progress bar.
The progress bar's value should be set to "0" be default. Now, in the code for sending the page to the printer, you're going to increase the progressbar's value (such as with the code "MyProgressBar.Value = MyProgressBar.Value + 1"). Put this code in between each line of the code you want to show progress for.
I would change the "+ 1" part of the code, however, to another value, so your progress bar progresses equally after each step. If you have three lines of code, then use "+ 33" (100\3), four lines use "+ 25", etc.
Finally, at the end of the code, set "MyProgressBar.Value = 100"
This only works, however, if you have access to a code longer than one line. For one line of code, I'm not sure how this works, unless you can get to the block of code that line points to.
If you have to use code from another class, you may need to do something like...
Dim MyWindowWhereProgressIs As New MyWindowWhereProgressIs
And then, each time you need to change the value, try...
MyWindowWhereProgressIs.MyProgressBar.Value = MyWindowWhereProgressIs.MyProgressBar.Value + 1
I'm not entirely sure whether or not those last two lines of code will work, as I'm away from Visual Studio right now, but it is worth a shot.

Resources