Tkinter GUI program issue. Entry.get() problem - python

Working on a project in which I use Tkinter in order to create a GUI that gives a list of software in a drop-down and when a particular software is chosen, it takes you to a separate window where a user's name will be entered and they would be added to a database. With the code I have so far, I am able to link a "submit" button on the second window to a function that prints a confirmation message as a test to make sure the button works. My issue now is trying to get the input from the entry field and link the input to the "Submit" button but I can't seem to find a way to do so. I was wondering if I could get some advice on how to go about this. Would classes need to be used in order to make it work? or can I stick with functions and keep the code relatively simple?
I have added the code for my program below.
import tkinter as tk
from tkinter import *
from tkinter import ttk
root = tk.Tk() # Main window
root.title("Software Licences")
root.geometry("300x300")
frame = ttk.Frame(root, padding="50 0 50 50")
frame.pack(fill=tk.BOTH, expand=True)
tkvar = StringVar()
choices = ['Imagenow', # Dropdown menu with software options
'FileMakerPro',
'Acrobat',
'Office',
'Lotus Notes']
tkvar.set('Acrobat') # Shows default dropdown menu option when program is opened
popupMenu = OptionMenu(frame, tkvar, *sorted(choices))
popupLabel = ttk.Label(frame, text="Choose Software")
popupLabel.pack()
popupMenu.pack()
def software_pages(): # In this function is the 2nd window with for each individual software
top = Toplevel()
top.title("Software Licences")
top.geometry("300x300")
myLabel = Label(top, text=tkvar.get()).pack()
employee_entrylbl = Label(top, text="Employee name").pack()
employee_entry = Entry(top, width=25, textvariable=tk.StringVar) # Entry field for adding user's name
employee_entry.pack() # Entry field is displayed
if tkvar.get() == "Acrobat": # for each if statement, button command is link to the functions
# defined below
button = ttk.Button(top, text="Submit", command=add_to_acrobat).pack()
elif tkvar.get() == "Imagenow":
button = ttk.Button(top, text="Submit", command=add_to_imagenow).pack()
elif tkvar.get() == "FileMakerPro":
button = ttk.Button(top, text="Submit", command=add_to_filemakerpro).pack()
elif tkvar.get() == "Office":
button = ttk.Button(top, text="Submit", command=add_to_office).pack()
else:
button = ttk.Button(top, text="Submit", command=add_to_lotusnotes).pack()
exit_button = ttk.Button(top, text="Exit", command=top.destroy).pack() # Exit button for second window
add_emp_button = ttk.Button(frame, text="Next", command=software_pages) # "Next" button in the main window takes the
# user to the second window
add_emp_button.pack()
# Functions below are linked to the button commands of each software in the second window function defined earlier.
# They print out specified messages that confirm the user had been added
def add_to_acrobat():
return print("User added to Acrobat")
def add_to_lotusnotes():
print("User added to IBM")
def add_to_imagenow():
print("User added to imagenow")
def add_to_office():
print("User added to 365")
def add_to_filemakerpro():
print("User added to FMP")
def click_button(): # Function for Exit button for main window
root.destroy()
exit_button = ttk.Button(frame, text="Exit", command=click_button) # Exit button for main window
exit_button.pack()
root.mainloop()

You can pass parameters to the command of tkinter.command using partial from the functools module.
in your case:
button = ttk.Button(top, text="Submit", command=partial(add_to_acrobat, employee_entry)).pack()
in the above line, I send the employee_entry(Which holds your desired text) to the add_to_acrobat function
and the add_acrobat function should look like this:
def add_to_acrobat(e):
print(e.get())
return print("User added to Acrobat")
Hope it helps

Related

Python tkinter functions with multiply Tk()

