Python tkinter disable "submit" button until all fields are populated - python-3.x

I am still relatively new at Python, but I am making a GUI app that has 2 entry fields and two filedialog buttons for the user to select the file to import and the directory to save the output of the program. I am trying to do some validation on the entry fields to make sure that the user cannot click on the submit button until the entry fields are filled in and they have selected a file to import and a directory to save the output.
I got some of the way, but I'm stuck and I'm afraid I don't know enough about classes and methods to determine why I cannot change the status of my submit_button.config?
I have read various examples of how to do validation to entry fields including using validatecommand and building a validate method within my class. I abandoned that because I could not figure out how to validate multiple fields within the submit_button command.
Here is my code as it sits right now. I am struggling with the validate method within the Application class.
import pandas as pd
import numpy as np
from tkinter import *
from tkinter import ttk
from tkinter import filedialog as fd
from tkinter import messagebox
import os
class FileLogic:
def __init__(self, path, save_location, request_id, exeuction_id):
self.path = path
self.save_location = save_location
self.request_id = request_id
self.execution_id = execution_id
def fileopen(self=None):
global fileName
global path
path = fd.askopenfilename(title = "Select File", filetypes=( ("Excel files", "*.xlsx"),("All files", "*.*") ) )
fileName = os.path.split(path)[1]
if not fileName:
messagebox.showerror("ERROR - File Not Selected", "A file was not selected to process. Please select a file by double-clicking or select file and press Open button")
else:
file_select_label = Label(root, text=("File Selected: " + fileName), width=75, bg="light blue")
file_select_label.grid(row=7, columnspan=2)
return path
def filesave(self=None):
global save_location
save_location = fd.askdirectory(title = "Select Directory")
if not save_location:
messagebox.showerror("ERROR - Directory Not Selected", "This upload process will build an output file. Please select a folder where the output file can be saved")
else:
file_select_label = Label(root, text=("Output file will be saved: " + save_location), width=75, bg="light blue")
file_select_label.grid(row=8, columnspan=2)
return save_location
def submit(self, path, save_location, request_id, execution_id):
print("FileLogic path: " + self.path)
print("FileLogic save: " + self.save_location)
print("FileLogic request: " + self.request_id)
print("FileLogic execution: " + self.execution_id)
# FileParsing.__init__(request_id)
class FileParsing:
def __init__(self, request_id):
self.request_id = request_id
# self.execution_id_entry = execution_id_entry
print("request id2: " + request_id)
class Application(Frame):
def __init__(self, master):
ttk.Frame.__init__(self, master)
self.grid()
self.create_widgets()
def create_widgets(self):
global submit_button
##### Define the Labels ###############
self.request_id_label = Label(root, text="Enter Rebate Request Id:", bg="light blue", bd=2, width=25).grid(row=0, column=0)
self.execution_id_label = Label(root, text="Enter Rebate Execution Id:", bg="light blue", bd=2, width=25).grid(row=1, column=0)
self.blank_label = Label(root, bg="light blue")
####### Define the Entry fields ##################
self.request_id_entry = Entry(root,bg="light gray", bd=2, width=25, textvariable=request_id_entry).grid(row=0, column=1)
self.execution_id_entry = Entry(root, bg="light gray", bd=2, width=25, textvariable=execution_id_entry).grid(row=1, column=1)
###### Define the Buttons ###############
self.submit_button = Button(root, text="Submit", bg="gray", width=17, command= lambda: self.submit_click(path, save_location, request_id, execution_id))
self.submit_button.config(state='disabled')
self.open_file_button = Button(root, text="Select file to process", width = 30, command=FileLogic.fileopen).grid(row=3, column=0)
self.save_location_button = Button(root, text="Select location to save output", width=30, command=FileLogic.filesave).grid(row=4, column=0)
##### Build the Grid ##################
self.blank_label.grid(row=2, column=0)
self.blank_label.grid(row=5, columnspan=2)
self.submit_button.grid(row=6, column=1)
def validate(self, *args):
print("validate")
button_status = self.create_widgets(submit_button)
if request_id_entry.get():
print("normal")
print(button_status)
# self.submit_button.config(state='normal')
else:
print("diabled")
print(submit_button.config)
# self.submit_button.config(state='disabled')
def num_check(self,var):
var = self.var.get()
print(var)
if var.isnumeric():
return True
else:
tkinter.messagebox.showinfo("Error", "Enter Numeric Value")
def submit_click(self, path, save_location, request_id, execution_id):
self.request_id = request_id_entry.get()
self.execution_id = execution_id_entry.get()
a = FileLogic(path, save_location, request_id, execution_id)
FileLogic.submit(a, path, save_location, request_id, execution_id)
root=Tk()
root.title("Rebate Bid Data Upload")
root.geometry("500x200")
root.configure(background="light blue")
request_id_entry = StringVar()
execution_id_entry = StringVar()
request_id_entry.trace("w", Application.validate)
app = Application(root)
root.mainloop()
I am trying to get where the submit button is disabled until all the entry elements and filedialog attributes are complete. Then for the entry fields I am checking to make sure they are numeric and I will want to make sure they are integers.

