Tkinter opening multiple files using one code - python

So I have designed a program that allows you to open 3 CSV files, and translate them into json, and 'clean' them then merge them into one file.
The way i have designed it, is that on display, there are 3 buttons for loading each file, but i am wondering if there is a better design that shows only 1 button, which the user can load multiple files that are assigned to different variables, depending on the column headings in these csv files.
The problem that I had, is when you load one file, it overrides the previously loaded file.
For reference, the csv files can be only 1/3 different formats so the column headings are known.
As you can see from a short part of my code, that i have created 2 different loadfile buttons, for the 2 separate files, but is there a way i can have just 1 button, that assisgns different files to different variables?
import tkinter as tk
from tkinter import *
from tkinter import filedialog
from tkinter import messagebox
import pandas as pd
import json
import csv
import sys
import sqlite3
#
def loadInspection():
global inspectionFile
global label_inspectionFile
loadingCSV = filedialog.askopenfilename()
inspectionFile = pd.read_csv(loadingCSV)
#Making buttons for load and translate and clean
loadButton = Button(window1, text="Load Inspections File", command=loadInspection)
loadButton.grid(row=0, column=1)
#loading first file called inspections
def inspectionClean():
global inspectionFile
inspectionFile = inspectionFile
#Check and remove any duplicates in the Inspection Data
inspectionFile = inspectionFile[inspectionFile.duplicated() == False]
cleanInsButton = Button(window1, text="Clean", command=inspectionClean)
cleanInsButton.grid(row=0, column=3)
#loading second file called inventroy
def loadInventroy():
global inventroyFile
loadingCSV = filedialog.askopenfilename()
inventroyFile = pd.read_csv(loadingCSV)
#Making buttons for load and translate and clean
loadButton = Button(window1, text="Load Inventroy File", command=loadInventroy)
loadButton.grid(row=3, column=1)
def inventroyClean():
global inventroyFile
inventroyFile = inventroyFile
#Check and remove any duplicates in the Inspection Data
inventroyFile = inventroyFile[inventroyFile.duplicated() == False]
cleanInvButton = Button(window1, text="Clean", command=inventroyClean)
cleanInvButton.grid(row=3, column=3)

My guess would be this may be a problem with global variables. In general I would recommend using instance/class variables instead, using global variables is generally not advised.
Your load functionality could instead be structured like this:
class MyCSVLoader:
def __init__(self):
self.inventory = None
self.inspection = None
def loadCSV(self):
loadingCSV = filedialog.askopenfilename()
return pd.read_csv(loadingCSV)
def loadAll(self):
self.inspection = self.loadCSV()
self.inventory = self.loadCSV()
However, let me know if this works as I don't have csv files on hand to test it with.
Then, you could implement it with one button like this:
csvLoader = MyCSVLoader()
loadButton = tk.Button(window1, text="Load All Files", command=csvLoader.loadAll)
loadButton.grid(row=0, column=1)
Which should pop up 1 window after the other for you to select 2 files. The files selected can then be accessed through csvLoader.inventory and csvLoader.inspection.
Note that your clean function would also have to go into this class to function properly.

Related

Button command doesn't updates my Label textvariable