I'm very new. Haven't gotten to "Classes" yet. Just trying to understand functions before I move forward. Trying to make a basic login widget that when the register button is clicked, it destroys the root window, launches the register window, then once the submit button is clicked, it gets the entry info and for right now, just prints it. I have one file that works but only has one Tk() window. Once you add another like the register function, the code no longer works. I figure it must be the order of operation that I am not understanding the concept of so I wanted some help. I have even tried to put the variables, "username_var, password_var into the register function since they are originally outside of the function but that didn't work either. Also tried calling global variables inside the register function but no luck there either. I worked on this for two days, so please don't think I didn't try all I could on my own. If you know of any documentation that I could read to better understand this, please let me know. I couldn't find anything on this topic.
from tkinter import *
# The first widget/container, not resizable
root = Tk()
root.resizable(False, False)
# variables to store the usernames and passwords
username_var = StringVar()
password_var = StringVar()
password2_var = StringVar()
''' Submit logic, if submit button is clicked or enter is pressed and username does not exist in variable list user_name and both password entries match, save username and password in variable list. '''
def submit():
print('Your username is ' + username_var.get())
if password_var == password2_var:
print('Your password is ' + password_var.get())
else:
print('Passwords do not match')
''' register button logic(if register button is clicked, destroy root window, load register window. Register window will have one username and two password labels and entries, entries have textvariables, rw = register window '''
def register_user():
root.destroy()
register_window = Tk()
rw_user_label = Label(register_window, text='Username')
rw_user_label.grid(row=0, column=0)
rw_pass_label = Label(register_window, text='Password')
rw_pass_label.grid(row=1, column=0)
rw_pass_label = Label(register_window, text='Password')
rw_pass_label.grid(row=2, column=0)
rw_user_entry = Entry(register_window, textvariable=username_var)
rw_user_entry.grid(row=0, column=1)
rw_pass_entry = Entry(register_window, textvariable=password_var, show='*')
rw_pass_entry.grid(row=1, column=1)
rw_pass_entry2 = Entry(register_window, textvariable=password2_var, show='*')
rw_pass_entry2.grid(row=2, column=1)
submit_button = Button(register_window, text='Submit', command=submit)
submit_button.grid(row=3, column=1, sticky='ew')
# username and password labels with grid locations
user_label = Label(root, text='Username')
user_label.grid(row=0, column=0)
pass_label = Label(root, text='Password')
pass_label.grid(row=1, column=0)
# username and password entries with grid locations
user_entry = Entry(root)
user_entry.grid(row=0, column=1)
pass_entry = Entry(root, show='*')
pass_entry.grid(row=1, column=1)
# Login and Register buttons with grid locations, both call functions
login_button = Button(root, text='Login')
login_button.grid(row=2, column=1, sticky='ew')
register_button = Button(root, text='Register', command=register_user)
register_button.grid(row=3, column=1, sticky='ew')
# creates an infinite loop for main root widget until destroy function is called or the widget is exited out of
root.mainloop()
In the register function the entry textvariables are used as initial values to be placed as default in this code. Any changes to the textvariables in the entry don't happen unless they have been declared global inside register.
def register():
global username_var, password_var, password2_var
so you are on the right track in terms of thinking about scope - a global variable has to be specified as global if it is changed inside a function scope. Otherwise it is simply referenced.

Call variables in function by adding to variable number?

I'm Creating a gui in tkinter and have buttons named btn1 btn2 btn3 etc, what i want the button to do on click is disable the button clicked and enable the next button in order. I can write out 6 seperate functions but that seems to defeat the point of a function.
if (btn1['state'] == tk.NORMAL):
btn1.config(state=tk.DISABLED),
btn2.config(state=tk.NORMAL)
else: print ('already clicked')
this is what i have now, but i want it to look more like btn #+1 (state=DISABLED)
You can put the buttons in a list, and then iterate over the list.
Here's a bit of a contrived example:
import tkinter as tk
root = tk.Tk()
def click(button_number):
button = buttons[button_number]
button.configure(state="disabled")
if button == buttons[-1]:
# user clicked the last button
label.configure(text="BOOM!")
else:
next_button = buttons[button_number+1]
next_button.configure(state="normal")
next_button.focus_set()
label = tk.Label(root, text="")
label.pack(side="bottom", fill="x")
buttons = []
for i in range(10):
state = "normal" if i == 0 else "disabled"
button = tk.Button(root, text=i+1, state=state, width=4,
command=lambda button_number=i: click(button_number))
button.pack(side="left")
buttons.append(button)
buttons[0].focus_set()
root.mainloop()

Trying to use a function to destroy tkinter frame that was created in another function. Unsuccessfully