You are not using textvariable correctly. Also note that you are not keeping a reference of your entry widgets by defining them and calling the grid method on the same line.
def create_widgets(self):
#global submit_button #you don't have to declare global here: submit_button is already an attribute
...
self.request_var = StringVar() #create StringVars for request
self.execution_var = StringVar() #ditto for execution
self.request_id_entry = Entry(root,bg="light gray", bd=2, width=25,textvariable=self.request_var).grid(row=0, column=1) #set the textvariable to the StringVar
self.execution_id_entry = Entry(root, bg="light gray", bd=2, width=25,textvariable=self.execution_var).grid(row=1, column=1)
self.request_var.trace("w",self.validate) #trace changes on StringVar
self.execution_var.trace("w",self.validate)
...
def validate(self, *args):
if self.request_var.get() and self.execution_var.get(): #if both StringVars has content
print("normal")
self.submit_button.config(state='normal')
else:
print("disabled")
self.submit_button.config(state='disabled')

Related

Use an entry input as a file name Python tkinter

I need to create an excel file then name it using a tkinter textbox, in other words I need to store the tkinter entry getvalue into a variable then assign it as a name to the file that I'll create.
Code:
import tkinter as tk
def show_entry_fields():
print("Nom du rapport global: %s" % (e1.get()))
master = tk.Tk()
tk.Label(master,
text="Nom du rapport global").grid(row=0)
e1 = tk.Entry(master)
e1.grid(row=0, column=1)
tk.Button(master,
text='Quit',
command=master.quit).grid(row=3,
column=1,
sticky=tk.W,
pady=4)
tk.Button(master,
text='Show', command=show_entry_fields).grid(row=3,
column=0,
sticky=tk.W,
pady=4)
import xlsxwriter
workbook = xlsxwriter.Workbook(e1.get()+'.xlsx')
worksheet = workbook.add_worksheet("Rapport global")
worksheet.set_column(1, 1, 25)
worksheet.set_column(1, 2, 25)
worksheet.write('F3', "Hello")
worksheet.write('G3', "world")
workbook.close()
tk.mainloop()
master.withdraw()
It creates an excel file, but with no name, I don't know how to retrieve the input entry and assign it as a file name
I don't have xlsxwriter but I assume that your
workbook = xlsxwriter.Workbook(e1.get()+'.xlsx')
is executed before you set a value in the entry box.
One possible solution would be:
Get the entry value and store it in a variable. To do that I create another button
called but_save. This button calls the method save_entry which get the value of
entry input and stores in a variable.
Run the script, type the desired name and press Save button.
Didn't store variable in a Microsoft Excel file format because I don't have this module
but for simplicity I store it in a text file. You should be able to store it as a xsl as well.
from tkinter import Tk, Label, Entry, Button
class Set_Name():
def __init__(self, master):
self.master = master
self.init_widgets()
def show_entry_fields(self):
print("Nom du rapport global: %s" % (self.e1.get()))
def init_widgets(self):
self.lab_1 = Label(self.master, text="Nom du rapport global")
self.lab_1.grid(row=0)
self.e1 = Entry(self.master)
self.e1.grid(row=0, column=1)
self.but_quit = Button(self.master, text='Quit', command=self.master.quit)
self.but_quit.grid(row=3, column=1, sticky='W', pady=4)
self.but_show = Button(self.master, text='Show', command=self.show_entry_fields)
self.but_show.grid(row=3, column=0, sticky='W', pady=4)
self.but_save = Button(self.master, text="Save", command=self.save_entry)
self.but_save.grid(row=3, column=2)
def save_entry(self):
# I don't have xlsxwriter.
file_name = self.e1.get() # get the string from Entry
with open(file_name, 'w', encoding='utf-8') as f:
f.write("Hello World!") # write whatever you want
if __name__ == "__main__":
root = Tk()
app = Set_Name(root)
root.mainloop()

How can I print the values of a Entry() in tkinter?

Im just simply trying to print the values of the entry fields and it tells me its not defined. I been looking online for a long while now. The lastest thing that I tried was adding self as a parameter of add_student but that didn't work.
This is the code
from tkinter import *
class window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.widgets()
def add_student(self):
print(f"Student's name (first, last): {self.fname_textbox}, {self.lname_textbox}")
def widgets(self):
self.master.title("Student Test Score & Grade")
self.master.minsize(200,200)
""" Labels """
# First name
self.fname_label = Label(root, text='First Name: ')
self.fname_label.grid(row=0, column=0, padx=5, pady=5)
# Last Name
self.lname_label = Label(root, text='Last name: ')
self.lname_label.grid(row=1, column=0, padx=5, pady=5)
""" Entry boxes """
# First Name
self.fname_textbox = Entry(root, width=30)
self.fname_textbox.grid(row=0, column=1, padx=5)
# Last name
self.lname_textbox = Entry(root, width=30)
self.lname_textbox.grid(row=1, column=1, padx=5)
""" Buttons """
# Add Button
self.add_btn = Button(root, text="Add Student", command=self.add_student).grid(row=4, column=2, padx=2, pady=2)
if __name__=="__main__":
root = Tk()
root.resizable(width=False, height=False)
app = window(root)
root.mainloop()
It prints this
Student's name (first, last): .!entry, .!entry2
Instead of: Student's name (first, last): John, Doe
What does this mean?
You need to get the value of the entries in order to use them in your print statement
You do this by putting:
firstname = self.fname_textbox.get()
lastname = self.1fname_textbox.get()
before you print and using these values in your print statement.
Ah, Try something like this:
def __init__(self, master):
self.nameEntry = Entry(master)
self.contents = StringVar()
self.nameEntry["textvariable"]=self.contents
self.nameEntry.pack()
self.nameEntry.grid(row=0,column=1)
self.buttonSave = Button(master,text="Save",command=self.save).grid(row=9,columnspan=2, sticky=W+E+N+S)
def save(self):
print self.nameEntry.get()

How to show images from path in new window in python tk

After browsing path of image i wanna show image on next window in python using Tk library but image is not showing in next window. please take a look on my code below and give answer Thanks.
import tkinter as tk
from tkinter import filedialog as fd
a=""
str1 = "e"
class Browse(tk.Frame):
""" Creates a frame that contains a button when clicked lets the user to select
a file and put its filepath into an entry.
"""
def __init__(self, master, initialdir='', filetypes=()):
super().__init__(master)
self.filepath = tk.StringVar()
self._initaldir = initialdir
self._filetypes = filetypes
self._create_widgets()
self._display_widgets()
def _create_widgets(self):
self._entry = tk.Entry(self, textvariable=self.filepath, font=("bold", 10))
a=self._entry
self._button = tk.Button(self, text="Browse...",bg="red",fg="white", command=self.browse)
self._classify=tk.Button(self,text="Classify",bg="red",fg="white", command=self.classify)
self._label=tk.Label(self, text="IMAGE CLASSIFICATION USING DEEP LERAINING.", bg="blue", fg="white",height=3, font=("bold", 14))
def _display_widgets(self):
self._label.pack(fill='y')
self._entry.pack(fill='x', expand=True)
self._button.pack(fill='y')
self._classify.pack(fill='y')
def retrieve_input(self):
#str1 = self._entry.get()
#a=a.replace('/','//')
print (str1)
def classify(self):
newwin = tk.Toplevel(root)
newwin.geometry("500x500")
label = tk.Label(newwin, text="Classification", bg="blue", fg="white",height=3, font=("bold", 14))
label.pack()
canvas = tk.Canvas(newwin, height=300, width=300)
canvas.pack()
my_image = tk.PhotoImage(file=a, master=root)
canvas.create_image(150, 150, image=my_image)
newwin.mainloop()
def browse(self):
""" Browses a .png file or all files and then puts it on the entry.
"""
self.filepath.set(fd.askopenfilename(initialdir=self._initaldir,
filetypes=self._filetypes))
if __name__ == '__main__':
root = tk.Tk()
labelfont = ('times', 10, 'bold')
root.geometry("500x500")
filetypes = (
('Portable Network Graphics', '*.png'),
("All files", "*.*")
)
file_browser = Browse(root, initialdir=r"C:\Users",
filetypes=filetypes)
file_browser.pack(fill='y')
root.mainloop()
Your global variable a which stores the path of the image is not getting updated. You need to explicitly do it. Below is the code that works. Have a look at the browse() function.
import tkinter as tk
from tkinter import filedialog as fd
a=""
str1 = "e"
class Browse(tk.Frame):
""" Creates a frame that contains a button when clicked lets the user to select
a file and put its filepath into an entry.
"""
def __init__(self, master, initialdir='', filetypes=()):
super().__init__(master)
self.filepath = tk.StringVar()
self._initaldir = initialdir
self._filetypes = filetypes
self._create_widgets()
self._display_widgets()
def _create_widgets(self):
self._entry = tk.Entry(self, textvariable=self.filepath, font=("bold", 10))
a = self._entry
self._button = tk.Button(self, text="Browse...",bg="red",fg="white", command=self.browse)
self._classify=tk.Button(self,text="Classify",bg="red",fg="white", command=self.classify)
self._label=tk.Label(self, text="IMAGE CLASSIFICATION USING DEEP LERAINING.", bg="blue", fg="white",height=3, font=("bold", 14))
def _display_widgets(self):
self._label.pack(fill='y')
self._entry.pack(fill='x', expand=True)
self._button.pack(fill='y')
self._classify.pack(fill='y')
def retrieve_input(self):
#str1 = self._entry.get()
#a=a.replace('/','//')
print (str1)
def classify(self):
global a
newwin = tk.Toplevel(root)
newwin.geometry("500x500")
label = tk.Label(newwin, text="Classification", bg="blue", fg="white",height=3, font=("bold", 14))
label.pack()
canvas = tk.Canvas(newwin, height=300, width=300)
canvas.pack()
my_image = tk.PhotoImage(file=a, master=root)
canvas.create_image(150, 150, image=my_image)
newwin.mainloop()
def browse(self):
""" Browses a .png file or all files and then puts it on the entry.
"""
global a
a = fd.askopenfilename(initialdir=self._initaldir, filetypes=self._filetypes)
self.filepath.set(a)
if __name__ == '__main__':
root = tk.Tk()
labelfont = ('times', 10, 'bold')
root.geometry("500x500")
filetypes = (
('Portable Network Graphics', '*.png'),
("All files", "*.*")
)
file_browser = Browse(root, initialdir=r"~/Desktop", filetypes=filetypes)
file_browser.pack(fill='y')
root.mainloop()
P.S. Do change your initialdir. I changed it as I am not on Windows.

