Open beastGrendel opened 2 days ago
You seem not to use the .open
method on the created dialog. Please compare to the example https://nicegui.io/documentation/dialog#awaitable_dialog.
I think the problem is that confirm_mission
is called without UI context so that ui.notify
doesn't know on which client (browser tab) to show the notification. Try wrapping it with with Client.auto_index_client
like in construct_ui
above.
You seem not to use the
.open
method on the created dialog. Please compare to the example https://nicegui.io/documentation/dialog#awaitable_dialog.
Thank you for answering. I do not see the .open method being used in the example for awaiting the dialog, especially since I have to submit values with it, no? Am I blind?
I think the problem is that
confirm_mission
is called without UI context so thatui.notify
doesn't know on which client (browser tab) to show the notification. Try wrapping it withwith Client.auto_index_client
like inconstruct_ui
above.
Also thank you for replying. I have tried that as well, just retried it. Same error again, it cannot determine the current slot :/
I do not see the .open method being used in the example for awaiting the dialog,...
You are right. awaiting the dialog internally opens it.
The tricky part is to make the result of the async show_confirm_dialog
available in the synchronous confirm_mission
. Here I demo it without a ROS2 node to reduce the dependencies. I assume you will use confirm_mission
as a service callback in your real application:
from nicegui import Client, background_tasks, app, ui
from concurrent.futures import Future
from threading import Thread
class OperatorGUI:
def __init__(self) -> None:
self.construct_ui()
# Start a thread to simulate a ROS2 service callback which runs on the thread pool
Thread(target=self.confirm_mission).start()
def construct_ui(self):
with Client.auto_index_client as self.gui_client:
with ui.dialog() as self.confirm_mission_dialog, ui.card():
ui.label('Confirm mission?')
with ui.row():
ui.button('Confirm', on_click=lambda _: self.confirm_mission_dialog.submit(True))
ui.button('Deny', on_click=lambda _: self.confirm_mission_dialog.submit(False))
def confirm_mission(self):
confirmation = Future()
background_tasks.create(self.show_confirm_dialog(confirmation))
return confirmation.result(timeout=30.0)
async def show_confirm_dialog(self, confirmation: Future):
with self.gui_client:
result = await self.confirm_mission_dialog
if result is True:
ui.notify('Mission confirmed', type='positive')
else:
ui.notify('Mission denied', type='negative')
confirmation.set_result(result)
def startup():
OperatorGUI()
app.on_startup(startup)
ui.run()
I'm wondering if we need the Future
at all. In a nutshell, it looks like we can boil it down to this:
class OperatorGUI:
def __init__(self) -> None:
with Client.auto_index_client:
with ui.dialog() as self.dialog, ui.card():
ui.label('Confirm mission?')
ui.button('Confirm', on_click=lambda _: self.dialog.submit(True))
Thread(target=lambda: background_tasks.create(self.show_dialog())).start() # simulate ROS2 service callback
async def show_dialog(self):
with Client.auto_index_client:
if await self.dialog:
ui.notify('Mission confirmed', type='positive')
app.on_startup(OperatorGUI)
Description
Good day,
I am trying to implement a small GUI for a ROS2 project. I am trying to send a service request to the GUI, so it can be confirmed or denied through a dialog pop up. I am generating a simple GUI in a function called from the constructor in which both the client as well as the dialog are assigned as class variables. However, once I am in the async function to await the dialog input no matter what I do (e.g. wait self.client: ... or simply await self.dialog), I always get back the error that "the current slot cannot be determined because the slot stack for this task is empty." I tried to reduce the example as much as possible:
I would expect the dialog to open so I could select either Deny or Confirm, however I get the following error:
Interestingly enough, with the ROS2 functionalities implemented (not as minimal as this modification of the problematic code), I do not get the warning to enable tracemalloc, but only the runtime error regarding the empty slot stack. Any idea what I am doing wrong, or how I can work with opening a dialog and submitting values within such a class function?
Kind regards and thank you, Stefan