Is there a simple way (idealy only using bind tricks) to implement the behavior:
If user makes a double click, do nothing.
If user releases the first mouse button, do something.
I tried this:
pack [label .l1 -text "Test"]
bind .l1 <ButtonRelease-1> {puts works}
bind .l1 <Double-1> {break}
But the "works" message apears twice if a do a double click.
I'm trying to find something that does not need "after cancel".
Thanks
Alexandru
I doubt that there is a solution without "after ..."
Not sure why you want to avoid "after cancel"... you can
pass a specific after-id to "after cancel", if you don't
want to cancel by naming the full scriptlet.
Another approach could also be to set&check a global (or namespaced)
variable in the after-handler and in other handlers.
e.g.:
ButtonRelease: { set var armed; after 500 { if {$var eq "armed"} { do it } } DoubleClick: { set var unarmed; ... }
Alexandru <alexandr...@meshparts.de> wrote:
Is there a simple way (idealy only using bind tricks) to implement the behavior:
If user makes a double click, do nothing.
If user releases the first mouse button, do something.
I tried this:
pack [label .l1 -text "Test"]
bind .l1 <ButtonRelease-1> {puts works}
bind .l1 <Double-1> {break}
But the "works" message apears twice if a do a double click.
I'm trying to find something that does not need "after cancel".
Thanks
Alexandru
Because I like the pure "bind" solution more.
Alexandru <alexandr...@meshparts.de> wrote:
Because I like the pure "bind" solution more.The "pure bind" approach kind of fails on the point, where it is
supposed to peek into future, to determine whether another click
will follow. -- That, or I completely misunderstood the original
question.
There are a few more or less dirty tricks to achieve all those
behaviors that do not require peek-into-future directly without
after handlers. If yours is of that kind, please try again,
describing the situations you want to capture, and those you
want to not react for.
But if you need some event fired only if the user is done with
his action, then you will need some kind of timer and see later
if the user continued harrassing the mouse, or gave it a break. ;-)
bind .l1 <Button-1> { set var "1st" }
bind .l1 <Double-1> { set var "2nd" }
bind .l1 <ButtonRelease-1> {
if {$var eq "1st"} { do it ... }
}
Wait, I've got a new idea of what you might have meant...
(sorry for implying you wanted tcl to read future)
My new interpretation is, that you want only the second
ButtonRelease to fire...
That would be:
bind .l1 <Button-1> { set var "1st" }
bind .l1 <Double-1> { set var "2nd" }
bind .l1 <ButtonRelease-1> {
if {$var eq "2nd"} { do it ... }
}
Note, that if the user just keeps hammering the Button, then you'll
still get multiple Doubles and thus multiple "do it ..."-calls.
To prevent that, you can either add a binding for <Triple-1> and
set the var to something else, e.g. "3rd".
I once had a case, where I wanted to handle Double Clicks, and then
reset the engine, so next click would become a plain click again.
For this I created a proc "reset_click":
proc reset_click {} {
event generate . <5>; event generate . <ButtonRelease-5>
}
and called it from the Double-handler.
That way, user pressing 4 times in a row would get through as
two separate doubleclicks.
Andreas Leitgeb <avl@logic.at> wrote:
Alexandru <alexandru.dadalau@meshparts.de> wrote:
Because I like the pure "bind" solution more.
The "pure bind" approach kind of fails on the point, where it is
supposed to peek into future, to determine whether another click
will follow. -- That, or I completely misunderstood the original
question.
There are a few more or less dirty tricks to achieve all those
behaviors that do not require peek-into-future directly without
after handlers. If yours is of that kind, please try again,
describing the situations you want to capture, and those you
want to not react for.
But if you need some event fired only if the user is done with
his action, then you will need some kind of timer and see later
if the user continued harrassing the mouse, or gave it a break. ;-)
Alexandru <alexandru.dadalau@meshparts.de> wrote:
Because I like the pure "bind" solution more.
The "pure bind" approach kind of fails on the point, where it is
supposed to peek into future, to determine whether another click
will follow. -- That, or I completely misunderstood the original
question.
There are a few more or less dirty tricks to achieve all those
behaviors that do not require peek-into-future directly without
after handlers. If yours is of that kind, please try again,
describing the situations you want to capture, and those you
want to not react for.
But if you need some event fired only if the user is done with
his action, then you will need some kind of timer and see later
if the user continued harrassing the mouse, or gave it a break. ;-)
Andreas Leitgeb schrieb am Montag, 28. Februar 2022 um 20:13:25 UTC+1:
Alexandru <alexandr...@meshparts.de> wrote:
Because I like the pure "bind" solution more.The "pure bind" approach kind of fails on the point, where it is
supposed to peek into future, to determine whether another click
will follow. -- That, or I completely misunderstood the original
question.
There are a few more or less dirty tricks to achieve all those
behaviors that do not require peek-into-future directly without
after handlers. If yours is of that kind, please try again,
describing the situations you want to capture, and those you
want to not react for.
But if you need some event fired only if the user is done with
his action, then you will need some kind of timer and see later
if the user continued harrassing the mouse, or gave it a break. ;-)
Okay, I get it.
Like I wrote I wanted this:
If user makes a double click, do nothing.
If user releases the first mouse button, do something.
But I undertand the "looking into future" thing.
The idea behind is that some users don't know if a single click is
expected and thy start doing double clicks instead. So without
anything else from the developer side, the user will trigger the
action twice.
Alexandru <alexandr...@meshparts.de> wrote:That's also an idea, except: it has the drawback in case an unexpected / uncatched error happens, then the button remains disabled. This also complicates things more.
Andreas Leitgeb schrieb am Montag, 28. Februar 2022 um 20:13:25 UTC+1:
Alexandru <alexandr...@meshparts.de> wrote:
Because I like the pure "bind" solution more.The "pure bind" approach kind of fails on the point, where it is
supposed to peek into future, to determine whether another click
will follow. -- That, or I completely misunderstood the original
question.
There are a few more or less dirty tricks to achieve all those
behaviors that do not require peek-into-future directly without
after handlers. If yours is of that kind, please try again,
describing the situations you want to capture, and those you
want to not react for.
But if you need some event fired only if the user is done with
his action, then you will need some kind of timer and see later
if the user continued harrassing the mouse, or gave it a break. ;-)
Okay, I get it.
Like I wrote I wanted this:
If user makes a double click, do nothing.Except your "requirements" are ambigious. A "double click" is also two
If user releases the first mouse button, do something.
"mouse button release" events as well. So it is impossible, using pure bindings to events without timers, to ignore a double click while doing something on a button release.
At the mouse hardware level there are only two button events: "button
down" and "button up" (release). "Double Clicks" (or any other plural
click types) are synthesized from these basic events by measuring
timing between them.
But I undertand the "looking into future" thing.1) Retrain users not to do that.
The idea behind is that some users don't know if a single click is
expected and thy start doing double clicks instead. So without
anything else from the developer side, the user will trigger the
action twice.
or
2) Inside the binding/command triggered from the widget, set the
respective widget to disabled state, and simultaneously attach a lambda
to an after event to fire in dt time (where dt is longer than the time between double clicks) to reenable the UI element. During the disabled
time dt, the widget will ignore the second click.
Rich schrieb am Montag, 28. Februar 2022 um 20:49:23 UTC+1:
2) Inside the binding/command triggered from the widget, set the
respective widget to disabled state, and simultaneously attach a
lambda to an after event to fire in dt time (where dt is longer than
the time between double clicks) to reenable the UI element. During
the disabled time dt, the widget will ignore the second click.
That's also an idea, except: it has the drawback in case an
unexpected / uncatched error happens, then the button remains
disabled. This also complicates things more.
Except your "requirements" are ambigious. A "double click" is also two "mouse button release" events as well. So it is impossible, using pure bindings to events without timers, to ignore a double click while doing something on a button release.
Rich <rich@example.invalid> wrote:
Except your "requirements" are ambigious. A "double click" is also two
"mouse button release" events as well. So it is impossible, using pure
bindings to events without timers, to ignore a double click while doing
something on a button release.
He had a special kind of "ignore the double click". he meant: ignore the second one of a double-click, after having already dealt with the first click. That is perfectly possible without timers.
What is similar, but not possible without timers would be: "if it is
a doubleclick, do nothing at all, even suppress any action on first
click".
Is there a simple way (idealy only using bind tricks) to implement the behavior:
If user makes a double click, do nothing.
If user releases the first mouse button, do something.
In the OP's case, I would suggest a somewhat different approach to
eliminate the need for an event timer and be more user responsive.
From: Julian H J Loaring <jhjloaring@gmail.com>
Date: Fri Mar 25 13:46:15 GMT 2022
Subject: Bind to buttonrelease but not to double click
Here is my attempt at a "debounce" class. I have stripped it from a package - the comments are for.....
The 800 ms value in the example was from trial an error...
Hope this helps
* Julian H J Loaring
| Here is my attempt at a "debounce" class. I have stripped it from a package - the comments are for Natural Docs...
--<snip-snip>--
| #
| package require TclOO
| package require oo::util
--<snip-snip>--
$ wish8.6
% info patchlevel
8.6.12
% package require TclOO
1.1.0
% package require oo::util
can't find package oo::util
?
| #
| # $debounce bind 100 {puts "%W text"}
| #
| method bind {ms body} {
| variable cmdref
| my Wait $ms
| set cmdref [Debounce newref]
| interp alias {} $cmdref {} [self object] execscript
- Who is responsible for deleting the 'used' aliases?
R'
From: Julian H J Loaring.....
Date: Fri Mar 25 13:46:15 GMT 2022
Subject: Bind to buttonrelease but not to double click
Here is my attempt at a "debounce" class. I have stripped it from a package - the comments are for
The 800 ms value in the example was from trial an error...I think you are dupicating logic in the Tk event system. The 800 ms delay will have to be tuned for each system and user.
Hope this helps
For a wiget (for example a label) that only respnds to double clicks
(ignores single clicks or more than two clicks) try:
label .odc -text "only double clik"
pack .odc
bind .odc <Button-1> return
bind .odc <Double-Button-1> "puts ok"
bind .odc <Triple-Button-1> return
For a wiget that only responds to a single click when shift is not pressed try:
label .osc -text "Only Single Click"
pack .osc
bind .osc <Button-1> "puts osc"
bind .osc <Shift-Button-1> return
bind .osc <Double-Button-1> return
It just works, no variables, objects or timers are necessary.I think I have spend too much time looking at JavaScript :) But who knows, a debounce may come in handy elsewhere...
Dave B
Here is my attempt at a "debounce" class. I have stripped it from a package - the comments are for Natural Docs...Apologies - I had tidied up the code just before posting and in introduced a bug :(
* Julian H J LoaringI will have to think about that!
| > % package require oo::util
| > can't find package oo::util
| >
| oo::util is in Tcllib. It is used for classvariable and classmethod in lieu of Tcl8.7
Ah, seems my tcllib is too old.
| > | # $debounce bind 100 {puts "%W text"}
| > | #
| > | method bind {ms body} {
| > | variable cmdref
| > | my Wait $ms
| > | set cmdref [Debounce newref]
| > | interp alias {} $cmdref {} [self object] execscript
| > - Who is responsible for deleting the 'used' aliases?
| >
| This is done in the object destructor
What about overwriting an already set cmdref in the bind method?
R'
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 485 |
Nodes: | 16 (2 / 14) |
Uptime: | 131:39:46 |
Calls: | 9,655 |
Calls today: | 3 |
Files: | 13,707 |
Messages: | 6,166,572 |