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?
Forum Archive
Can't show an alert?
You have to decorate the function you are trying to show the alert from with "@ui.in_background".
@ui.in_background
def your_function(sender):
console.alert()
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.
In the main function, a new View is created and the TextField items reside in that View.
My main function ends with a my_view.wait_modal() so that the view doesn't close (if this is important).
Oh, the display_grid function updated some TextField items in my view, but not the ones whose field_edit function 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_modal does. It causes the current thread, in this case the main thread, to wait until the dialog is closed.
Think about what in_background does.. 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_modal unblocks. 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_alert probably 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.