How to add background image to my application in Tkinter?

The code picture needs to fit the screen size perfectly. I saw a bunch of tutorials but nothing seems to work.I tried adding a canvas but it covers half the screen.All my buttons go under the image itself not over it. It's getting on my nerves .
here's my code :
import tkinter as tk
import PIL
from PIL import Image, ImageTk
from tkinter import *
from tkinter import filedialog
from tkinter import messagebox
root = Tk()
w = Label(root, text="Send and receive files easily")
w.config(font=('times', 32))
w.pack()
def create_window():
window = tk.Toplevel(root)
window.geometry("400x400")
tower= PhotoImage(file="D:/icons/tower.png")
towlab=Button(root,image=tower, command=create_window)
towlab.pack()
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.master.title("Bifrost v1.0")
self.pack(fill=BOTH, expand=1)
self.img1 = PhotoImage(file="D:/icons/download.png")
self.img2 = PhotoImage(file="D:/icons/upload.png")
sendButton = Button(self, image=self.img2)
sendButton.place(x=305, y=15)
receiveButton = Button(self, image=self.img1)
receiveButton.place(x=355, y=15)
menu = Menu(self.master)
self.master.config(menu=menu)
file = Menu(menu)
file.add_command(label='Exit', command=self.client_exit)
menu.add_cascade(label='File', menu=file)
edit = Menu(menu)
edit.add_command(label='abcd')
menu.add_cascade(label='Edit', menu=edit)
help = Menu(menu)
help.add_command(label='About Us', command=self.about)
menu.add_cascade(label='Help', menu=help)
def callback():
path = filedialog.askopenfilename()
e.delete(0, END) # Remove current text in entry
e.insert(0, path) # Insert the 'path'
# print path
w = Label(root, text="File Path:")
e = Entry(root, text="")
b = Button(root, text="Browse", fg="#a1dbcd", bg="black", command=callback)
w.pack(side=TOP)
e.pack(side=TOP)
b.pack(side=TOP)
def client_exit(self):
exit()
def about(self):
top = Toplevel()
msg = Message(top, text="This is a project developed by Aditi,Sagar and
Suyash as the final year project.",
font=('', '15'))
msg.pack()
top.geometry('200x200')
button = Button(top, text="Okay", command=top.destroy)
button.pack()
top.mainloop()
root.resizable(0,0)
#size of the window
root.geometry("700x400")
app = Window(root)
root.mainloop()
Overlaying elements is tricky. I think this might be approximately what you're looking for. At least it's a start...
import PIL
from PIL import Image, ImageTk
from tkinter import *
from tkinter import filedialog
from tkinter import messagebox
root = Tk()
class Window:
def __init__(self, master=None):
tower = PIL.Image.open("Images/island.png")
master.update()
win_width = int(master.winfo_width())
win_height = int(master.winfo_height())
# Resize the image to the constraints of the root window.
tower = tower.resize((win_width, win_height))
tower_tk = ImageTk.PhotoImage(tower)
# Create a label to hold the background image.
canvas = Canvas(master, width=win_width, height=win_height)
canvas.place(x=0, y=0, anchor='nw')
canvas.create_image(0, 0, image=tower_tk, anchor='nw')
canvas.image = tower_tk
frame = Frame(master)
frame.place(x=win_width, y=win_height, anchor='se')
master.update()
w = Label(master, text="Send and receive files easily", anchor='w')
w.config(font=('times', 32))
w.place(x=0, y=0, anchor='nw')
master.title("Bifrost v1.0")
self.img1 = PhotoImage(file="Images/logo.png")
self.img2 = PhotoImage(file="Images/magnifier.png")
frame.grid_columnconfigure(0, weight=1)
sendButton = Button(frame, image=self.img2)
sendButton.grid(row=0, column=1)
sendButton.image = self.img2
receiveButton = Button(frame, image=self.img1)
receiveButton.grid(row=0, column=2)
receiveButton.image = self.img1
menu = Menu(master)
master.config(menu=menu)
file = Menu(menu)
file.add_command(label='Exit', command=self.client_exit)
menu.add_cascade(label='File', menu=file)
edit = Menu(menu)
edit.add_command(label='abcd')
menu.add_cascade(label='Edit', menu=edit)
help = Menu(menu)
help.add_command(label='About Us', command=self.about)
menu.add_cascade(label='Help', menu=help)
def callback():
path = filedialog.askopenfilename()
e.delete(0, END) # Remove current text in entry
e.insert(0, path) # Insert the 'path'
# print path
w = Label(root, text="File Path:")
e = Entry(root, text="")
b = Button(root, text="Browse", fg="#a1dbcd", bg="black", command=callback)
w.pack(side=TOP)
e.pack(side=TOP)
b.pack(side=TOP)
def client_exit(self):
exit()
def about(self):
message = "This is a project developed by Aditi,Sagar and"
message += "Suyash as the final year project."
messagebox.showinfo("Delete Theme", message)
root.resizable(0,0)
#size of the window
root.geometry("700x400")
app = Window(root)
root.mainloop()

