Fares Al Ghazy
Fares Al Ghazy

Reputation: 55

Tkinter creates unexpected additional blank window

I am using Python 3.5 to create a simple GUI that takes in information from the user via a textbox, then saves to a .txt file.

What I've noticed is the following:

  1. The SaveButton is automatically clicked at startup, but clicking again does nothing;
  2. An additional, blank window, named tk, appears in the foreground.

This is my first GUI python application, so simplicity and patience are appreciated.

Here is the code:

#Program by Fares Al Ghazy started 20/5/2017
#Python script to assign key combinations to bash commands, should run in the background at startup
#Since this program is meant to release bash code, it is obviously non-system agnostic and only works linux systems that use BASH
#Further versions which support more OSs may come to life
#This is one file which only creates the GUI, another file is needed to use the info taken by this program

import tkinter as tk
#function to write to file
def SaveFunction(e1,e2):
    print("opening file")
    file = open("BinderData.txt","a")
    combo = e1.get()
    print("combo =" + combo)
    performed = e2.get()
    print("action = " + performed)
    print("Writing to file")
    file.write(combo)
    file.write(performed)
    print("closing file")
    file.close()
    print("file closed")

class MainFrame(tk.Tk):
    def __init__(self,*args,**kwargs):
        tk.Tk.__init__(self,*args,**kwargs)
        #create GUI to take in key combinations and bash codes, then save them in file
        root = tk.Tk() # create new window
        root.wm_title("Key binder") #set title
        #create labels and text boxes
        KeyComboLabel = tk.Label(root,text = "Key combination = ")
        KeyComboEntry = tk.Entry(root)

        ActionLabel = tk.Label(root, text = "Command to be executed = ")
        ActionEntry = tk.Entry(root)
        #place widgets in positions
        KeyComboLabel.grid(row=0,column =0,sticky = tk.E)
        ActionLabel.grid(row=1,column =0, sticky = tk.E)

        KeyComboEntry.grid(row=0,column =1)
        ActionEntry.grid(row=1,column =1)
        #create save button
        SaveButton= tk.Button(root,text = "save")
        SaveButton.grid(row=2,column =2, sticky = tk.E , command = SaveFunction(KeyComboEntry,ActionEntry))

app = MainFrame()
app.mainloop()

Upvotes: 2

Views: 1393

Answers (1)

tobias_k
tobias_k

Reputation: 82899

  1. You execute the SaveFunction callback and bind the result to the command parameter; try a lambda expression instead. Also, the command parameter has to go to the constructor, not to the layout function.

    SaveButton= tk.Button(root,text = "save", command = lambda: SaveFunction(KeyComboEntry,ActionEntry))
    SaveButton.grid(row=2,column =2, sticky = tk.E )
    
  2. You get the additional empty window because you create two Tk instances, the first being the MainFrame itself, extending Tk, and the second the Tk() you create in __init__. Instead of creating another Tk, just use self as root:

    root = self # or change all "root" to "self" in the code below
    

    Or don't have MainFrame extend Tk.


Some more clarification about the command callback part and lambda. The problem, as I said, is that you execute the function and then bind the result of that execution to command. To make this clearer, command=SaveFunction(KeyComboEntry, ActionEntry) is the same as

cmd = SaveFunction(KeyComboEntry, ActionEntry)
SaveButton= tk.Button(root, text="save", command=cmd)

which is obviously not what you want. If you would call a function with no parameters, you could just use command=SaveFunction without (), thus not calling the function but using the function itself as a parameter, but since SaveFunction needs parameters, you have to define an in-line lambda, calling SaveFunction, which itself takes no parameters.

Upvotes: 1

Related Questions