Is there a way to handle double-click as single-click?

What I’m trying to do:
Prevent users from double-clicking my buttons and links. This is a habit of some users, outside of my control. (Complain to Microsoft as to how they got into this habit.)

Double-clicking activates most links/buttons twice, which does not always end well. This should be treated as a single-click, unless specified otherwise.

I have hundreds of links and buttons, so adding code to every single one of their event-handlers is not an attractive solution.

If there’s no global solution, I might try creating a decorator (proposed name: @debounce) to do the job. If the same event is triggered more than once within a second or so, it would ignore the second triggering. I’d still have to use it in over a hundred places, but it’s better than coding it longhand.

1 Like

Rather than debounce the handlers in form code, you might consider overriding the Button/Link classes add_event_handler method

from functools import wraps
from time import sleep

orig_add_event_handler = Button.add_event_handler
DELAY = 0.3

def debounce(fn):

    clicks = []
    
    @wraps(fn)
    def wrapped(*args, **kws):
        if clicks:
            return
        clicks.append(True)
        try:
            fn(*args, **kws)
        finally:
            sleep(DELAY)
            clicks.pop()

    return wrapped

def add_event_handler(self, event, handler):
    if event == "click":
        handler = debounce(handler)
    return orig_add_event_handler(self, event, handler)

Button.add_event_handler = add_event_handler
2 Likes

Patching the Button class this way is something I don’t normally think of, coming from a C++ background. Thanks!

And I could revert to the decorator approach if my app needs finer control. With some links/buttons, for example, it might suffice simply to disable the control until the handler returns.

Edit: Luckily, this problem has reared its head in only one spot in my code, so I was able to keep the scope of the change very small. But I’ll keep this tactic on hand, for worse cases.

Thank you for bringing this up! Huge headache of mine I didn’t bring to the forum :slight_smile:

I wrap my functions with the following

button.enable = False
#DO EVENT STUFF HERE
button.enable = True 

But that is not full proof.

Yes, that is not foolproof. If an exception is raised, it will never reach the button.enable = True line.

A With Statement Context Manager would do the job, though, in those cases.

1 Like

Could the “wait_for_writeback” decorator work?

https://anvil-extras.readthedocs.io/en/latest/guides/modules/utils.html#wait-for-writeback

I haven’t looked at Anvil Extras in any detail yet. However, in my immediate case, writeback is not involved.