Python Tkinter Toplevel runs without calling - python

Hello I have some very simple python code:
from Tkinter import *
from tkFileDialog import askopenfilename
def createnewguiprojectgui():
asktk = Toplevel()
asktk.title("Create new gui source")
Label(asktk, text="Gui options").pack(side=TOP)
askfilename = Entry(asktk)
askfilename.insert(0, "Source name")
askfilename.pack(side=LEFT,fill=X)
yesfornew = Button(asktk, text="cancel", command=createnewguiproject())
nofornew = Button(asktk, text="cancel",command=) #a command
def createnewguiproject():
pass
def main():
mainparent = Tk()
w, h = mainparent.winfo_screenwidth(), mainparent.winfo_screenheight()
mainparent.title("GUI CREATOR")
mainmenu = Menu(mainparent)
filemenu = Menu(mainmenu,tearoff = 0)
filemenu.add_command(label="New project", command = createnewguiprojectgui())
mainmenu.add_cascade(label="File", menu=filemenu)
separator = Frame(height=2, bd=1, relief=SUNKEN)
separator.pack(fill=X, padx=5, pady=5)
mainparent.config(menu=mainmenu)
mainmenu.focus_set()
mainparent.mainloop()
if __name__ == "__main__":
main()
However, every time I run ths script, the asktk toplevel pops up with the mainparent Tk, even if I don't press the menu bar, and the focus is set to asktk. Whats wrong?

The command here is calling the function that creates a new window object onload rather than when New Project is selected.
filemenu.add_command(label="New project", command = createnewguiprojectgui())
You need to change it to:
filemenu.add_command(label="New project", command = createnewguiprojectgui)

Try this: in the line that has ...
filemenu.add_command(label="New project", command = createnewguiprojectgui())
take the () off the end of createnewguiprojectgui. In other words, pass the function, don't call it.
The same should be true for the following line ...
yesfornew = Button(asktk, text="cancel", command=createnewguiproject())

Don't call the function command=createnewguiproject(). Remove the (). Your createnewguiproject() method gets called as soon as the main loop starts.
Do this:
yesfornew = Button(asktk, text="cancel", command=createnewguiproject)
Or if you want to send some argument then:
yesfornew = Button(asktk, text="cancel", command=lambda:createnewguiproject(args))

Related

Tkinter gives following error in python 3.6: TclError: NULL main Window

I am writing a python program which executes the following sequence:
1. Dialog box to open/select a directory
2. perform certain operations
3. rename the file using a tkinter dialog box
4. Perform rest of the operations
I have written the following code:
def open_directory():
directory_name = filedialog.askdirectory(title='Ordner Auswählen',parent=root)
print(directory_name)
root.destroy()
def input_name():
def callback():
print(e.get())
root.quit()
e = ttk.Entry(root)
NORM_FONT = ("Helvetica", 10)
label = ttk.Label(root,text='Enter the name of the ROI', font=NORM_FONT)
label.pack(side="top", fill="x", pady=10)
e.pack(side = 'top',padx = 10, pady = 10)
e.focus_set()
b = ttk.Button(root, text = "OK", width = 10, command = callback)
b.pack()
def close_window():
root.destory()
root = tk.Tk()
root.withdraw()
open_directory() #dialogue box to select directory
<perform certain operations>
input_name() #dialgue box for user input file name
root.mainloop()
close_window() #exit the mainloop of tkinter
<perform rest of the functions>
but I get the following error
Tclerror: NULL main window
I think it is realted to declaring root as the main window, but I dont seem to find where I have made the mistake.
Is there some other method, which is better, for what I am trying to do here?
As #CommonSense has mentioned, when you use withdraw to hide the main window, then you need to use the method deiconify to use the root again. Hence, change the function change_directory as follows:
def open_directory():
directory_name = filedialog.askdirectory(title='Ordner Auswählen',parent=root)
print(directory_name)
root.deiconify()
If you do not deiconify the window, you could not call the function input_name, which makes use of the root window.
I have tested this code and it works.
PS: You also have a typo in the function close_window (when destroying the window).
Your use of .destroy() and .quit() as #CommonSense truly said do not really seem well planned.
Not only that, you need to use triggers or events to control your function calls, else they just run straight the one preventing the other from running as is the case in your code.
You should also control when close_window() is called with an event:
from tkinter import filedialog
import tkinter as tk
def open_directory():
directory_name = filedialog.askdirectory(title='Ordner Auswählen',parent=root)
print(directory_name)
#root.destroy()
input_name()
def input_name():
def callback():
print(e.get())
#root.quit()
es_variable=tk.StringVar()
e = tk.Entry(root, textvariable=es_variable)
NORM_FONT = ("Helvetica", 10)
label = tk.Label(root,text='Enter the name of the ROI', font=NORM_FONT)
label.pack(side="top", fill="x", pady=10)
e.pack(side = 'top',padx = 10, pady = 10)
e.focus_set()
b = tk.Button(root, text = "OK", width = 10, command = callback)
b.pack()
def close_window():
root.destory()
root = tk.Tk()
#root.withdraw()
open_dir_button = tk.Button(root, text = "Open Dialog", width = 10, command =open_directory)
open_dir_button.pack()
#dialogue box to select directory
#<perform certain operations>
#dialgue box for user input file name
root.mainloop()
#close_window() #exit the mainloop of tkinter
#<perform rest of the functions>

