PracTCL Programming Tips

This month, we inaugurate a bimonthly column for Tcl/Tk programmers. Stephen Uhler will cover some useful but perhaps poorly-known or poorly-understood features of the Tcl language and the Tk windowing toolkit.
What a Drag

For our second example, we'll use the placer to permit a user to interactively “drag and drop” a widget within a window. When the user selects a widget, by clicking on it with the mouse, we'll lift it up so it hovers over the window, and casts a shadow as we drag it around. Releasing the mouse drops the widget in its new location.

label .label -text "drag me"\
  -borderwidth 3 -relief raised
frame .shadow -bg black
lower .shadow .label
place .label -x 50 -y 50
set hover 5

We'll start by creating a widget to drag, .label, and its shadow .shadow. We'll use lower to make sure the shadow is always “below” the widget, and we'll start .label in an arbitrary location, 50 pixels from the top left corner of .. The variable hover controls how high we'll lift the widget above its window as we drag it.

bind .label <1> {
    array set data [place info .label]
    place .label -x [expr $data(-x) - $hover]\
                 -y [expr $data(-y) - $hover]
    place .shadow -in .label -x $hover -y $hover \
                  -relx 0 -rely 0 -relwidth 1 \
                  -relheight 1 -width -2 -height -2 \
                  -bordermode outside
    set Rootx [expr %X - [winfo x %W]]
    set Rooty [expr %Y - [winfo y %W]]

When we first click on .label, we need to lift it up, add its shadow, and compute where it is relative to the root window so we can figure out how to move it. The array set command (new in tcl7.4), takes name-value pairs and creates an array from them. Fortunately, the place info command happens to report the current place options in the form of name-value pairs, permitting us to access and modify individual place options using array accesses. The first place command simply moves the widget up and to the left $hover pixels as we first press the mouse. I think the second place command, which positions the shadow, uses every available place option!

The -in option, which would more accurately be described as “relative to”, causes all locations specified in .shadow to be relative to .label, instead of ., which would be the default. The -x and -y options, when added to -relx and -rely, position the shadow where .label was before we $hovered it. The -relwidth and -relheight options make .shadow the same size as .label, and then the -width and -height options make the shadow a little smaller, so it will appear farther away. Finally, the -bordermode option instructs the placer to include the border of .label when computing the sizes for -relwidth and -relheight.

Finally, we compute the location of the mouse cursor, in pixels, relative to the top left corner of the root window (Rootx, Rooty), so it will be easier to figure out how to track .label with the mouse.

bind .label <B1-Motion> {
    place .label -x [expr %X - $Rootx] \
                 -y [expr %Y - $Rooty]

As the mouse moves, we reposition the widget to follow along. Because we “placed” the shadow relative to the widget (using the -in option), it tags along all by itself.

bind .label <ButtonRelease-1> {
    array set data [place info .label]
    place .label -x [expr $data(-x) + $hover] \
                 -y [expr $data(-y) + $hover]
    place forget .shadow

When we release the mouse button, the same array set trick as before is used to “drop” the widget back on the window, then remove the shadow.

As you can hopefully see from these two simple examples, the “placer” can be a powerful tool for the dynamic placement of widgets in Tk.

Stephen Uhler is a researcher at Sun Microsystems Laboratories, where he works with John Ousterhout improving Tcl and Tk. Stephen is the author of the MGR window system and of PhoneStation, a TCL-based personal telephony environment. He may be reached via email at Stephen.Uhler@Eng.Sun.COM.


White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState