ui.switch: prevent animation on click #5641
Replies: 5 comments 4 replies
-
|
I can use |
Beta Was this translation helpful? Give feedback.
-
|
My solution: app.storage.general['switch_enabled'] = True
app.storage.general['motor'] = False
async def toggle_motor():
if not app.storage.general['switch_enabled']:
return
print('Toggling motor...')
app.storage.general['switch_enabled'] = False
await asyncio.sleep(1) # takes some time
app.storage.general['motor'] = not app.storage.general.get('motor', False)
app.storage.general['switch_enabled'] = True
@ui.page('/')
def main_page():
ui.switch('Motor On-Off').bind_enabled_from(app.storage.general, 'switch_enabled').bind_value_from(
app.storage.general, 'motor').on('click', toggle_motor)
I haven't found a way ( |
Beta Was this translation helpful? Give feedback.
-
|
Here's an example using Events. Might be useful if you have multiple pages monitoring the same state of the value. Events are defined globally as well as the switch click event subscription. Do whatever you need to do in the separate thread and emit the results back to the switch element (Or anywhere else needed). switch_event = Event()
valve_event = Event[bool]()
app.storage.general.setdefault('valve_open', False)
app.storage.general.setdefault('pending', False)
@switch_event.subscribe
async def toggle_value():
app.storage.general['pending'] = not app.storage.general['pending']
success = False
try:
await asyncio.sleep(2)
success = random.choice([True, False]) # For failed valve changes
if success:
app.storage.general['valve_open'] = not app.storage.general['valve_open']
except Exception:
success = False
finally:
valve_event.emit(success)
app.storage.general['pending'] = not app.storage.general['pending']
@ui.page('/')
def main_page():
default_value = app.storage.general.get('valve_open')
@valve_event.subscribe
async def set_valve_switch(success: bool):
if not success:
ui.notify('Failed')
return
valve_switch.set_value(app.storage.general.get('valve_open'))
async def switch_toggled(e: ClickEventArguments):
e.sender.set_value(app.storage.general.get('valve_open'))
switch_event.emit()
with ui.row().classes('items-center gap-2'):
ui.label('Valve Status: ')
valve_switch = ui.switch(value=default_value).on("click", switch_toggled) \
.bind_text_from(app.storage.general, 'valve_open', lambda v: 'Open' if v else 'Closed')
ui.spinner().bind_visibility_from(app.storage.general, 'pending') |
Beta Was this translation helpful? Give feedback.
-
|
I disabled pointer events on a checkbox and added click events to an enclosing element. This prevented animation on click def draw_valve_control(backend: ArenaZenohBackend, valve: Valve, rect: Rectangle, draw_refdes: bool = False):
if draw_refdes:
ui.label(valve.refdes).style(
f"""
position: absolute;
left: {rect.x_percent}%;
top: {rect.y_percent}%;
transform: translateY(-100%);
"""
).classes("text-[8pt] pl-1 font-mono")
with (
ui.grid(columns="auto")
.classes("justify-center cursor-pointer select-none")
.style(
f"""
position: absolute;
left: {rect.x_percent}%;
top: {rect.y_percent}%;
width: {rect.width_percent}%;
height: {rect.height_percent}%;
"""
)
) as grid:
checkbox = ui.checkbox("no data", value=None).props("dense checked-icon='circle' unchecked-icon='block' v-ripple=true").classes("font-mono text-xs pointer-events-none")
async def on_click(e):
current_state = backend.cvt.get(valve.status)
assert type(current_state) is None or type(current_state) is bool
if current_state is None:
new_state = True
else:
new_state = not current_state
assert type(new_state) is bool
backend.put(bool, valve.cmd, new_state)
grid.on("click", lambda e: on_click(e))
def translate_state_str(cvt_value: bool | None) -> str:
if cvt_value is None:
return "???"
match valve.default_state:
case Normally.open:
return "CLOSED" if cvt_value else "OPEN"
case Normally.closed:
return "OPEN" if cvt_value else "CLOSED"
case _:
assert_never(valve.default_state)
checkbox.bind_text_from(backend.cvt, valve.status, backward=lambda x: translate_state_str(x))
backend.add_subscriber_to_current_arena(valve.status)
def translate_state_bool(cvt_value: bool | None) -> bool | None:
if cvt_value is None:
return None
match valve.default_state:
case Normally.open:
return not cvt_value
case Normally.closed:
return cvt_value
case _:
assert_never(valve.default_state)
checkbox.bind_value_from(backend.cvt, valve.status, backward=lambda x: translate_state_bool(x))
with grid:
with ui.tooltip().props("anchor='center right' self='center left' transition-duration=0"):
ui.html(f"{valve.status}<br>{valve.cmd}", sanitize=False) |
Beta Was this translation helpful? Give feedback.
-
|
Thanks to @jeffective for discovering app.storage.general['switch_enabled'] = True
app.storage.general['motor'] = False
async def toggle_motor():
if not app.storage.general['switch_enabled']:
return
print('Toggling motor...')
app.storage.general['switch_enabled'] = False
await asyncio.sleep(1) # takes some time
app.storage.general['motor'] = not app.storage.general.get('motor', False)
app.storage.general['switch_enabled'] = True
@ui.page('/')
def main_page():
with ui.row().on('click', toggle_motor):
ui.switch('Motor On-Off').bind_enabled_from(app.storage.general, 'switch_enabled').bind_value_from(
app.storage.general, 'motor').classes('pointer-events-none') |
Beta Was this translation helpful? Give feedback.

Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Would adding an
on_clickhandler toui.switchbe a good idea? It would be specific to user clicks, not any change ason_changecurrent is.My use case is a machine control application.
I would like to use
ui.switchas both the status readout of the current state of a valve, and the means for the user to change the state of the valve:My desired behavior is:
The network request and background thread are fast enough where the ui.switch can update quickly enough.
Unfortunately, there is no way for me to register a callback only for user clicks. The callback is also triggered by my background task updating the bound data. So I sometimes get multiple events emitted for a single click due to the network request racing the background task.
I am also open to alternatives. So far I have also implemented this as two buttons whose disabled status indicates the current state of the valve, which is effective but less compact and less intuitive to the user.
Beta Was this translation helpful? Give feedback.
All reactions