I read on the internet that the default mouse wheel bindings were
improved in Tcl 8.6. Could the version I'm using account for the
behavior which I'm seeing?
Any suggestions would be appreciated.
Thanks in advance.
can you use the mousewheel in other applications? it used to be
necessary to enable the mousewheel with 'ZAxisMapping' in the X
servers config file.
Yes, I can use the mousewheel with a text widget which is next to the
canvas in the toplevel. There was no tcl software modification
required to cause this.
For the canvas, here's some code:
frame $w.c -bg lightblue
canvas $w.c.canvas -width 100 -height $hgt -borderwidth 0 -
yscrollcommand [list $w.c.yscroll set]
scrollbar $w.c.yscroll -orient vertical -command [list $w.c.canvas
yview]
set canvas_frame [frame $w.c.canvas.f -borderwidth 0 -background
lightblue
$w.c.canvas create window 0 0 -anchor nw -window $canvas_frame
A statement such as
bind $w.c.canvas <Enter> {MY_SCROLL_PROC %W }
can be used to scroll the canvas some number of lines when the cursor
enters the canvas
A statement such as
bind $w.c.canvas <Button_4> {bell}
will NOT ring the bell
I can use the frame $w.c.canvas.f created above in the following
statement
bind $w.c.canvas.f <Button_4> {bell}
to ring the bell, but the area of this frame is steadily diminished as
more widgets are written to the canvas. so I can't bind to this to
scroll.
Thanks.
Did you mean to bind using <Button-4> instead of <Button_4>?
DrS
DrS,
I mistyped the post; I used <Button-4>.
Thanks
I think it is correct to bind to the frame in the canvas. What you
have to do is to define the scrollregion everytime the content in the
canvas changes.
bind $w.c.canvas <Configure> {
%W configure -scrollregion [%W bbox all]
}
Regards
Christian,
Thanks, I will definitely try your suggestion. I mentioned above that
scrolling with the scrollbars works perfectly, regardless of the
amount of content in the canvas. It's the binding that I'm having
trouble with. If I bind a mouse button to the canvas, the binding
doesn't work. If I bind to the frame in the canvas, the bind works,
but not for the whole canvas. Will configuring the scrollregion affect
this?
This works fine for me in wish 8.5.8 on Linux/Opensuse 11.3:
pack [canvas .c -bg yellow] -fill both -expand yes
bind .c <Button-4> {puts 4}
bind .c <Button-5> {puts 5}
If I now scroll up with the scroll wheel over the canvas, '4' gets printed
in the console, scroll down -> '5'. Does this code work for you?
R'
Ralf,
I don't have access to the system today, but a couple of days ago, I
could not bind the canvas to any mouse button as you suggest; only to
<Enter> and <Leave>. I used the bell instead of the puts in your
example. What you suggest does work however with the canvas frame as I
reported above. I will try your suggestion as soon as possible. I'm
glad to see it works on Linux 8.5.8 in case I need to upgrade.
Thanks so much.
further to my email, the following works on my machine (Tcl 8.4.19):
bind .c <ButtonPress-4> {.c yview scroll 1 units}
bind .c <ButtonPress-5> {.c yview scroll -1 units}
hth
HTH,
Are using Linux? Also, is ButtonPress- equivalent to Button- ?
Thanks much.
yes, and yes.
the box is slackware (12.0), and <ButtonPress-N> is equivalent to
<Button-N> (or even a simple <N>).
btw, hth stands for 'hope that helps', my name (initials) is jr.
Thank you. I'll investigate further.
> btw, hth stands for 'hope that helps', my name (initials) is jr.
By the way, there's no reason to take offense and insult
tklish, addressing him as Butt Terribly Wide.
;-)
--
Donald Arseneau as...@triumf.ca
oh dear! there goes our last, best hope for peace :-)
(so you're into B5??)
Ralf,
I tried the three code lines you suggested using Wish and they worked
on my Unix system. This indicates that my binding problem probably has
nothing to do with the system or Tcl version. Thank you. It probably
has more to do with all the widgets that are placed on the canvas. If
I bind the <Enter> to "all" widgets I get five or six widgets output
each time I move the mouse around the canvas. They range from . to .c
to several levels below .c:
.
.App
.App.left
.App.left.c
.App.left.c.canvas
.App.left.c.canvas.f
.App.left.c.canvas.f.left
Could the fact that these are all stacked above each other cause the
mouse binding for the canvas to not work?
Donald,
Actually, jr4412 had it right.
BetterThanWonderful
> DrS,
> I mistyped the post; I used<Button-4>.
> Thanks
Here is some code that I have used across several linux distributions
over the years. They have worked on them just fine. The delta is the
minimum value between two consecutive mouse wheel events:
bind all <Button-4> \
{event generate [focus -displayof %W] <MouseWheel> -delta 120}
bind all <Button-5> \
{event generate [focus -displayof %W] <MouseWheel> -delta -120}
You can then use MouseWheel as a bindable event on tk objects like this:
bind $w <MouseWheel> ...
DrS
Thanks, DrS,
I will try this as soon as I can get computer time.
Tklish
I think I need to refine my question. Below I've added a small Tk
script in which I've created a canvas and two frames within it. I find
I need a separate binding to mouse button 2 for each of these widgets
in order to ring the bell with button 2 when it is over each of them.
(In actuality I will use buttons 4 and 5 and scroll instead of beep.)
Many objects are created on the canvas in the actual application and
the user may decide to use the mouse wheel when the cursor is over any
of them. Only the canvas widget has a scrollbar. Do I need a separate
connection to the scrollbar via a bind for every object on the
canvas? I could do this as they are created, but is there not some
way of using only one bind statement for the entire canvas as it
requires only one command to scroll the whole canvas? Or is this what
DrS is trying to tell me in the post above.
For illustration, I echo the window Id as I enter and exit the window.
Thanks in advance.
wm title . "Canvas Test"
set w .app
frame $w
set hgt 300
pack $w -anchor nw -expand 1 -fill both
pack $w -side left -anchor nw -fill y
frame $w.c -bg lightblue
canvas $w.c.canvas -width 300 -height $hgt -borderwidth 0 \
-yscrollcommand [list $w.c.yscroll set]
scrollbar $w.c.yscroll -orient vertical -command [list $w.c.canvas
yview]
pack $w.c.yscroll -side right -anchor e -fill y
pack $w.c.canvas -anchor nw -expand 1 -fill both
pack $w.c -anchor nw -expand 1 -fill both
frame $w.c.canvas.f -borderwidth 3 -background pink
$w.c.canvas create window 0 0 -anchor nw -window $w.c.canvas.f
frame $w.c.canvas.f.left -height $hgt -width 20 -background lightblue
grid $w.c.canvas.f.left
bind $w.c.canvas <Button-2> {bell}
bind $w.c.canvas.f <Button-2> {bell}
bind $w.c.canvas.f.left <Button-2> {bell}
bind all <Enter> {puts "Entering %W"}
bind all <Leave> {puts "Leaving %W"}
I think so. If the frame f.left gets an event, the canvas won't 'see'
it. This is different for 'window' canvas items and for other
canvas items:
pack [canvas .c -bg yellow] -fill both -expand yes
bind .c <1> {puts canvas}
.c create oval 20 20 100 100 -fill red
.c create window 200 200 -window [frame .c.f -height 50 -width 50 -bg green]
.c bind all <1> {puts canvas-item}
If you click on the canvas, 'canvas' gets printed.
If you click on the red circle, 'canvas-item' and 'canvas' get printed
(both bindings trigger).
If you click on the green rectangle, nothing happens (the event goes to
the frame, not to the canvas).
R'
Not easy to do this for a single canvas, but you can use a global binding to "all" to make the mousewheel work everywhere.
proc MouseWheel {w D X Y} {
# search upward for widget which can perform yview
for {} {[winfo toplevel $w] ne $w} {set w [winfo parent $w]} {
# do not scroll canvas with undefined scrollregion
if {![catch {$w cget -scrollregion} sr] && $sr eq ""} {continue}
if {![catch {$w yview scroll [expr {-$D/30}] units}]} {break}
}
}
# Remove existing MouseWheel bindings
foreach class {Text Listbox} {
bind $class <MouseWheel> {}
if {[tk windowingsystem] eq "x11"} {
bind $class <4> {}
bind $class <5> {}
}
}
# Bind MouseWheel to all
bind all <MouseWheel> {MouseWheel %W %D %X %Y}
if {[tk windowingsystem] eq "x11"} {
bind all <4> {MouseWheel %W 120 %X %Y}
bind all <5> {MouseWheel %W -120 %X %Y}
}
--Koen
Ralf, Koen,
Thanks so much for the explanation. I got the canvas to scroll by
binding each object as it's created. The bind returns %W, which I
manipulate, knowing that all the widgets are children of the canvas
and I delete all extraneous characters at the end of the %W string to
get the name of the canvas alone and using it to scroll the entire
canvas. In my situation it might not be a good idea to bind to all,
since besides the canvas there are all kinds of other widgets in the
main window, probably another 20 or so. And more children are created
on the canvas as the application continues, based on user input.
Koen, I will save the code you provided since I think it will be handy
in the future.
Many thanks to all who helped me. I was sure that the bindings worked
some other way or that my version of Tcl was responsible, but it just
turned out that I didn't understand how Tk works.
Tklish
Hmmm. Can't you just add the canvas' name directly to the bind?
set canvas .c
set frame $canvas.frame
pack [canvas $canvas]
$canvas create window 0 0 -window [frame $frame -width 100 -height 100 -bg red]
# someproc called with two parameters: widget name of click, and the fixed canvas name.
# Just make sure the canvas' name does not include any %-signs.
bind $frame <1> [list someproc %W $canvas]
proc someproc {w canvas} {
puts "button on widget $w, canvas is $canvas"
}
HTH
R'