1

I'm sorry if this question has already been answered, but I couldn't find anything on here (except this one which hasn't been answered: link and one that doesn't quite answer the question i'm asking link

I'm creating a button with ipywidgets, but the script doesn't wait for the button to be clicked. Here's a sample of the code/what I'm trying to achieve:

button = widgets.Button(description = "Click")
output = widgets.Output()
display(button, output)

def on_button_clicked(b):
     with output:
     print("button clicked")

button.on_click(on_button_clicked)
print("Python is ignoring you")

If I run this, I'll just get "Python is ignoring you" before I click the button. I want it to display the button, wait for the person to click it, and only then execute the rest ("Python is ignoring you").

Does anyone have an idea of how I can make python wait for the button to be clicked?

Would appreciate any help! Thanks

  • If you have *lots* more code to run, then you will need to place all of this code inside functions. The `button.on_click` just makes the connection between what *will* happen if you do click the button. There is no way to suspend the body of code being run. – ac24 Sep 08 '20 at 08:21

2 Answers2

1

I never used the ipywidgets, but the problem is on the last line

you're telling python to print "Python is ignoring you" and python is doing it.

It will not wait for the user to click the button,

because the print statement is out the function "on_button_clicked".(or any)

So just Put it in the function. (That print Statement)

Nili
  • 89
  • 2
  • 8
  • Thanks! For now I just put a random input command that makes you press enter after the button click. Good enough for what I'm trying to achieve :) – david_abaev Sep 10 '20 at 17:44
0

We need to explicitly poll the UI events

There's a neat little library called jupyter-ui-poll which handles exactly this use case! The rest of the button setup you have can stay the same. We just need to wrap a pollable scope around the loop like so:

from jupyter_ui_poll import ui_events
import time
...
clicked = False
def on_button_clicked(b):
    global clicked
    clicked = True
    with output:
        print("button clicked")

button.on_click(on_button_clicked)

with ui_events() as poll:
    while not clicked:
        poll(10) # poll queued UI events including button
        time.sleep(1) # wait for 1 second before checking again
print('python waited for the button click')

The issue is that the IPython kernel executes a queue of events, but there's one queue for both UI event callbacks and cell execution. So once it's busy working on a cell, UI events don't get processed. jupyter-ui-poll temporarily (inside the scope) adjusts this queueing behaviour to allow for explicit polling.

Community
  • 1
  • 1
Oly
  • 2,329
  • 1
  • 18
  • 23