I have this very easy program which I want to display one random line from a file each time I click on the Button.
Problem is a new line is display at startup of the program, but nothing happens when I click the button, can someone explain me why ?
from random import randrange
from tkinter import *
def entree():
n=randrange(251)
fs = open('lexique','r')
liste = fs.readlines()
return liste[n]
fen = Tk()
fen.title("lexique anglais politique")
defi = StringVar()
defi.set(entree())
lab = Label(fen, textvariable=defi).pack()
Button(fen, text='Beste Bat', command=entree).pack()
fen.mainloop()
As stated in one of the comments (by #matszwecja), your entree() function doesn't really do anything appart from returning a value.
Nothing in your code updates the actual label. Try something like this :
from random import randrange
from tkinter import *
def entree():
n=randrange(251)
fs = open('lexique','r')
liste = fs.readlines()
return liste[n]
def update_label():
lab.config(text=entree())
fen = Tk()
fen.title("lexique anglais politique")
lab = Label(fen, text=entree())
lab.pack()
Button(fen, text='Beste Bat', command=update_label).pack()
fen.mainloop()
In this example, the entree() function is used to go get a line from your file, and the update_label() function is used to actually update the label.
Also, if you want to be able to update a label, you'll have to pack it after assigning it to a variable.
On a side note, it could be worth noting that hardcoding values that could change in the future is generally considered bad practice. In that regard, I think coding the entree() function this way might be a better idea :
def entree():
fs = open('lexique','r')
liste = fs.readlines()
n=randrange(len(liste))
return liste[n]
This way, if you ever add or remove lines to your "lexique" file, you will not have to change the code.

How to update variables from a text file in a GUI in real time? Python and tkinter

I have a script that continuously updates numbers on a text file in the same directory. I made a GUI using tkinter to display these numbers. I'm having a hard time getting the GUI to update the numbers in real time. It will display the numbers as they were when the GUI first started, but will not update the display as the text file changes. Here's some basic code to demonstrate:
def read_files(file, line):
old = open(f'{file}.txt', 'r').readlines()[line]
new = old.replace('\n', '')
return new
number = read_files('Statistics', 0)
number_label = Label(frame1, text=f'{number}')
number_label.grid(row=0, column=0)
The above code shows the number from the text file as it was when the GUI first opened. However, it does not update the number as its value in the text file changes. I did some reading around and also tried the following:
def read_files(file, line):
old = open(f'{file}.txt', 'r').readlines()[line]
new = old.replace('\n', '')
return new
number = read_files('Statistics', 0)
number_label = StringVar()
number_label.set(number)
number_display = Label(frame1, text=f'{number_label.get()}')
number_display.grid(row=0, column=0)
This has the same effect. It shows the value retrieved from the text file at the moment the GUI was opened, but does not update it as the text file is updated. Any help is appreciated.
Since there is no complete code, take a look at this example:
from tkinter import *
root = Tk()
def update_gui():
number = read_files('Statistics', 0) # Call the function
number_display.config(text=number) # Change the text of the label, also same as text=f'{number}'
root.after(1000,update_gui) # Repeat this function every 1 second
def read_files(file, line):
old = open(f'{file}.txt', 'r').readlines()[line]
new = old.replace('\n', '')
return new
number_display = Label(root) # Empty label to update text later
number_display.grid(row=0, column=0)
update_gui() # Initial call to the function
root.mainloop()
Here the label is created outside the function but the text is not given, but inside the function we are repeating the function every 1 second, with after, and changing the text of the label with config method. I have avoided the use of StringVar() as it's of no use here, you can just store it in a normal variable and use it.
Here is a plagiarized look at how after should be used:
def after(self, ms, func=None, *args):
"""Call function once after given time.
MS specifies the time in milliseconds. FUNC gives the
function which shall be called. Additional parameters
are given as parameters to the function call. Return
identifier to cancel scheduling with after_cancel."""

Global variable are not working in this Python code

I have a student that is working on a task and trying to use global variables within a couple functions across different files. I have had to include excerpts of the files. The first file is the main one and when you click the results button in that program (from the main window it creates) it should call the other file and pass a variable. But, he gets the following error...
Results.py", line 44, in GiveResults if row[0] == sname: NameError: name 'sname' is not defined
I'm hoping that someone with much better ability and knowledge might be able to point us in the right direction to remedy this. If there is a better way to share the code on here then please also let me know.
Thanks,
Scott
'Solution.py'
#This imports the tkinter module of python
from tkinter import *
#This imports the other windows for use later
import Results, New_User, Edit_User
#This part forms the main window and controls things such as size, colour, and message
main = Tk()
main.title('Hello there')
main.geometry("1000x600")
main['background']='light blue'
#This creates a frame for use later
window = Frame(main).pack()
#Defines a function that when called will convert whatever is in the textboxes to variables
def retrieve():
global sname
sname = selectedname.get()
global sboss
sboss = selectedname.get()
'Results.py'
from tkinter import *
#This is defining the function that the first window is calling upon
def GiveResults():
#This is defining the variables as globe for use across windows (Although it isnt working)
global sname
global sboss
global inputt
#Defines a quit function to close the window when called
def quit():
ResultsGiven.destroy()
#This is making the window
ResultsGiven = Tk()
ResultsGiven.title('You did the program')
ResultsGiven.geometry("600x400")
ResultsGiven['background']='light blue'
#Creating a frame
windowr = Frame(ResultsGiven, bg = 'light blue')
#Creating a title
titlefont = ('papyrus', 30)
title = Label(windowr, text='Results', font=titlefont)
title.config(height=1, width=400)
title.pack(side=TOP, fill = 'x')
#Creating a canvas
canvasr = Canvas(windowr, width = 400, height = 400, background = 'light blue')
canvasr.pack()
#This is importing the csv module of python
import csv
#This is opening the csv file created when a new user is made
#It is then creating a reader to check the first column for the name entered in the main window
#When it finds a match it moves along that row to find the class
#(Unfinished)
with open("userbase.csv") as f:
for row in csv.reader(f):
if row[0] == sname:
sclass = str(column[2])```

How can i make the browsed file the target for process, instead of it being hard coded in?

Instead of "mbox = ?????????" in the def start_processing(self) section, how do i make it the file that has been uploaded. This was originaly hard coded however have changed it to a file upload? Thanks
class App:
def __init__(self, master):
self.master = master
# call start to initialize to create the UI elemets
self.start()
def start(self):
self.master.title("Extract Email Headers")
self.now = datetime.datetime.now()
# CREATE A TEXT/LABEL
# create a variable with text
label01 = "Please select the .mbox file you would like to analyse"
# put "label01" in "self.master" which is the window/frame
# then, put in the first row (row=0) and in the 2nd column (column=1),
# align it to "West"/"W"
tkinter.Label(
self.master, text=label01).grid(row=0, column=0, sticky=tkinter.W)
# CREATE A TEXTBOX
self.filelocation = tkinter.Entry(self.master)
self.filelocation["width"] = 60
self.filelocation.focus_set()
self.filelocation.grid(row=1, column=0)
# CREATE A BUTTON WITH "ASK TO OPEN A FILE"
# see: def browse_file(self)
self.open_file = tkinter.Button(
self.master, text="Browse...", command=self.browse_file)
# put it beside the filelocation textbox
self.open_file.grid(row=1, column=1)
# now for a button
self.submit = tkinter.Button(
self.master, text="Execute!", command=self.start_processing,
fg="red")
self.submit.grid(row=3, column=0)
def start_processing(self):
date1= "Tue, 18 Jan 2015 15:00:37"
date2="Wed, 23 Jan 2015 15:00:37"
date1 = parser.parse(date1)
date2 = parser.parse(date2)
f = open("results.txt","w")
mbox = ????????????????????
count = 0
for msg in mbox:
pprint.pprint(msg._headers, stream = f)
tempdate = parser.parse(msg['Date'])
print(tempdate)
f.close()
print(count)
pass
def browse_file(self):
# put the result in self.filename
self.filename = filedialog.askopenfilename(title="Open a file...")
# this will set the text of the self.filelocation
self.filelocation.insert(0, self.filename)
I'm assuming you want to store the file path in a StringVar. TK uses special control variables to provide functionality for Entry objects. You can create a string control variable by calling the function tk.StringVar().
You want to create the variable when you initialize your UI, so in your start() method:
# CREATE A TEXTBOX
self.filepath = tkinter.StringVar() # This will hold the value of self.filelocation
# We set it to the "textvariable" option of the new entry
self.filelocation = tkinter.Entry(self.master, textvariable=self.filepath)
self.filelocation["width"] = 60
self.filelocation.focus_set()
self.filelocation.grid(row=1, column=0)
Now when we want to retrieve the value of it we use the get() method. In your start_processing() method:
# Here it opens the file, but you may want to do something else
mbox = open(self.filepath.get(),'r')
The way you set the value in your browse_file() method can be updated to use the control variable quite easily. Instead of inserting into the entry box directly, we'll set the value of our control variable and it will automatically update in the text entry field. In browse_file():
# this will set the text of the self.filelocation
self.filepath.set( self.filename )
Now you can properly set and retrieve the value of self.filelocation the intended way. You can change the name of self.filepath to whatever you want, of course.
For more information:
Tkinter 8.5 Reference - Control Variables
TkDocs - Tk Tutorial - Basic Widgets - Entry
I don't know for certain if mbox is supposed to be an open file, a list, a tuple, or some custom object. I'm going to assume it's an open file, since you have a function to pick a filename.
If that's the case, all you need to do is call the get method of the entry widget to get whatever the user typed:
mbox_name = self.filelocation.get()
mbox = open(mbox_name, "r")
for msg in mbox:
...

inserting path in the entry box in Python GUI

I'm new to GUI programming. I made a small GUI where the user browses the file and then do the functionalities he wants with the file.
Now i have an Entry Box in the GUI and whenever a user browses for the required file and after he finishes browsing the path to the file should appear in the entry box.
basically i want it like this
befor browsing
after browsing
How can i do this?
My code to the GUI is :
#!/usr/bin/python
import Tkinter as tk
from tkFileDialog import *
import os
class StageGui:
prot=0
log=0
cwd=os.getcwd()
def __init__(self,parent,tex):
self.tex=tex
self.fm=tk.Frame(remodelmain)
self.l1=tk.Label(self.fm, text='Import .prot File').grid(row=0,column=0,sticky='w',padx=5,pady=10)
self.l2=tk.Label(self.fm, text='Import .log File').grid(row=1,column=0,sticky='w',padx=5,pady=10)
self.protentry = tk.Entry(self.fm, width = 50).grid(row=0,column=1,sticky='w',padx=5,pady=10)
self.logentry = tk.Entry(self.fm, width = 50).grid(row=1,column=1,sticky='w',padx=5,pady=10)
self.b1=tk.Button(self.fm, text='Browse',height=1,width=20,command=self.callback).grid(row=0,column=2,sticky='e',padx=5,pady=10)
self.b2=tk.Button(self.fm, text='Browse',height=1,width=20,command=self.callback1).grid(row=1,column=2,sticky='e',padx=5,pady=10)
self.fm.pack()
self.fm0=tk.Frame(remodelmain,width=500,height=500)
self.b3=tk.Button(self.fm0, text='Check',height=1,width=15,command=self.check).grid(row=4,column=2,sticky='e',padx=5,pady=10)
self.b4=tk.Button(self.fm0, text='Inertia',height=1,width=15).grid(row=5,column=2,sticky='e',padx=5,pady=10)
self.b5=tk.Button(self.fm0, text='Summary',height=1,width=15).grid(row=6,column=2,sticky='e',padx=5,pady=10)
self.b6=tk.Button(self.fm0, text='Report',height=1,width=15).grid(row=7,column=2,sticky='e',padx=5,pady=10)
self.fm0.pack(side='right')
self.fm1=tk.Frame(remodelmain,width=200,height=200)
self.tex1= tk.Text(self.fm1,width=130,height=10)
self.l3=tk.Label(self.fm1, text='Status Box:').grid(row=6,column=0,sticky='nw')
self.tex1.grid(row=6,column=1,sticky='s',padx=20,pady=10)
self.fm1.pack(side='left',anchor='w')
def callback(self):
name= askopenfilename()
StageGui.prot=name
self.printstatements(StageGui.prot)
def printstatements(self,name):
self.tex1.insert('end','\nthe file has been imported \n')
s='the path of the imported file is {}\n'.format(name)
self.tex1.insert('end',s)
self.tex1.see(tk.END)
return
def callback1(self):
name1= askopenfilename()
StageGui.log=name1
self.printstatements(StageGui.log)
def check(self):
file=open(StageGui.prot,'r')
a,b,c='|Checks|','|Status|','|Remarks|'
mess='\n{0:10s} \t {1:10s} \t {2:100s}\n'.format(a,b,c)
self.tex.insert('end',mess)
count_string_occurance(file)
remodelmain = tk.Tk()
fmn1=tk.Frame(remodelmain,width=300,height=300)
l3=tk.Label(fmn1, text='Message Box:').grid(row=6,column=0,sticky='nw')
tex= tk.Text(fmn1,width=130,height=60)
tex.grid(row=6,column=1,sticky='s',padx=20,pady=20)
fmn1.pack(side='bottom',anchor='w')
stagegui=StageGui(remodelmain,tex)
remodelmain.title('prototype_remodel')
remodelmain.geometry('1200x1200+300+300')
remodelmain.mainloop()
Create a string varible that is associated with the Entry widget:
self.pathVar = tk.StringVar(self.fm)
self.protentry = tk.Entry(self.fm, width = 50, textvariable=self.pathVar).grid(row=0,column=1,sticky='w',padx=5,pady=10)
Then after getting the path, set the variable to that path:
name= askopenfilename()
self.pathVar.set(name)

Categories