Return Value from TkInter Entry with Button

Python novice, here. I've noticed there are a lot of questions around the topic of returning values from a TkInter function, but none of the solutions seem to solve my issue.
I can successfully print self.e1path to the shell from within getPath.submit, but I cannot return it to the rest of my code. I'm using a print statement outside of the class to test whether I've successfully returned the CSV path.
from tkinter import *
import tkinter as tk
class getPath(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.label1 = tk.Label(self, text="CSV Path").grid(row=0, column=0)
self.e1 = tk.Entry(self, width=50)
self.e1Grid = self.e1.grid(row=0, column=1)
self.browse = tk.Button(self, text='Browse', command=self.getCSV).grid(row=0, column=2)
self.submit = tk.Button(self, text='Submit', command=self.submit).grid(row=1, column=1)
def getCSV(self):
self.fileName = filedialog.askopenfilename( filetypes = (('Comma Separated Values', '*.csv'), ('All Files', '*.*')), title = "Choose a CSV File")
self.e1.insert(10, self.fileName)
def submit(self):
self.e1Path = self.e1.get()
return self.e1Path
app = getPath()
app.mainloop()
print(app)
I figured it out! I needed to add a self.destroy() to the submit function. This stopped the mainloop and let me call on self.e1path outside of the function using app.e1path. New code:
from tkinter import *
import tkinter as tk
class getPath(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.label1 = tk.Label(self, text="CSV Path").grid(row=0, column=0)
self.e1 = tk.Entry(self, width=50)
self.e1Grid = self.e1.grid(row=0, column=1)
self.browse = tk.Button(self, text='Browse', command=self.getCSV).grid(row=0, column=2)
self.submit = tk.Button(self, text='Submit', command=self.submit).grid(row=1, column=1)
def getCSV(self):
self.fileName = filedialog.askopenfilename( filetypes = (('Comma Separated Values', '*.csv'), ('All Files', '*.*')), title = "Choose a CSV File")
self.e1.insert(10, self.fileName)
def submit(self):
self.e1Path = self.e1.get()
self.destroy()
app = getPath()
app.mainloop()
print(app.e1Path)

Resources