Home > Mobile >  Passing values/tkinter elements between classes in tkinter
Passing values/tkinter elements between classes in tkinter

Time:01-07

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.

CodePudding user response:

Instead of passing the individual variables, pass the instance of the class that owns the variables. This reduces the number of things you have to pass back and forth, and it makes the code more self-documenting since it's clear that self.main.files.append(...) is appending to the list managed by the main program instead of a list managed locally.

class MainFrame:
    def __init__(self, master):
        ...
        FileSelect(master, main=self)
        LoadFiles(master, main=self)

class FileSelect:
    def __init__(self, master, main):
        self.main = main
        ...

    # 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.main.files.append(tb)

        # Update GUI, activate button in different class if condition met
        if len(os.listdir(directory)) == 0:
            # Update GUI Labels...
            self.main.button_state = tk.DISABLED
            print(self.main.files, self.main.button_state)
        elif len(self.files) == len(os.listdir(directory)):
            # Update GUI Labels...
            self.main.button_state = tk.NORMAL
            print(self.main.files, self.main.button_state)
  •  Tags:  
  • Related