1

I have been writing a program for a GUI based plotter using matplotlib and tkinter. I have added a toplevel window for some options. I want to execute a function and quit the toplevel window after clicking a button. Is that possible?


The problem that I face is that I have used a toplevel window which has to be called from the main window. SO I defined a function that contains this toplevel window. If I define another function that can do multiple operations, it cannot recognize the toplevel window. I could define it all under a class but am unsure if it works. Here's a part of my code that contains the toplevel window.

def plt_options(arg):
    global lg_var,col_var,line_type_var,marker_var

    plt_opt = Toplevel(app)

    lg_var = StringVar(None)
    lg_text = Label(plt_opt,text='Legend').grid(row=0,column=0,sticky=E)
    lg_box = Entry(plt_opt,textvar=lg_var)
    lg_box.grid(row=0,column=1,sticky=W)

    col_var = StringVar(None)
    col_var.set('blue')
    col_text = Label(plt_opt,text='Color').grid(row=1,column=0)
    col_chooser = OptionMenu(plt_opt,col_var,'blue','green','red','cyan',\
           'magneta','yellow','black','white')
    col_chooser.grid(row=1,column=1)

    line_type_var = StringVar(None)
    line_type_var.set('Solid')
    line_type_text = Label(plt_opt,text='Line type').grid(row=2,column=0)
    line_chooser = OptionMenu(plt_opt,line_type_var,'Solid','Dashed',\
                          'Dotted','Dash-Dotted','None')
    line_chooser.grid(row=2,column=1)

    marker_var = StringVar(None)
    marker_var.set('None')
    marker_text = Label(plt_opt,text='Marker').grid(row=3,column=0)
    marker_chooser = OptionMenu(plt_opt,marker_var,'Plus','Dot','Circle',\
        'Star','Pentagon','Square','Cross','Diamond','Hexagon','Triangle')
    marker_chooser.grid(row=3,column=1)    

    ok_btn = Button(plt_opt,text='OK',command=testing).grid()
ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
gaurab rimal
  • 11
  • 1
  • 2

2 Answers2

3

Buttons are designed for exactly this. Typically you would define a function or method that does whatever you want, then assign that method to the command attribute of the button:

import Tkinter as tk
import tkMessageBox

class SampleApp(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        button = tk.Button(text="Press me!", command=self.on_button)
        button.pack()
    def on_button(self):
        tkMessageBox.showinfo(message="Good-bye!")
        self.destroy()

app = SampleApp()
app.mainloop()
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Can I construct a class where I define the toplevel window and a function that can do multiple operations at a time? That is without constructing a separate class for the parent window. – gaurab rimal Jul 10 '12 at 18:09
  • @gaurabrimal: yes, of course. Buttons can call a function, and there's no limit to what that function can do. – Bryan Oakley Jul 10 '12 at 19:27
2

The command option of a button lets you specify a function/method/callable object which will be called when the button is pressed.

from Tkinter import *

def buttonClicked(event):
    do_a_thing()
    do_another_thing()
    do_a_third_thing()
    #etc

root = Tk()

myButton = Button(root, text="Do Some Things", command=buttonClicked)
myButton.pack()

root.mainloop()

You can quit a window by calling its destroy method.

you seem to have another problem, which is that you can't destroy the top level window from inside the callback function, if you aren't in the scope that created the window. If you don't want to define a whole class just to hold a reference to the window, you can nest your function definitions:

from Tkinter import *

def makeMyWindow():
    root = Tk()
    def buttonClicked():
        print "Reticulating Splines..."
        print "Done. Goodbye!"
        #we can access root since we're inside the right scope, 
        #even if this function gets passed somewhere else as a callback
        root.destroy()
    myButton = Button(root, text="Do Some Things", command=buttonClicked)
    myButton.pack()

    root.mainloop()

makeMyWindow()
Kevin
  • 74,910
  • 12
  • 133
  • 166
  • 2
    In the case of a button, this is even easier: `myButton = Button(root, text="Do Some Things",command=buttonClicked)` (Look mom, no `bind`!) – mgilson Jul 09 '12 at 20:29
  • You shouldn't set a `<1>` binding on a button; use the built-in `command` attribute. Otherwise you're circumventing some of the features of Tkinter, such as the ability to navigate the app with the keyboard and invoke buttons with a button press (among others) – Bryan Oakley Jul 10 '12 at 01:15
  • @Kevin: now your first sentence says you can add a binding, but your example doesn't have anything to do with bindings. It might be a bit confusing to someone new to Tkinter. – Bryan Oakley Jul 10 '12 at 19:29