9

I have written an application in python 2.7 and tkinter. I created a tool bar with several buttons that open up respective top windows that display various options. I used ttk.Checkbutton with the 'toolbutton' style as an indicator to show whether the option windows are open or closed.

The problem is that the option windows will go to the back if another window is selected. Currently, if one selects the toolbutton again, the option window will close. However, I only want to close the window if it is on top. If the option window is not on top, I want the window to moved to the front.

Some of the code I have working:

class MainWindow:
    def __init__(self,application):
        self.mainframe=tk.Frame(application)
        application.geometry("900x600+30+30")

        self.otherOptionsSelect=tk.IntVar()
        self.otherOptions_Button=ttk.Checkbutton(application,style='Toolbutton',variable=self.otherOptionsSelect,
                                                onvalue=1, offvalue=0,image=self.optionsIcon, command=self.otherOptions)
    def otherOptions(self):

        if self.otherOptionsSelect.get()==0:
            self.otherOptions.destroy()
            return

        self.otherOptions=tk.Toplevel()
        self.otherOptions.title("IsoSurface Options")
        self.otherOptions.geometry("200x165+"+str(int(application.winfo_x())+555)+"+"+str(int(application.winfo_y())+230))

        self.otherOptApply_button=ttk.Button(self.otherOptions,text="Apply",command=self.showFrame)
        self.otherOptApply_button.place(x=20,y=80,width=50,height=30)

        self.otherOptClose_button=ttk.Button(self.otherOptions,text="Close",command=self.otherOptionsClose)
        self.otherOptClose_button.place(x=80,y=80,width=50,height=30)

    def otherOptionsClose(self):
        self.otherOptionsSelect.set(0)
        self.otherOptions.destroy()

Here is a picture of the entire application I have written: enter image description here

In the above image, each window has their respective ttk.checkbutton. At the moment, toggling the checkbutton either opens or closes the window. However, what I really want it to do is close the window if the window is in front of the application, or bring the window to the front if it is behind the application.

Hopefully this clears some things up.

Thanks in advance!

Onlyjus
  • 5,799
  • 5
  • 30
  • 42
  • If you choose a checkbutton, won't the window with the checkbutton always be on top, or do you have a window manager that lets you click buttons on background windows? – Bryan Oakley Apr 27 '12 at 10:46
  • Maybe I should clear this up a little. I have a "main window" on which there is a tool bar with multiple checkbuttons. Each checkbutton opens/closes a "toplevel" window, however the "main window" is still active. The "toplevel" windows are not always on top of the "main window", they can go to the background. Maybe I will try to post some pictures. – Onlyjus Apr 27 '12 at 12:28
  • I tried posting an image however I need more reputation... – Onlyjus Apr 27 '12 at 12:44
  • so, if one of these other windows is on the screen but behind the main window, what should happen? It's not literally on top, so do you want it deleted? – Bryan Oakley Apr 27 '12 at 23:07
  • other windows is on the screen but behind the main window, I want to bring the window to the front. I have a picture that would clear it up I just need 1 more reputation!!!!! – Onlyjus Apr 28 '12 at 15:51
  • Perhaps it would be possible to create a binding on each window so you could track the order in which they overlay ? ie. a button-1 binding, that tracks focus changes ... – Niall Byrne Apr 30 '12 at 02:22
  • That might not always work. That would just give me the order in which each window is generated. Odds would be that the "older" windows would be in back, however not always. – Onlyjus Apr 30 '12 at 20:16

1 Answers1

10

It is in fact possible to check stacking order of windows. Using Tkinter, you have to do some funny tcl evals to get at the information. I found the answer at TkDoc in the section on Windows and Dialogs, scroll down until you get to "Stacking Order". The code baffled me until I started playing around with it interactively. My test code was:

import Tkinter as tk
root = tk.Tk()
root.title('root')
one = tk.Toplevel(root)
one.title('one')
two = tk.Toplevel(root)
two.title('two')

I then manipulated the windows so that two was on top, one under that and root below them all. In that configuration, the following weirdness can tell you relative layering of windows:

root.tk.eval('wm stackorder '+str(two)+' isabove '+str(root))

returns 1, meaning "Yes, window two is above window root." While the following:

root.tk.eval('wm stackorder '+str(root)+' isabove '+str(two))

returns 0, meaning "No, window root is not above window two." You can also use the command:

root.tk.eval('wm stackorder '+str(root))

Which gives back the full window stacking order in the form of a weird string something like this:

'. .68400520L .68401032L'

Which starts to make sense when you run the commands:

str(root)
str(one)
str(two)

and figure out that root has the internal name '.', one is '.68400520L' and two is '.68401032L'. You read the output of root.tk.eval('wm stackorder '+str(root)) backwards so it's saying two is on top, one is under that and root is below both.

John Gaines Jr.
  • 11,174
  • 1
  • 25
  • 25
  • In Python 3.8, tkinter no longer uses random strings of numerals as references to widgets so the window stacking order output would be: `. .!toplevel .!toplevel2`. The root is still a dot. – Luther Sep 16 '20 at 05:55