Initially I wrote this tkinter app functionally, but now that I'm converting it into OOP due to how bloated its become, the major issue I'm having is understanding a streamlined way to pass variables between a large number of classes.
Below is a minimum test version of the start of my code, with two variables defined in Mainframe that I want to first pass to FileSelect to update them and then on to LoadFiles. The big area of confusion for me is why file_list is seemingly updating correctly when running print_files, but the import_state variable I want to use to enable a button in LoadFiles does not.
import os
import tkinter as tk
from tkinter import filedialog
class MainFrame:
def __init__(self, master):
self.master = master
# Variables
self.file_list = [] # Files list
self.import_state = tk.DISABLED # Enable import on correct fp
# Class Frames
FileSelect(master, self.file_list, self.import_state)
LoadFiles(master, self.file_list, self.import_state)
class FileSelect:
def __init__(self, master, files, button_state):
self.files = files
self.button_state = button_state
# Frame
self.frame = tk.LabelFrame(master, text='File Selection')
self.frame.grid(row=0, column=0)
# Select directory button
tk.Button(self.frame, text='Open:', command=self.directory_path).grid(row=0, column=0)
# Tkinter Elements...
# Directory Selection
def directory_path(self):
# Select filepath
directory = filedialog.askdirectory(initialdir="/", title="Select a directory")
os.chdir(directory)
# Populate list of files
for tb in os.listdir(directory):
self.files.append(tb)
# Update GUI, activate button in different class if condition met
if len(os.listdir(directory)) == 0:
# Update GUI Labels...
self.button_state = tk.DISABLED
print(self.files, self.button_state)
elif len(self.files) == len(os.listdir(directory)):
# Update GUI Labels...
self.button_state = tk.NORMAL
print(self.files, self.button_state)
class LoadFiles:
def __init__(self, master, files, button_state):
self.files = files
self.button_state = button_state
# Frame
self.frame = tk.LabelFrame(master, text='File loading')
self.frame.grid(row=1, column=0)
# Load button
self.import_files_button = tk.Button(self.frame, text='Import TB', command=self.print_files)
self.import_files_button.grid(row=0, column=0, sticky="EW")
# Tkinter Elements...
def print_files(self):
print(self.files, self.button_state)
if __name__ == "__main__":
root = tk.Tk()
MainFrame(root)
root.mainloop()
Aside from the issue of variable passing between classes, is there a more streamlined way of doing this in general? One of the main reasons I've seen OOP advocated is how much it improves readability, organisation, and isolating tkinter elements, but the variable handling seems to be a major lynchpin when converting from functional.
tk.DISABLEDis a string and they're immutable, so all that happens in the called method is a value is assigned to the class'button_stateattribute and when that's changed it only affect the value associated with the attribute. On the other handfile_listis a list which are mutable. So changes made to it through itsappend()method actually change its value (contents). See Facts and myths about Python names and values.