How to Varibalize a Tkinter User Input - python

I am trying to create a little GUI to convert Parquet to XLSX files. In my code, I am currently using tkinter to create a GUI and then using a function to convert from Parquet to XLSX.
When I run the below code though, I am still getting an error that "myfunc() missing 3 required positional arguments: 'txt_file', 'txt_name', and 'txt_dir'" any idea why they are not getting assigned?
import os
import pandas as pd
from tkinter import *
import pyarrow
import shutil
from pathlib import Path
window = Tk()
window.title("Convertor")
#Sets the size of the window
window.geometry('550x200')
#Adds a header to the window and configures the size
lbl = Label(window, text="Convert Parquet to CSV", font=("Arial Bold", 18))
#Configures where the label message will appear
lbl.grid(column=0, row=0)
#asks for parquet file
lbl2 = Label(window, text="Where is the parquet file currently located?", font=("Arial", 12))
lbl2.grid(column=0, row=1)
#adds a field for an input text message
txt_file = Entry(window,width = 30)
txt_file.grid(column=1, row=1)
#asks for name of xlsx file
lbl3 = Label(window, text="What would you like to call the new xlsx file?", font=("Arial", 12))
lbl3.grid(column=0, row=2)
txt_name = Entry(window,width = 30)
txt_name.grid(column=1, row=2)
#asks where you want to put the new xlsx file
lbl3 = Label(window, text="Where would you like to ouput the xlsx file?", font=("Arial", 12))
lbl3.grid(column=0, row=3)
txt_dir = Entry(window,width = 30)
txt_dir.grid(column=1, row=3)
def myfunc(txt_file, txt_name, txt_dir):
file = txt_file
df1 = pd.read_parquet(file)
df = df1.append(df1, ignore_index=True)
dirout = txt_dir
name = txt_name
cfile = os.path.join(dirout, name + "." + "xlsx")
df.to_excel(cfile)
#Adding a button
btn = Button(window, text="Convert", command=myfunc)
btn.grid(column=1, row = 4)
#The mainloop causes the window to remain open until someone interacts with it
window.mainloop()

Instead of passing values into your function, have your function retrieve the values from the UI. In your case you're saving the widgets in global variables which makes that easy to do.
For example:
def my_func():
file = txt_file.get()
name = txt_name.get()
dir_out = txt_dir.get()
df1 = pd.read_parquet(file)
df = df1.append(df1, ignore_index=True)
cfile = os.path.join(dirout, name + "." + "xlsx")
df.to_excel(cfile)
...
btn = Button(window, text="Convert", command=my_func)
If you want to make your code easier to test by having the code that does the work be in a function that accepts parameters, simply move that code to a separate function.
def my_func():
file = txt_file.get()
name = txt_name.get()
dir_out = txt_dir.get()
do_conversion(file, name, dir_out)
def do_conversion(file, name, dir_out):
df1 = pd.read_parquet(file)
df = df1.append(df1, ignore_index=True)
cfile = os.path.join(dirout, name + "." + "xlsx")
df.to_excel(cfile)
With that, you can use do_conversion with or without a GUI, making it easier to write a unit test for the code that performs the actual conversion.

Related

Run a function on button command using tkinter