Tkinter module - program will just run then stop and won't open the window

I need help, I am doing a budget calculator and using tkinter for the first time and wondered why it is not working...
When I run it, it will just end straight away and when I put the root = Tk() at the end it comes up with an error.
I really need help, my code is below...
from time import sleep
from tkinter import *
from tkinter import messagebox, ttk, Tk
root = Tk()
class GUI():
def taskbar(self):
menu = Menu()
file = Menu(menu)
file.add_command(label="Exit", command=self.exit_GUI)
file.add_command(label = "Information", command=self.info_popup)
def Main_Menu(self):
topFrame = Frame(root)
topFrame.pack()
bottomFrame = Frame(root)
bottomFrame.pack(side=BOTTOM)
Income_button = Button(topFrame, text="Enter your incomes", command=self.Income)
Expense_button = Button(topFrame, text="Enter your expenses", command=self.Expense)
Total_button = Button(bottomFrame, text="View Results", command=self.Total)
Income_button.pack()
Expense_button.pack()
Total_button.pack()
def Income(self):
pass
def Expense(self):
pass
def Total(self):
pass
def exit_GUI(self):
exit()
def info_popup():
pass
g = GUI()
g.Main_Menu()
g.taskbar()
g.Income()
g.Expense()
g.Total()
g.exit_GUI()
g.info_popup()
root.mainloop()
You are exiting before you ever get to the mainloop with:
g.exit_GUI()
That method is calling the standard exit() and stopping the entire script. Remove or comment out the above call. You will also need to add self as an argument to info_popup to get your script to run:
def info_popup(self):
pass

