0

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)

Dino Hsu
  • 21
  • 4
  • 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 Answers1

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