Reputation: 50
I'm trying to create a 'read from csv file' class. This class should read a csv file and return result as a list.So far- quite simple even for a newbie as me.
BUT- I need something a bit more complexed:
1) If filename is not given ( as an argument to class) - a file selection dialog box pops up to select one.
2) Optional: show file's content in a GUI, using a CSVGui
class (using method self.out_in_gui
).
Since ReadCSV
is not GUI based class, GUI is initialized only in need to launch a askopenfilename
. A use of widtdraw()
is made in order not to show additinal blank GUI.
The probelm is: When I try to read a file, without spcifing one, a file selection dialog pops up, PLUS calling method self.out_in_gui
to execute CSVGui
class - file contents does not show in GUI (Entries left empty).
TRIES:when I specify as a parameter, the file to be loaded, everything runs OK. My guess- it has something to do with using the GUI in ReadFile
to load file selection GUI.
Thanks J
import csv
import tkinter as tk
from tkinter import ttk
from tkinter.filedialog import askopenfilename
class ReadFile:
"""This class reads CSV w/out header line, and returen it as a list"""
def __init__(self, fname='', path='', **kwargs):
if fname == '' and path == '':
tk.Tk().withdraw()
self.filename = askopenfilename(title='Select CSV file', filetypes=[('CommaSeperatedFile', '*.csv')])
else:
if path != '':
self.filename = path + '/' + fname
else:
self.filename = fname
self.file_content = []
self.read_file(kwargs)
self.out_in_gui()
def read_file(self, kwargs):
with open(self.filename, newline='', **kwargs) as csvfile:
file_obj = csv.reader(csvfile)
for i in file_obj:
self.file_content.append(i)
print("file %s was read successfully, containing %d lines" % (self.filename, len(self.file_content)))
def out_in_gui(self):
print("send data to CSVGui")
CSVGui(self, data=self.file_content)
def file_contents(self):
return self.file_content
class CSVGui(ttk.Frame):
def __init__(self, master=None, data=[]):
ttk.Frame.__init__(self, master)
self.master = master
# csvroot = tk.Tk()
fname = 'No file loaded'
# if data is not None and master is not None:
# fname = self.master.filename
# csvroot.title("CSVGui - " + fname)
self.frame = ttk.LabelFrame(self, text='Data set', padding=10)
self.frame.grid(row=0, column=0, padx=5, pady=5)
self.widgets_frame = ttk.Frame(self)
self.widgets_frame.grid(row=1, column=0)
self.m, self.row_vars = [], []
self.exec_gui(data)
print(data)
# self.read_from_gui()
# csvroot.mainloop()
def exec_gui(self, data):
# populted and create GUI with data
for r in range(len(data)):
self.m = []
self.ent = ''
for col in range(len(max(data))):
self.m.append(tk.StringVar())
self.ent = ttk.Entry(self.frame, textvariable=self.m[-1], state=tk.NORMAL)
self.ent.grid(row=r, column=col)
try:
self.m[-1].set(data[r][col])
print("IN")
except IndexError:
self.m[-1].set('')
print("OUT")
# create structured vector of var for use in save mode
self.row_vars.append(self.m)
self.create_widgets()
print("CSVGui - Created")
def create_widgets(self):
self.save_button = ttk.Button(self.widgets_frame, text='Save', command=self.save2file)
self.save_button.grid(row=0, column=0)
self.exit_button = ttk.Button(self.widgets_frame, text='Exit') # , command=print('Exit'))
self.exit_button.grid(row=0, column=1)
tk.Spinbox(self.widgets_frame, width=5, from_=0, to=20).grid()
def read_from_gui(self):
data_list = []
for r, rows in enumerate(self.row_vars):
c_data = []
for c, cols in enumerate(rows):
if cols.get() != '':
c_data.append(cols.get())
data_list.append(c_data)
return data_list
def save2file(self):
WriteFile('w', self.master.filename, data=self.read_from_gui())
Upvotes: 2
Views: 572
Reputation: 142859
I tried your code and it doesn't work for me because problem is master
In ReadFile
you run CSVGui(self, ...)
and self
means ReadFile
. In CSVGui
you assign this ReadFile
to master
and use in ttk.Frame.__init__(self, master)
- but master
has to be any tkinter's
widget, not ReadFile
.
I made changes in two places
First: in ReadFile
I create Tk()
window and after askopenfilename
I destroy it. This way if I run ReadFile()
or ReadFile(filename.csv)
I always will run CSVGui
without master
in computer memory.
if fname == '' and path == '':
master = tk.Tk()
master.withdraw()
self.filename = askopenfilename(title='Select CSV file', filetypes=[('CommaSeperatedFile', '*.csv')])
master.destroy()
Second: CSVGui
doesn't need master
as second argument because I create it inside CSVGui
class CSVGui(ttk.Frame):
def __init__(self, data=[]):
master = tk.Tk()
ttk.Frame.__init__(self, master)
It also need self.pack()
to put class CSVGui(ttk.Frame)
inside this master, and master.mainloop()
to keep it open.
import csv
import tkinter as tk
from tkinter import ttk
from tkinter.filedialog import askopenfilename
class ReadFile:
"""This class reads CSV w/out header line, and returen it as a list"""
def __init__(self, fname='', path='', **kwargs):
if fname == '' and path == '': # <--- changes
master = tk.Tk()
master.withdraw()
self.filename = askopenfilename(title='Select CSV file', filetypes=[('CommaSeperatedFile', '*.csv')])
master.destroy()
else:
if path != '':
self.filename = path + '/' + fname
else:
self.filename = fname
self.file_content = []
self.read_file(kwargs)
self.out_in_gui()
def read_file(self, kwargs):
with open(self.filename, newline='', **kwargs) as csvfile:
file_obj = csv.reader(csvfile)
for i in file_obj:
self.file_content.append(i)
print("file %s was read successfully, containing %d lines" % (self.filename, len(self.file_content)))
def out_in_gui(self):
print("send data to CSVGui")
CSVGui(self.filename, data=self.file_content) # <--- changes
def file_contents(self):
return self.file_content
class CSVGui(ttk.Frame):
def __init__(self, filename, data=[]): # <--- changes
self.filename = filename # <--- changes
master = tk.Tk() # <--- changes
ttk.Frame.__init__(self, master)
self.grid() # <--- changes (updated. was `pack` before)
# csvroot = tk.Tk()
fname = 'No file loaded'
# if data is not None and master is not None:
# fname = self.master.filename
# csvroot.title("CSVGui - " + fname)
self.frame = ttk.LabelFrame(self, text='Data set', padding=10)
self.frame.grid(row=0, column=0, padx=5, pady=5)
self.widgets_frame = ttk.Frame(self)
self.widgets_frame.grid(row=1, column=0)
self.m, self.row_vars = [], []
self.exec_gui(data)
print(data)
# self.read_from_gui()
# csvroot.mainloop()
master.mainloop() # <--- changes
def exec_gui(self, data):
# populted and create GUI with data
for r in range(len(data)):
self.m = []
self.ent = ''
for col in range(len(max(data))):
self.m.append(tk.StringVar())
self.ent = ttk.Entry(self.frame, textvariable=self.m[-1], state=tk.NORMAL)
self.ent.grid(row=r, column=col)
try:
self.m[-1].set(data[r][col])
print("IN")
except IndexError:
self.m[-1].set('')
print("OUT")
# create structured vector of var for use in save mode
self.row_vars.append(self.m)
self.create_widgets()
print("CSVGui - Created")
def create_widgets(self):
self.save_button = ttk.Button(self.widgets_frame, text='Save', command=self.save2file)
self.save_button.grid(row=0, column=0)
self.exit_button = ttk.Button(self.widgets_frame, text='Exit') # , command=print('Exit'))
self.exit_button.grid(row=0, column=1)
tk.Spinbox(self.widgets_frame, width=5, from_=0, to=20).grid()
def read_from_gui(self):
data_list = []
for r, rows in enumerate(self.row_vars):
c_data = []
for c, cols in enumerate(rows):
if cols.get() != '':
c_data.append(cols.get())
data_list.append(c_data)
return data_list
def save2file(self):
WriteFile('w', self.filename, data=self.read_from_gui()) # <--- changed
ReadFile()
EDIT: I added filename
to CSVGui(self.filename, data=self.file_content)
Upvotes: 1