How do you make two windows act as one?

Zipguy (2013-01-13) - My email is zipguypub @ thefreesite dot com please change the dot to a ".".

I'm working on ML - Heavily Modified & Improved, which I like a lot. It is available there with the one I've currently released. I've got a new problem.

I've been using TCL for a while, on Windows. I'm on a Windows laptop. I've decided to run it as two windows, from TCL terms (. and .proc). This maximizes the space for the main window. Now I have two windows running as one application, called ML v1.25b, which has not been released yet. It looks like this:

It works well. Even if you have closed the "Procedures" window, it's easy to re-open it, by using the "Window" menu (you can switch to another window and switch back to the one you were on, if you only have one entry under the Windows menu, you can make another by the File->New, and then you have two entries).

So my question is:

How can I make these two windows act as one.

For example, when the main one has been minimized, the remaining one, Procedures, remains unaffected. I have to minimize it also. And, visa versa when the main one has been restored, I have to restore the Procedure window also. I've been looking of into the TCL manual, which is rather large, and I thought it would be easier to ask this question here. I think I need to know when the "Minimize" button is pressed, put a bind or bindtag on that to tell the wm to minimize the Procedure window also. Also I need to know when they're restoring the windows also, in a likewise fashion. Thanks for any help in advance.

I categorized it as Tk. I hope that's right

RLE (2013-01-13): You need to read up on the Tk bind command, specifically upon the Map and Unmap events. You will need to use bind to cause a proc to be executed whenever a Map or Unmap event occurs, and perform the appropriate wm iconify or wm withdraw command on all the windows you want to act the same in response to the relevant event.

Zipguy (2013-01-14) - Greets RLE. I found a sample program at the end of the "bind" page, so I tried making an example out of it. This is what I had

        package provide app-bindb 1.0
        #  zipguy - routine added for puts with date %Y-%m-%d and time 
        proc puts_log {message {code 0}} {
        set time [clock format [clock seconds] -format "%Y-%m-%d %I:%M:%S %p"]
        puts "$time  $message"
        };# END-PROC

        console show
        puts_log "Just Strarting Now."
        toplevel .procs
        set keysym "Press any key"
        pack [label .l1 -textvariable keysym -padx 2m -pady 1m]
        bind . <Key> {set keysym "You pressed key: %K"}
        set map "         "
        pack [label .l2 -textvariable map -padx 2m -pady 1m]
        bind . <Unmap>        {
                set map "Just Unmaped"
                puts_log $map
                wm iconify .procs
                puts_log "wm state is: [wm state .procs]" 
        bind . <Map>                        {
                set map "Just Maped"
                puts_log $map
                wm deiconify .procs
                puts_log "wm state is: [wm state .procs]" 

It turned out terrific. Both the window .proc and the . one behave properly when Minimzed (or Restored), because they do act like ONE window.

One curious thing that I noticed was that the Unmap (or Map) events, seem to occur in threes.

Don't know why? It did not seem to matter, even though I seemed to be executing them three times. Anyway, thanks RLE.

Zipguy (2013-01-15) - Ah.... I figured it out. The Map/Unmap events occur once for each element that exists in the window that is in progress of being Mapped/Unmapped.

I found this when I was exploring the behavior of the Console window in console - work with the parent window. This is where I was attempting to get the Console window to behave in a similar fashion. It is so far unsolved, but it did occur there about thirty+ times in there each time the main window was being Mapped/Unmapped.

RLE (2013-01-15): Yes, the <Map> and <Unmap> events are delivered to all child windows of each toplevel window. If you don't want to run multiple wm iconfiy/deiconify calls then you need to filter out all but the toplevel window names. I.e. something like:

proc is-toplevel? { win } { expr { [ winfo toplevel $win ] eq $win } }

bind . <Map> [ list map-unmap %W ]

proc map-unmap { win } {
  if { ! [ is-toplevel? $win ] } { return }
  # ... do processing on toplevel window here

If you are using Tcl 8.5, you can filter in a fancier way:

proc return-if-not-toplevel { win } { if { [ winfo toplevel $win ] ne $win } { return -code return } }

bind . <Map> [ list map-unmap %W ]

proc map-unmap { win } {
  return-if-not-toplevel $win

  # ... only get here if $win contains a name of a toplevel

Zipguy (2013-01-15) - I only have one more problem. In fact, it always seems to initially be on the console at first. Also, when I've clicked on the Appliction's minimize button, and I've clicked on the Application's Name to Restore it, both windows come back, but the focus has switched to the .console Window (instead of the Application's main window). I tried making the bind Map into focus on .toolbar, the main window, but now it always seems to focus on the console instead, until I click on the Application's window. hmmmm...

RLE (2013-01-15): Why don't you try focusing the text widget instead of the toolbar? It may be that the toolbar simply does not accept focus.

Also, are you running on Windows or Linux? It matters because in Windows the window on top always has focus. So you might try raising "." before attempting to focus to it.

Zipguy (2013-01-15) - I'm running Windows 7.0. I have it like this in ezsdx.tcl:

 bind . <Unmap>                "console eval { wm iconify   .}"
 bind . <Map>                "console eval { wm deiconify .} ; focus .toolbar "

where . is the console window, and .toolbar is defined in ezsdx.tcl. I'm running two discussions at once. One also in console - work with the parent window. That page was created in response to this one, later. That's because I was trying to make the console be paired with the application that opened the console, which I consider a larger issue. I have it implemented in ML1.25c (which is a slightly newer version than v1.25b, which is seen above in the first screenshot). Does this make sense to you RLE?

RLE (2013-01-15): Try replacing "focus .toolbar" with "focus .". Also try adding a "raise ." just before "focus .toolbar". Also try instead of "focus ." running focus upon the text widget within the main application window.

Zipguy (2013-01-15) - I tried the following in the bindb.tcl with a slight change in the Map bind:

  bind . <Map>                        {
    set map "Just Maped"
    puts_log $map
    wm deiconify .procs
    focus .l1
    puts_log "wm state is: [wm state .procs]" 

and now it's working perfectly.

  • I minimize the bindb window, and both get minimized
  • When I restore the bindb, from the Windows toolbar, both get restored, and most important, the bindb window still has focus!

RLE (2013-01-16): Glad to know it works now. One tip however. It is best to place the code executed by a bind into a proc, and have the binding call the proc, rather than place the code directly in the binding itself. This produces several advantages:

  1. bind scripts run in the global namespace. Your example above just implicitly created a global variable named "map". This pollutes the global namespace with extraneous variables, and as well creates the possibility of several bindings stepping on each others variables in strange ways. Read this last one as "quite hard to debug". Using a proc avoids polluting the global namespace.
  2. You avoid arriving in quoting hell.
  3. You can more easily pass parameters to the proc to instruct it what to do as a result of the call.
  4. The actual code of the proc will get byte compiled. This will result in the binding code executing more quickly.

I.e., your code above could be:

proc mapwin { win } {
  puts_log "Just Maped $win"
  wm deiconify .procs
  focus .l1
  puts_log "wm state is: [wm state .procs]" 

bind . <Map> [ list mapwin %W ]

Zipguy (2013-01-21) - Here us the program which is working just fine with two windows, which is extremely small (1.1k). You can Minimize one window, and the other one minimizes. If you restore the main window, the other one will restore also. It's called bindb.kit which is at [L1 ]. Here's where the bindb Source Code is.