first of all, I'm a beginner. I have a basic script (get grades()) that takes a .csv file and specific class sections (min 1, max 3). I wrote this function to clean courses grades, and the output is a .txt containing only the student number, class section and grade. This text file is then ready to be upload to a system at my uni.
I'm trying to create a GUI for this script, but I'm stuck. Googling around, I managed to get a basic GUI, but even though I can enter the class sections and browse for a file, I cannot make it run my function. When I click on the button to the get the grades, the GUI crashes. Could you please point me in the right direction? Thank you in advance.
tkinter code
import tkinter as tk
from tkinter import ttk
from tkinter.messagebox import showinfo
import tkinter
from tkinter import *
from tkinter import filedialog as fd
from get_grades import get_grades
from functools import partial
# root window
root = tk.Tk()
root.geometry("500x450")
root.title('Grades')
# store sections
sections = tk.StringVar()
file_name = tk.StringVar()
def save_sections():
""" callback when the sections button clicked
"""
msg = f'You entered sections: {sections.get()}'
showinfo(
title='Information',
message=msg
)
# Sign in frame
signin = ttk.Frame(root)
signin.pack(padx=10, pady=10, fill='x', expand=True)
# sections
sections_label = ttk.Label(signin, text="sections:")
sections_label.pack(fill='x', expand=True)
sections_entry = ttk.Entry(signin, textvariable=sections)
sections_entry.pack(fill='x', expand=True)
sections_entry.focus()
# login button
section_button = ttk.Button(signin, text="save sections", command=save_sections)
section_button.pack(fill='x', expand=True, pady=10)
def get_file_name(file_entry):
file_name = fd.askopenfilename(title="Select file", filetypes=(("CSV Files", "*.csv"),))
file_entry.delete(0, END)
file_entry.insert(0, file_name)
entry_csv = Entry(root, text="", width=50)
entry_csv.pack(fill='x', expand=True)
file_label = ttk.Label(root, text="Input CSV")
file_button = ttk.Button(root, text="Browse...", width=10, command=lambda: get_file_name(entry_csv))
file_button.pack(fill='x', expand=True, pady=10)
grades_button = ttk.Button(root, text="Get grades", width=10, command=lambda: get_grades(entry_csv, sections))
grades_button.pack(fill='x', expand=True, pady=10)
# infinite loop
root.mainloop()
get_grades.py
import pandas as pd
from datetime import datetime
def get_grades(file, section1=True, section2=False, section3=False):
sections = []
if section1:
sections.append(section1)
if section2:
sections.append(section2)
if section3:
sections.append(section3)
else:
return "missing sections"
# get file
df = pd.read_csv(file)
# delete the first two rows
df = df.drop([df.index[0], df.index[1]])
# important columns are "SIS User ID", "Section", and the name of the test, which changes by course
# first, rename the assignment column
df = df.rename(columns={df.columns[5]: "Grade"})
df = df[df.Student != "Student, Test"]
# select columns
df = df[["SIS User ID", "Section", "Grade"]]
df = df[df['Section'].isin(sections)]
# cleaning
df = df.replace("0.0", "NVD")
df = df.fillna("NA")
# deleting decimal
df['SIS User ID'] = df['SIS User ID'].astype(str).apply(lambda x: x.replace('.0', ''))
# save to txt and csv
# file name
date_time = datetime.now().strftime("%Y_%m_%d-%I_%M_%S_%p")
filename = str(date_time) + "_" + str(sections)
df.to_csv(str(filename + ' .txt'), sep='\t', index=False)
print("done! file " + str(filename) + ".txt saved")
You are passing an Entry widget and a StringVar to your function. But your function expects string objects.
You have to get the values of your entry box and StringVar. Luckily, the method is called the same for both cases. It's the .get() method.
grades_button = ttk.Button(root, text="Get grades", width=10, command=lambda: get_grades(entry_csv.get(), sections.get()))
This should pass the correct values to get_grades(). But to be sure, you should print the values to console, just to check. This would also have hinted at the problem you had with your code.

Having a problem with adding new information to a CSV file on Tkinter

