Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Dragging *WINDOW* objects on a canvas ...

16 views
Skip to first unread message

sp...@controlq.com

unread,
May 1, 2008, 2:04:38 PM5/1/08
to

I've borrowed some code from the wiki to be able to drag and move objects
around on a canvas, and I'm attempting to drag a ttk::labelframe (WINDOW)
object. I've tagged it as movable, but the code does *NOT* seem to have
the desired effect.

Are WINDOW object on a canvas somehow different than other objects?

Sample code is attached to this message

Thanks for any pointers ...

Cheers,
Rob.

aaa

sp...@controlq.com

unread,
May 1, 2008, 3:35:18 PM5/1/08
to
Hmmm ... I added an oval, and I found that both the ttk::labelframe, and
the oval *WILL* move, but only if you grab them on the edge. I filled the
oval with a color and the problem goes away. I suppose I must put some
sort of handle on the ttk::labelframe ...

How can I get the binding to kick in if I click and hold button 1 anywhere
inside the labelframe? Is this possible???

Thanks in advance ...

Cheers,
Rob.
---- Posted via Pronews.com - Premium Corporate Usenet News Provider ----
http://www.pronews.com offers corporate packages that have access to 100,000+ newsgroups

Bruce Hartweg

unread,
May 1, 2008, 5:10:18 PM5/1/08
to
sp...@controlq.com wrote:
> On Thu, 1 May 2008, sp...@controlq.com wrote:
>>
>> I've borrowed some code from the wiki to be able to drag and move
>> objects around on a canvas, and I'm attempting to drag a
>> ttk::labelframe (WINDOW) object. I've tagged it as movable, but the
>> code does *NOT* seem to have the desired effect.
>>
>> Are WINDOW object on a canvas somehow different than other objects?
>>
>> Sample code is attached to this message
>>
>> Thanks for any pointers ...
>>
> Hmmm ... I added an oval, and I found that both the ttk::labelframe, and
> the oval *WILL* move, but only if you grab them on the edge. I filled
> the oval with a color and the problem goes away. I suppose I must put
> some sort of handle on the ttk::labelframe ...
>
> How can I get the binding to kick in if I click and hold button 1
> anywhere inside the labelframe? Is this possible???
>
instead of a canvas bind, add a normal bind to the labelframe itself
and trigger the move that way (you'll need to do a little extra work
to get the canvas coords from the raw window coords)

Bruce

Jeff Hobbs

unread,
May 1, 2008, 6:04:58 PM5/1/08
to

The issue is that you bind on the canvas, but the labelframe (or other
embedded widget) receives the events. You have to make sure it
doesn't respond or otherwise passes these to the canvas. It is
tricky, but if you look at projects like SpecTcl and GUI Builder, you
can see all the necessary code:
http://spectcl.sourceforge.net/

Jeff

sp...@controlq.com

unread,
May 2, 2008, 11:29:07 AM5/2/08
to
On Thu, 1 May 2008, Jeff Hobbs wrote:
>
> The issue is that you bind on the canvas, but the labelframe (or other
> embedded widget) receives the events. You have to make sure it
> doesn't respond or otherwise passes these to the canvas. It is
> tricky, but if you look at projects like SpecTcl and GUI Builder, you
> can see all the necessary code:
> http://spectcl.sourceforge.net/
>
> Jeff
>

hmmm, i can find the [winfo parent $lfrm] to get the path of the canvas.
I then need to map the %W widget path of the $lfrm to a canvas ID ...
and then apply the move algorithm to the newly found ID or tag which
corresponds to the lfrm widget.

Thanks for the hints guys ... I'll man and review the spectcl code, as
required.

sp...@controlq.com

unread,
May 2, 2008, 11:56:54 AM5/2/08
to
On Thu, 1 May 2008, Bruce Hartweg wrote:
> instead of a canvas bind, add a normal bind to the labelframe itself
> and trigger the move that way (you'll need to do a little extra work
> to get the canvas coords from the raw window coords)
>
> Bruce

