Can't show an alert?
I'm trying to show an alert with console.alert
But I keep getting an error saying: AssertionError: Cannot show alert from main UI thread
So, can't I show an alert anywhere I need to?
How can I show alerts?
Well, I did that and the alert only shows when I close my View (in the top left X icon).
My function is like this:
@ui.in_background def alert(message): alert_result=console.alert('Warning',message, button1='OK') return
And I call it like this:
alert('The message to show in the alert')
Is there any particular place where I should place that function for it to work?
I still find it confusing why can't we simply show an alert wherever and whenever we want?
I unluckily am not able to reproduce your problem, therefore I can just make assumptions. Do you call any functions beyond the "alert ('The message to show in the alert')" call that might interfere with the ui? This might lead to unexpected behavior as your alert and anything you call beyond console.alert run on different threads. Do you maybe have any calls beyond this, that access the console?
I have no other console access.
However, the alert function is being called from inside an action assigned to a TextField.
That usually shouldn't be the problem then. Would you mind posting a little more of your code to give me more insight on what might be causing the problem ?
Well, here is a snippet of the function that calls the alert:
def field_edit(sender): global current_player global lines global rows global scores global totals global finished global n_players global scores_grid global combs global info size=lines*rows start=current_player*size display_grid() for x in range(lines): last=-1 for y in range(rows-1,-1,-1): value1=scores[start+(x*rows)+y] if value1!=0: last=y break if last!=-1: for y in range(last,-1,-1): value1=scores[start+(x*rows)+y] if value1==0: alert('Esse valor não pode ser colocado nessa posição.') return
This function is assigned to a few TextField items so that, whenever I type something in there and press Enter, the function is executed.
mainfunction, a new View is created and the TextField items reside in that View.
mainfunction ends with a
my_view.wait_modal()so that the view doesn't close (if this is important).
display_gridfunction updated some TextField items in my view, but not the ones whose
field_editfunction is attached to.
I could reproduce your error with my_view.wait_modal() at the end, therefore I assume it to be the problem. As soon as you leave this line out it works. Can you by any chance restructure your code in a way to make .wait_modal() not necessary?
Think about what
wait_modaldoes. It causes the current thread, in this case the main thread, to wait until the dialog is closed.
Think about what
in_backgrounddoes.. It calls a function on the main thread, instead of the ui thread. The name may therefore be a little misleading. So, your program main starts, then the thread sits and waits for the view to close. It can't do anything else until that
wait_modalunblocks. Meanwhile, your ui thread is operating, and then tries to background a call to console.alert. That call just gets queued up until wait modal finishes. For instance if you have alert tied to a button press, and press the button 5 times, then close your view, the alert will come up 5 times after you quit.
Since your are just trying to display a message,
console.hud_alertprobably is what you really want, as it does not require backgrounding to be called from the main ui thread (it goes away on its own after a few seconds, and does not block while doing so).
If you really want to use the interactive bits of console.alert, see the following example which calls console.alert from a threading Timer. This allows you to have the main thread waiting on the modal close, while still popping up alert. The first button is what you tried, and does not work until the view is closed. The second button works as expected, except when the view is presented as a full screen view, in which case presumably the console.alert is still shown, you just can't see it.
#demonstrate using threading to call console from a running ui that is wait_modal'ing' import ui, console from threading import Timer def myinbackground(f): Timer(0.25,f).start() # delay of 0 does lock ui, some small delay seems to be needed def alert(): try: pressed=console.alert('hello!','world','ok') console.hud_alert('got OK') except KeyboardInterrupt: console.hud_alert('got keyboardinterrupt') @ui.in_background def button_tapped1(sender=None): alert() #start alert on main thread def button_tapped2(sender=None): myinbackground(alert) # start alert in new thread def setup(): view = ui.View() view.name = 'Demo' view.background_color = 'white' view.width=200 view.height=200 button = ui.Button(title='ui.in_background') button.center = (view.width * 0.5, view.height * 0.25) button.flex = 'LRTB' button.action = button_tapped1 button2 = ui.Button(title='myinbackground!') button2.center = (view.width * 0.5, view.height * 0.5) button2.flex = 'LRTB' button2.action = button_tapped2 view.add_subview(button) view.add_subview(button2) return view def main(): view=setup() view.present('panel') # sheet, popover, or panel work, not full_screen view.wait_modal() main()
Well, I create a view and I want to keep it visible all the time.
I will see if I can restructure my code taking you example into account.
Thank you very much :-)
You don't need to wait_modal to keep a view on the screen. Wait_modal would be used if you want to pop up a menu for example! then have your main script wait for the user to choose something.
It seems like you just wanted to display a notification, in which hud alert is the best option.