I have a project on python I am working on.
I need to make a program which runs CSV, matplotlib and other modules.
I have encountered a problem I can't solve, saving new info through the tkinter to the original CSV file
Mainly the problem is the "save to db" function
My entire code is :
from tkinter import *
from tkinter.ttk import *
import pandas as pd
from tkinter import messagebox
root = Tk()
root.title('DYR')
root.minsize(700, 500) # the minimum size of the window
root.geometry('500x500') # in what resolution the window will open at
root.configure(bg='LightBlue1')
nameLabel = Label(root, text=' Company Name',font=("Arial Bold", 12))
nameLabel.grid(column=2, row=0)
nameInput = Entry(width=30)
nameInput.grid(column=3, row=0)
idLabel= Label(root, text = 'Client ID',font=("Arial Bold", 12))
idLabel.grid(column=2, row=1)
id_input = Entry(width=9)
id_input.grid(column= 3, row=1)
addresslabel= Label(root, text = "Company Address", font=("Arial Bold", 12))
addresslabel.grid(column= 2, row= 2)
addressinput = Entry (width= 50 )
addressinput.grid(column =3 , row = 2)
fieldlabel= Label(root, text= "Filed",font=("Arial Bold", 12))
fieldlabel.grid(column=2 , row =3)
fieldcomobx = Combobox (root)
fieldcomobx['values']= ("Choose field",'consulting','Medical','Gaming','Cyber')
fieldcomobx.current(0) #set the selected item
fieldans = fieldcomobx.get()
fieldcomobx.grid(column=3, row=3)
numberof = Label (root, text = "Number of employees", font=("Arial Bold", 12))
numberof.grid(column = 2 , row = 4)
numberin = Entry (width= 15)
numberin.grid(column = 3 , row= 4)
contactlabel=Label(root, text = "Contact", font=("Arial Bold", 12))
contactlabel.grid(column=2, row =5)
contactin = Entry (width = 15)
contactin.grid(column=3, row =5)
lastcall = Label (root, text = "Last call ",font=("Arial Bold", 12))
lastcall.grid(column = 2 , row = 6)
lastcallin = Entry (width = 15)
lastcallin.grid(column = 3 , row=6)
def cheker():#func to check if the client exsit
import pandas as pd
path = r"C:\Users\HP\PycharmProjects\untitled\Gmar\Gmar_Project.csv"
companyName = str(nameInput.get())
df = pd.read_csv(path)
result = df[df.Company == companyName]
if len(result) == 0:
messagebox.showinfo("Cheker", "Not exist, Good luck!")
else:
messagebox.showinfo("Cheker", "The client already exists in the data base!")
btn = Button(root,text="check existence",command= cheker)
btn.grid(column=4, row = 0)
def save_to_db(): #save the information to csv
path = r"C:\Users\HP\PycharmProjects\untitled\Gmar\Gmar_Project.csv"
newRow = [str(nameInput.get()), str(id_input.get()), str(addressinput.get()),str(fieldans), str(numberin .get()),str(contactin.get()),str(lastcallin.get())]
df = pd.read_csv(path)
df2 = pd.DataFrame(newRow).T
df2.columns = ['Company','client ID','address','field','Number of employees','contact','last call'] # df.columns
df = df.append(df2, ignore_index=True)
df.to_csv(path_or_buf=path, index_label=False, index=False)
endbtn = Button (root, text = "SAVE" ,command = save_to_db())
endbtn.grid(column =3, row=8)
root.mainloop()
The problem is that you are setting fieldans about a millisecond after you create the combobox. The user won't have had a chance to make a section.
A general rule of thumb in GUI development is that you should not fetch data until immediately before you need it.
You need to move fieldans = fieldcomobx.get() inside of save_to_db so that you get the value entered by the user rather than the default value.
You also have the problem that you're calling save_to_db immediately as the GUI starts rather than after the user has had a chance to enter any data.
You need to define endbtn like this:
endbtn = Button (root, text = "SAVE" ,command = save_to_db)

Invalid file path for button box

I am creating a window with two buttons - one to import excel files and another to close the window after excel sheets are selected. I can choose the excel files, but when I click Okay, I get an error that I have an invalid file path.
using python 2.7
import Tkinter, tkFileDialog
import pandas as pd
root= Tkinter.Tk()
canvas = Tkinter.Canvas(root, width = 300, height = 300, bg = 'PowderBlue')
canvas.pack()
def getExcel ():
global df
import_file_path = tkFileDialog.askopenfilenames(title = 'Select file(s)',filetypes = (('Excel','*.xlsx'),('Comma Delimited','*.csv'),('xls', '*.xls')))
df = pd.read_excel (import_file_path)
print (df)
okay = Tkinter.Button(text='Okay', command=root.destroy, bg='blue', fg='white', font=('Arial', 10, 'bold'))
canvas.create_window(150, 200, window=okay)
browse_excel = Tkinter.Button(text='Import Excel File(s)', command = getExcel, bg='gray23', fg='white', font=('helvetica', 12, 'bold'))
canvas.create_window(150, 150, window = browse_excel)
root.mainloop()
the error I get it
raise ValueError(msg.format(_type=type(filepath_or_buffer)))
ValueError: Invalid file path or buffer object type: <type 'tuple'>
tkFileDialog.askopenfilenames(...) returns a tuple of one or more filenames. You can't pass this tuple directly to read_excel(); you'd have to loop over the contents of the tuple and call that function once per filename:
filenames = tkFileDialog.askopenfilenames(...)
for filename in filenames:
df = pd.read_excel(filename)
print(df)
Or you can call askopenfilename() (note there is no s on the end) for a single filename.

Problems while Handling Button Event in Python