Thanks gentlemen, I have got it working, both with canvas bindings, and
with general $lfrm bindings (a little less smooth than the canvas
binding), and I'm just trying to determine the best approach for my app.

keithv

unread,
May 2, 2008, 1:42:03 PM5/2/08
to
On May 2, 11:56 am, s...@controlq.com wrote:
> On Thu, 1 May 2008, Bruce Hartweg wrote:
> > instead of a canvas bind, add a normal bind to the labelframe itself
> > and trigger the move that way (you'll need to do a little extra work
> > to get the canvas coords from the raw window coords)
>
> > Bruce
>
> Thanks gentlemen, I have got it working, both with canvas bindings, and
> with general $lfrm bindings (a little less smooth than the canvas
> binding), and I'm just trying to determine the best approach for my app.

Could you post your solution so others can benefit from your
work?

Thanks,
K

sp...@controlq.com

unread,
May 2, 2008, 2:07:20 PM5/2/08
to
On Fri, 2 May 2008, keithv wrote:

>>> Bruce
>>
>> Thanks gentlemen, I have got it working, both with canvas bindings, and
>> with general $lfrm bindings (a little less smooth than the canvas
>> binding), and I'm just trying to determine the best approach for my app.
>
> Could you post your solution so others can benefit from your
> work?
>
> Thanks,
> K

Sure, sorry Keith

... while I'm still working on a more elegant solution, the problem is
identifying the window to the canvas, in order to perform the move
operation ... In the general case, the CanvasMarkIt very cleverly uses the
[$can find closest $x $y] to determine the id, but that has some
limitations, and requires a fiddly mouse positioning to pick up the window
object (thought it does indeed work). You just can't click on the middle
of the frame, and get the desired effect.

The original code for CanvasMarkIt was as follows:

proc CanvasMarkIt { x y can } {
global canvas
$can raise current
set x [$can canvasx $x]
set y [$can canvasy $y]
set canvas($can,obj) [ $can find closest $x $y ]
set canvas($can,x) $x
set canvas($can,y) $y
}

For embedded windows, I modified it as follows, to pass in the
ID of the embedded window. This I store in an array, indexed by the
widget path as follows:

set x [ttk::labelframe $c.lf0 -text Xyzzy]
set wdg($x) [$c create window 200 200 -window $x -tag movable]

proc WinMarkit { x y can id } {
global canvas
set x [$can canvasx $x]
set y [$can canvasy $y]
set canvas($can,obj) $id
set canvas($can,x) $x
set canvas($can,y) $y
}

bind $x <Button-1> {WinMarkit %x %y $c $wdg(%W)}
bind $x <B1-Motion> {CanvasDragIt %x %y $c}

This does not have the advantage of the canvas binding in the original
solution, where it just refers to the "closest" object ... but I suspect
that the "HALO" option in the canvas find closest might provide a more
general solution -- assuming you click "near the edge" of the window
object. If not that, then I'll need to find a way for the canvas to
return the canvas ID of the widget object ...

Great fun, and REALLY cool capability this ... and if/when I come up with a
more general solution which has some elegance, I'll post something which
might be actually useful.

sp...@controlq.com

unread,
May 2, 2008, 3:30:12 PM5/2/08
to

Actually, the code from the original post works just fine, with the
added addition of the -closeenough option when creating the canvas.

As the default for -closeenough is 1, I simply set it to 30, and lo and
behold, if the mouse pointer is within 30 pixels of the window, it will
move smoothly with just the default canvas bindings. It will *NOT*
however move when clicking on the window item, but this gives the added
advantage of allowing the window its own bindings which will not
interfere with its positioning on the canvas.

At this point, I think I'm done, as it serves my purpose, moves very
smoothly, and offers a consistent user interface which even *I* can
understand 8-).

I just love man pages 8-) ... Thanks for the pointers, guys.

0 new messages