I'm very new to python programming and I've been unable to find out how to get this to function properly. I'm using frames to show a login screen prior to loading the main inventory frame. I intend to record changes to inventory per user, so this is necessary for the program to function properly.
The program calls the Loginscreen() and LoginFrameGenerate() functions to generate the top menu and the frame including labels and entry fields. (Using Tkinter)
The "Log In" button, once pressed, calls the loginfun() function.
The loginfun() function is supposed to use an if statement to check the username and password and if they are correct, remove the login screen frame. Once the login screen frame has been removed, the mainframe and menu functions are called.
Unfortunately, the login screen frame will not go away when using the destroy() command. I can't move forward until I can get this working. Any guidance would be greatly appreciated.
I tried the function without re-initializing the frame inside the loginfun() function, but it generates a name error. I no longer get the name error, but the frame doesn't get destroyed. I've searched google and stack overflow for hours and the only thing I could find regarding Tkinter destroy() was in reference to classes. I'm beginning to think I've been coding this wrong and I should have made each frame a separate class.
from tkinter import *
import tkinter.messagebox
import sys
root = Tk()
root.iconbitmap('Favicon.ico')
testusername = "Admin"
testpassword = "Pass"
CurrentUser = StringVar()
Pass = StringVar()
root.state("zoomed")
def Exitbtnclick():
sys.exit(0)
def logout():
MainFrame=Frame(root)
MainFrame.destroy()
loginScreen
loginFrameGenerate
def loginScreen():
loginMenu = Menu(root)
root.configure(menu=loginMenu)
FileMenu=Menu(loginMenu)
loginMenu.add_cascade(label="File", menu=FileMenu)
FileMenu.add_cascade(label="Exit",command=Exitbtnclick)
def loginFrameGenerate():
#THIS CREATES THE LOGIN FRAME
logframe = Frame(root)
logframe.grid()
UL = Label(logframe, text="Username:", font="Arial 10 bold")
UL.grid(row=0, column=0, sticky="E")
UE = Entry(logframe, textvariable=CurrentUser)
UE.grid(row=0,column=1)
PL = Label(logframe, text="Password:", font="Arial 10 bold")
PL.grid(row=1, column=0, sticky="E")
PE = Entry(logframe, textvariable=Pass)
PE.grid(row=1,column=1)
loginbtn = Button(logframe, text="Log In", command=loginfun)
loginbtn.grid(row=3,columnspan=2)
def loginfun():
#THIS FUNCTION IS CALLED WHEN THE "LOG IN" BUTTON IS PRESSED
global testusername
global testpassword
logframe = Frame(root)
if (CurrentUser.get() == testusername) and (Pass.get() == testpassword):
logframe.destroy() #THIS IS THE PART THAT DOES NOT WORK
initializeMainMenu
initializeMainFrame
else:
tkinter.messagebox.showinfo("Error!", "Invalid Username/Password")
return
def initializeMainMenu():
mainMenu = Menu(root)
root.configure(menu=mainMenu)
FileMenu = Menu(mainMenu)
UserMenu = Menu(mainMenu)
ItemsMenu = Menu(mainMenu)
ReportMenu = Menu(mainMenu)
mainMenu.add_cascade(label="File", menu=FileMenu)
mainMenu.add_cascade(label="Users", menu=UserMenu)
mainMenu.add_cascade(label="Items", menu=ItemsMenu)
mainMenu.add_cascade(label="Reports", menu=ReportMenu)
FileMenu.add_separator()
FileMenu.add_command(label="Log Out/Switch User", command=logout)
FileMenu.add_command(label="Exit", command=Exitbtnclick)
UserMenu.add_command(label="Add/Remove Users",command=random)
def initializeMainFrame():
##Main Inventory Screen To Be Filled in once the user is logged in
MainFrame = Frame(root)
MainFrame.grid()
loginScreen()
loginFrameGenerate()
root.mainloop()

Self Made Tkinter Popup Menu Python

I was writing a GUI library in Python based on tkinter and I was designing and building all the widgets, but I have come to the PopUp menus.
Due that tkinter picks system menus and this can't be customized, I write the following code to make a frame where I can put my customized buttons in and works as a popup.
from tkinter import *
root = Tk()
w = Label(root, text="Right-click to display menu", width=40, height=20)
w.place(x=0)
def function1():
print('function1 activated')
# create a menu
f = Frame(root,width=80,height=60,background='green')
b2 = Button(f,text='function',command=function1)
b2.pack()
def open_popup(event):
try:
f.place(x=event.x, y=event.y)
root.after(1)
f.focus_set()
w.bind_all("<Button-1>",close_popup)
except:
print("Can't open popup menu")
def close_popup(event):
try:
f.place_forget()
root.after(1)
w.unbind_all("<Button-1>")
except:
print("Can't close popup menu")
w.bind("<Button-3>", open_popup)
b = Button(root, text="Quit", command=root.destroy)
b.pack()
root.mainloop()
Everything works well, if I clicked with the mouse right-button the popup menu appears, and if I clicked on every other part the popup menu dissapears.
The problem is that, due to bind_all when I press the button of my popup menu, function1 doesn't run and the event handler closes the popup. I have tried with only bind but this time, function1 runs and the event handler doesn't activates.
Is there anyway I can do that?
Thanks
I would do this using a tracking variable.
We can first assign None to f as a way to check if f is currently set up.
If f is not None then we create frame and button. Then when the function is activated we can run function and destroy the frame the button was in. This also destroys the button and then we set f back to None for out next use.
Take a look at the below reworked example.
Let me know if you have any questions.
from tkinter import *
root = Tk()
w = Label(root, text="Right-click to display menu", width=40, height=20)
w.place(x=0)
f = None # Tracking F to see if it is None or not.
def function1():
global f
print('function1 activated')
# add this to the end of the function to destroy the frame and reset f
if f != None:
f.destroy()
f = None
def open_popup(event):
global f
# if f is None then create frame and button else don't
if f == None:
f = Frame(root,width=80,height=60,background='green')
f.place(x=event.x, y=event.y)
b2 = Button(f,text='function',command=function1)
b2.pack()
else:
print("Can't open popup menu")
w.bind("<Button-3>", open_popup)
b = Button(root, text="Quit", command=root.destroy)
b.pack()
root.mainloop()
I found a way to do this without modifying so much the code, the idea of the tracking variable was good but doesn't solve all the problems, and this code does.
from tkinter import *
root = Tk()
w = Label(root, text="Right-click to display menu", width=40, height=20)
w.pack()
def function1():
print('function1 activated')
try:
f.place_forget()
except:
pass
# create a menu
f = Frame(root,width=80,height=60,background='green')
b2 = Button(f,text='function',command=function1)
b2.place(x=0,y=5)
def open_popup(event):
try:
f.place(x=event.x, y=event.y)
root.after(1)
f.focus_set()
except:
pass
def close_popup(event):
try:
f.place_forget()
root.after(1)
w.unbind_all("<Button-1>")
except:
pass
def enable_depopup(event):
w.bind_all("<Button-1>",close_popup)
def disable_depopup(event):
w.unbind_all("<Button-1>")
w.bind("<Button-3>", open_popup)
w.bind("<Motion>", enable_depopup)
f.bind("<Motion>", disable_depopup)
b = Button(root, text="Quit", command=root.destroy)
b.pack()
root.mainloop()
In this way, everytime I move the mouse over the parent window, the <Button-1> of the mouse is binded to close the popup menu.
And doing a trick, that is place the button of the menu a few pixels down, this let the mouse pass through the popup frame to reach the button and disable the <Button-1> binding letting me click the button.
The function of the button activate the place_forget method of the frame, so everything works correctly.