How to Handle a Button Click Event in Python? I am New to python and trying to develop Zip Extractor tool.i've handled the Btn1 and Btn2 Properly but the 3'rd one is giving me errors.("name res1 is not defined") Here is the code
i've Wrote as follows: Plz Help Me as i am a noobie :| Thanks In Adv :)
from tkinter import *
from tkinter.filedialog import askdirectory
import os, zipfile
extension = ".zip"
PASSWORD = "virus007"
global res1
global res2
window = Tk()
window.title("Welcome Zip_Extractor_Utility")
window.geometry('640x260')
lbl1 = Label(window, text="Select Source Location:" ,font=("Arial Bold", 12))
lbl2 = Label(window, text="Select Destination Location:" ,font=("Arial Bold", 12))
lbl1.grid(column=0, row=7)
lbl2.grid(column=50, row=7)
def clicked1():
res1 = askdirectory()
print(res1)
return res1
btn1 = Button(window, text="Browse" , command=clicked1)
btn1.grid(column=1, row=7)
def clicked2():
res2 = askdirectory()
print(res2)
return res2
btn2 = Button(window, text="Browse" , command=clicked2)
btn2.grid(column=51, row=7)
##lbl3 = Label(window, text="Extract:" ,font=("Arial ", 12))
##lbl3.grid(column=70, row=7)
def clicked3():
os.chdir(res1) # change directory from working dir to dir with files
for item in os.listdir(res1): # loop through items in dir
if item.endswith(extension): # check for ".zip" extension
file_name = os.path.abspath(item) # get full path of files
zip_ref = zipfile.ZipFile(file_name) # create zipfile object
zip_ref.setpassword(PASSWORD)
zip_ref.extractall(res2) # extract file to dir
zip_ref.close() # close file
#os.remove(file_name) # delete zipped file
print('done')
btn3 = Button(window, text="Extract" , command=clicked3)
btn3.grid(column=71, row=7)
window.mainloop()
In your case, just check if res1 and res2 is defined in clicked3 function. Maybe with 'res1' in vars() and 'res2' in vars(). If it's not defined, warn users that they need to specify source and destination folder first.

How to load Excel cell values onto empty textboxes in a tkinter GUI, after the file has been selected by and "Open File" menu and loaded?

I have constructed a GUI with tkinter. There are two buttons, one to load an excel sheet and parse all cells and print their value. Also, I have a series of empty textboxes with headers. What I am trying to achieve is to load the parsed excel cells each onto a variable, then fill the empty textboxes with the cell value (i.e. the variable in question). Any pointers would be greatly appreciated. Here's my code so far:
#!/usr/bin/python3
from tkinter import filedialog
from tkinter import *
import openpyxl
from openpyxl import load_workbook
#Define Window Geometry
main = Tk()
main.geometry("1024x768")
main.title("Window Title")
#Define Empty Cells to be Filled in by Excel File & Calculation
def OpenDataInputSpreadsheetCallBack():
main.iconify()
file_path = filedialog.askopenfilename(initialdir = "file_path_goes_here",title = "Choose Input Spreadsheet",filetypes = (("Excel 2010 files","*.xlsx"),("Excel 2003 Files","*.xls")))
wb = load_workbook(filename = file_path, read_only=True)
ws = wb.active
for row in ws.iter_rows():
for cell in row:
if (cell.value==None):
pass
else:
print(cell.value)
#
#
#Function to display empty rows and columns
#
height = 5
width = 6
for x in range(1,height+1): #Rows
for y in range(width): #Columns
b = Entry(main, text='')
b.grid(row=x, column=y)
#
# Define Buttons
b1 = Button(main, text = "Open Data Input Spreadsheet", command = OpenDataInputSpreadsheetCallBack)
b1.place(x = 1,y = 120)
b2 = Button(main, text='Quit', command=main.destroy)
b2.place(x = 1,y = 150)
##
##
### Initialize Column Headers
Label(main, text="Header1").grid(row=0, column=0, sticky=W)
Label(main, text="Header2").grid(row=0, column=1, sticky=W)
Label(main, text="Header3").grid(row=0, column=2, sticky=W)
Label(main, text="Header4").grid(row=0, column=3, sticky=W)
Label(main, text="Header5").grid(row=0, column=4, sticky=W)
Label(main, text="Header6").grid(row=0, column=5, sticky=W)
###
# Define a function to close the window.
def quit(event=None):
main.destroy()
# Cause pressing <Esc> to close the window.
main.bind('<Escape>', quit)
#
#
main.mainloop()
Question: What I am trying to achieve is to load the parsed excel cells each onto a variable, then fill the empty textboxes with the cell value
You don't have to use a variable, you can pass the cell values direct to the textbox.
For instance:
class Textbox(object):
text = None
series_of_textboxes = [Textbox(),Textbox(),Textbox(),Textbox()]
# start reading from row 2
for i, row in enumerate( ws.iter_rows(min_row=2) ):
series_of_textboxes[i].text = ' '.join(cell.value for cell in row)
print( series_of_textboxes[0].text )
Output:
Bundesliga 27.08.16 Hamburg Ingolstadt
Tested with Python:3.4.2 - openpyxl:2.4.1
Come back and Flag your Question as answered if this is working for you or comment why not.

Categories

Resources