Version 6 of Move any widget

Updated 2010-03-17 21:44:08 by AMG

SeS: In my quest to develop a gui generator, I have reached a stage in which I need to provide the user the ability to explore widgets placement and do a quick and easy form layout design. Same idea as some of us are already familiar with within Visual Basic and C++. The code presented here is a simplified version in order to be able to share it with a wider tcl/tk community, from newbie to guru.

The code as presented is developed in & for (yes, the tool is creating itself) tG2 v1.06.01

Some limitations which have already been solved in tG2:

  - the titlebar height and framewidth of a toplevel is assumed fixed
  - when widgets are placed in frames, it will create another offset which needs to be taken into account, recursively...

The presented code is tested with tcl/tk v8.4.19 & WinXP OS.

# ------------------------------------------------------------------------------
bind . <Configure> {set components(geo) [split [split [wm geometry .] "x"] "+"]}

# ------------------------------------------------------------------------------
bind . <Motion> {
  if {$components(moveObject) != ""} {
    place $components(moveObject) \
      -x [expr [winfo pointerx .] - [lindex $components(geo) 1] - 3  - $objectXoff] \
      -y [expr [winfo pointery .] - [lindex $components(geo) 2] - 29 - $objectYoff]
  }
}

# ------------------------------------------------------------------------------
proc makeMovableObject {w} {
  set cmd "bind $w  <Motion>    \{$w config -cursor crosshair\}"; eval $cmd
  set cmd "bind $w  <Leave>     \{$w config -cursor \"\"\}"; eval $cmd
  set cmd "bind $w  <ButtonPress-1>   \{+; 
    set objectXoff \[expr %x]
    set objectYoff \[expr %y]
    set components(moveObject) $w
    eval \[bind . <Motion>\]
  \}"
  eval $cmd
  
  bind $w <ButtonRelease-1> {+; 
    set components(moveObject) ""
  }
}

set components(moveObject) ""
eval [bind . <Configure>]

# ---------------------------------- TEST CODE ---------------------------------
button .button1 -text "hello world"
place .button1 -x 50 -y 50
makeMovableObject .button1

label .label1 -text "hello again"
place .label1 -x 50 -y 80
makeMovableObject .label1

AMG: Is there any particular reason why the braces backslashed inside of double quotes? e.g. "foo \{ bar \} quux" As far as I know, this is only necessary when a brace-quoted string (here, the third argument to proc) contains mismatched braces, and this is necessary even outside double quotes, for instance in comments. Maybe you're just doing it out of stylistic preference, which is just fine.

Also I am curious about this use of eval. Why put the script inside a variable? Just pass it to eval directly. I can see why you're tempted to use eval, since you want substitutions to take place inside braces, but you can usually just run bind directly and avoid quoting hell by leveraging the list command:

bind $w <Motion> [list $w config -cursor crosshair]

Here, you also have the option of using the %W bind substitution, which is replaced with the window name. It works the same as %x and %y, which you already use.

You use "eval [bind . <Motion>\]" to execute the script associated with the <Motion> event. You can also use the [event generate command to do pretty much the same thing. Or you can use {*} instead of eval: "{*}[bind . <Motion>]". Also I suggest putting your bind scripts in procs to simplify the argument to bind, to make them easier to call, and to improve performance (this makes bytecode compilation possible). For example:

proc click {w x y} {
    global objectXoff objectYoff components
    set objectXoff $x
    set objectYoff $y
    set components(moveObject) $w
    event generate $w <Motion>
}
bind $w <ButtonPress-1> {click %w %x %y}

Try to avoid using <Motion> when you can just use <Enter>. But in this application, you shouldn't need bindings for setting the cursor anyway. Just set the cursor for the widget once, and the window system will automatically change the mouse pointer to match the cursor of the widget it's currently on.

Another question: what is expr doing? The only thing I can think of is that it forces the internal representation of %x and %y to be a number, but this is going to automatically happen anyway so there's no need to be explicit.

While I'm on the subject of expr, you really should brace your expr-essions in your <Motion> binding for the "." widget. This improves both performance and security.


Fabricio Rocha - 14 Mar 2010 - Very interesting project, Lars.... Is there any way to contact you? I found no info in your page...

SeS - 2010-03-17 08:30:21

Fabriccio, I am sorry that I created a confusion here by omitting/forgetting my initials (SeS or SES_home). For some reason, Lars made an update or something and the page is written on his name, I think this is not on purpose, something he or myself did wrong during page creation? I do not want to reveal my real name yet to prevent any email communication at this moment. I am an electronics engineer working for a semicon company, so I have a daytime job, this project is a private project, so you do understand that I am kind of bizzy, that's the reason. Thank you though for your interest, please follow me on the progress by subscribing to the youtube account. As soon as I am confident I have a sharable version of tG2 I will let the world know.

Of course dont hesitate to ask me questions via this channel, as soon as I have time and check out these pages, I will try answer your questions. Regards, SeS.

Lars H: Indeed, I was just gnoming by (fixing spelling of category name). Content one wants to take credit for should carry some sort of signature.


SeS - 2010-03-17 09:09:58

Thanks Lars! Also, for the record:

This is the first page I created at wiki.tcl.tk, but I have more contributions by commenting to initiatives by other enthusiasts/developers:

Ctext

Drag and Drop

And now I really have to go back to work...

Regards, SeS