I have a Toplevel button in tkinker that I want to close the window and then perform a function

So far I have created a frame with some functioning buttons/menus. One of my menu buttons opens a new Toplevel window. This new Toplevel window is basically a forum fill out page. At the end of the page is a done button. This done button closes the tkiniter Toplevel window while leaving the root window. I wish to execute lines of code after the button is pressed.
My first idea was to set the done button command to make the window 'withdrawn'. If I do this, it does withdraw the window but if I try to run an if check the check will already have been checked before the button is pressed. The most simple solution to this would be to create a function the withdraws the window and does the other stuff I am wanting, however, when I try to pass a function as the command for the Toplevel done button it does not call the function.
Any advice how to make the button close the window and then perform additional code (Only after the button is pressed) would be greatly appreciated. I have attached the section of code in question below. Thank You in advance for your help. (Side note Computer class is handled in another file). (I am using Python 3.x)
def draw_new_computer_entry(self):
t = Toplevel(self)
t.resizable(0,0)
t.wm_title("Solution Center: Add New Computer")
t.geometry("300x300")
nameLabel = Label(t, text="Computer Name:")
nameLabel.place(x=0,y=10)
a = computer()
comp_nameEntry = Entry(t, width=30)
comp_nameEntry.place(master=None, x=100, y=10)
a.name = comp_nameEntry.get()
comp_makerEntry= Entry(t,width=30)
comp_makerEntry.place(x=100, y=50)
a.maker = comp_makerEntry.get()
makerLabel= Label(t, text="Maker:")
makerLabel.place(x=55,y=50)
graphics_cardEntry= Entry(t, width=30)
graphics_cardEntry.place(x=100,y=90)
a.gpu = graphics_cardEntry.get()
graphics_cardLabel= Label(t, text="Graphics Card:")
graphics_cardLabel.place(x=15, y=90)
processorEntry= Entry(t, width=30)
processorEntry.place(x=100, y=130)
a.processor = processorEntry.get()
processorLabel= Label(t, text="Processor:")
processorLabel.place(x=38, y=130)
hard_driveEntry= Entry(t, width=30)
hard_driveEntry.place(x=100, y=170)
a.hard_drive = hard_driveEntry.get()
hard_driveLabel= Label(t, text="Hard Drive:")
hard_driveLabel.place(x=30, y=170)
ramEntry= Entry(t, width=30)
ramEntry.place(x=100, y=210)
ramLabel= Label(t,text="Ram:")
ramLabel.place(x=65,y=210)
doneButton = Button(t, text="done", command=t.withdraw)
doneButton.place(x=265, y=275)
All you have to do is create a function that closes the window and then performs additional code.
Here is a snippet of your code:
def donePressed():
t.withdraw() # Or t.destroy(), depending if you need to open this window again
# Enter Code Here
print('code after window close')
doneButton = Button(t, text="done", command=donePressed)
doneButton.place(x=265, y=275)

Categories