With a Jupyter notebook (I use Jupyter Lab 4 as IDE), I have a loop to go indefinitely until the user presses a key, say, Q or q, by which the application can check the status of the key having been pressed and stops the loop. Unfortunately, all keyboard inputs are intercepted by the system in a Jupyter notebook (modules such as keyboard, etc. don't work). so I was forced to try GUI modules such as tkinter, Qs5/6, etc., and then I studied ipywidgets for several days, which came to a stop with the asynch problem unresolved: the on_click event for a button is not triggered until the finish of the main loop, and that is useless then; there are 3 options in the documentation: https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20Asynchronous.html, I tried the first one: Event loop integration and it doesn't work (event still not triggered), and I am so frustrated. Is it so hard to take a non-blocking key input with a notebook? Your advice is highly apprecated. (note that input function is "blocking", so it's not the question)
Asked
Active
Viewed 44 times
0
-
These discussions may help you decide how to adapt to accomplish what you need in Jupyter: [here](https://discourse.jupyter.org/t/is-it-possible-to-get-the-current-value-of-a-widget-slider-from-a-function-without-using-multithreading/15524/2?u=fomightez), [here](https://stackoverflow.com/a/71223447/8508004), [here](https://discourse.jupyter.org/t/threading-with-matplotlib-and-ipywidgets/14674/2?u=fomightez), [here](https://discourse.jupyter.org/t/wait-for-specific-user-input-from-widgets/11436/2?u=fomightez), [here](https://stackoverflow.com/a/74896997/8508004), or ... – Wayne Aug 07 '23 at 01:44
-
or [here](https://stackoverflow.com/a/76397794/8508004). – Wayne Aug 07 '23 at 01:45
1 Answers
0
I think the following is one of the simplest solutions. (compared with asyncio, threading, multiprocessing)
import ipywidgets as widgets
from jupyter_ui_poll import ui_events
import time
button = widgets.Button(description="STOP!")
output = widgets.Output()
display(button, output)
clicked = False
def on_button_clicked(b):
global clicked
clicked = True
with output:
print("button clicked")
print(f"debug1: clicked={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(f"debug2: clicked={clicked}")
print('python waited for the button click')

Dino Hsu
- 21
- 4