don`t succed in make one python file run another

I am trying to make one python file run another only if the user choose that option, and every time it runs the another file no matter what happened.
I have two options:
If the user chose option 1: the code needs to run SendMenu file.
If the user chose option 2: the code needs to run RecvimagesMenu file
but it doesn't work like I want, it opens the SendMenu file when I run the code.
Code:
import sys
from Tkinter import *
import Image, ImageTk
import SendMenu
import RecvimagesMenu
mGui = Tk()
def mhello():
global v
if(v.get() == 1): # if the user chose option 1
mGui.destroy()
SendMenu.run()
if(v.get() == 2): # if the user chose option 2
mGui.destroy()
RecvimagesMenu.run()
else: # if the user didn`t choose any option
print "5"
def Action():
global v
print (v.get())
def close(): # close the window
exit()
def menu():
global v
v = IntVar()
menubar = Menu(mGui) # menu
filemenu = Menu(menubar, tearoff=0) # menu works
filemenu.add_command(label="Close", command=close)
menubar.add_cascade(label="File", menu=filemenu)
mGui.geometry('450x300+500+300')
mGui.title('Nir`s ScreenShare')
canvas = Canvas(mGui, width=500, height=150)
canvas.pack(pady = 10)
pilImage = Image.open("logo5.png")
image = ImageTk.PhotoImage(pilImage)
imagesprite = canvas.create_image(0, 0, image=image, anchor="nw")
Radiobutton(mGui, text="Share My Screen ", variable=v, value=1, command = Action).pack(anchor=CENTER)
Radiobutton(mGui, text="Watch Another`s Screen", variable=v, value=2, command = Action).pack(anchor=CENTER, pady = 7.5)
mbutton = Button(mGui, text='Start', command=mhello).pack() # button\
mGui.config(menu=menubar) # menu helper
mGui.mainloop()
menu()
The problem you have is when you import your python file into the other one, it runs all of the code. Since you have not given the code for those 2 I can make an educated guess. You are not putting the code in those files into functions
for example:
def printme( str ):
print("str"
print"Hello world again"
If this was in a RecvimagesMenu.py as soon as you import the code it would print "Hello world again" and then you call RecvimagesMenu.printme("hello world") it would print the "Hello world".
In your file you also have code not in functions which is being executed right away. Either remove this code or move it into functions and call them.

How do you close a tkinter window in another function?

I want a button in my window to open a new window and close the previous one. Is it possible to have one button do both of these? I've tried in the following code, but it hasn't worked, just told me that window is not defined:
import tkinter
def window1():
window = tkinter.Tk()
tkinter.Button(window, text = "Next", command = window2).pack()
window.mainloop()
def window2():
window.destroy() #This is where the error is
menu = tkinter.Tk()
etc, etc, etc
window1()
First, you need to return the window object from the first function:
def window1():
window = tkinter.Tk()
tkinter.Button(window, text = "Next", command = lambda: window2(window)).pack()
window.mainloop()
return window
Then, you need to pass the window as an argument to your function:
def window2(window):
window.destroy()
menu = tkinter.Tk()
And then call window1 with:
window = window1()
and click the button to destroy it and do the rest
This is an example using Toplevels, which is usually a better choice than creating, destroying, re-creating Tk() instances. The unique Toplevel ID is passed to the close_it function using partial(). You would, of course, combine them or have the close function call the open function.
try:
import Tkinter as tk ## Python 2.x
except ImportError:
import tkinter as tk ## Python 3.x
from functools import partial
class OpenToplevels():
""" open and close additional Toplevels with a button
"""
def __init__(self):
self.root = tk.Tk()
self.button_ctr=0
but=tk.Button(self.root, text="Open a Toplevel",
command=self.open_another)
but.grid(row=0, column=0)
tk.Button(self.root, text="Exit Tkinter", bg="red",
command=self.root.quit).grid(row=1, column=0, sticky="we")
self.root.mainloop()
def close_it(self, id):
id.destroy()
def open_another(self):
self.button_ctr += 1
id = tk.Toplevel(self.root)
id.title("Toplevel #%d" % (self.button_ctr))
tk.Button(id, text="Close Toplevel #%d" % (self.button_ctr),
command=partial(self.close_it, id),
bg="orange", width=20).grid(row=1, column=0)
Ot=OpenToplevels()
Yes. Is possible. But you'll need to def that:
def window1:
blablabla
blablabla
def window2:
window2.destroy() <-- Here where the error was
How you noticed, put your name of window what you want Destroy and it will work!
using Python3
You could use a "global" such as:
root = Tk()
root.title('This is the root window')
def window_create():
global window_one
window_one = Tk()
window_one.title('This is window 1')
Then, from any function (or elsewhere) when you want to destroy window_one, do:
def window_destroyer():
window_one.destroy()
You could call your window_destroyer function from a button anywhere such as root which the example shows:
kill_window_btn = Button(root, text="Destroy", command=window_destroyer).pack()
Of course, follow your own naming conventions. :)
It seems to me, just 'global window_one' would solve it.

Using the variable from entry/button in another function in Tkinter

When I press the button, I want it to get the Entry and -for future things- use it in another function.
import tkinter
def ButtonAction():
MyEntry = ent.get() #this is the variable I wanna use in another function
den = tkinter.Tk()
den.title("Widget Example")
lbl = tkinter.Label(den, text="Write Something")
ent = tkinter.Entry(den)
btn = tkinter.Button(den, text="Get That Something", command = ButtonAction )
lbl.pack()
ent.pack()
btn.pack()
den.mainloop()
print MyEntry #something like this maybe. That's for just example
I will use this thing as a search tool. Entry window will appear, get that "entry" from there and search it in files like:
if MyEntry in files:
#do smth
I know I can handle the problem with using globals but from what I've read it's not recommended as a first solution.
Structure the program using class.
import tkinter
class Prompt:
def button_action(self):
self.my_entry = self.ent.get() #this is the variable I wanna use in another function
def __init__(self, den):
self.lbl = tkinter.Label(den, text="Write Something")
self.ent = tkinter.Entry(den)
self.btn = tkinter.Button(den, text="Get That Something", command=self.button_action)
self.lbl.pack()
self.ent.pack()
self.btn.pack()
den = tkinter.Tk()
den.title("Widget Example")
prompt = Prompt(den)
den.mainloop()
You can access the input using prompt.my_entry later.

Categories