Robin
Robin

Reputation: 153

Python, tkinter, complex dialogs and code structure

When implementing complex dialogs (i.e. dialogs with some 10 or more widgets, especially when arranged within multiple frames or the like), the creation requires many tkinter calls and the code can become increasingly complex (difficult to read and maintain) when it is kept within a single method. Also in general, short functions/methods are usually preferred over longer ones.

My current approach to limit method length is to encapsulate creation of all widgets that belong to a group within the dialog into one method(parent_frame, other_options) that returns the top-level widget like this:

import tkinter as tk

class Dialog:
    def __init__(self, master):
        self.__master = master
        self.create_gui(master)

    def create_gui(self, frame, title = None):
        if title:  frame.title(title)

        group_a = self.create_group_a(frame)
        group_a.grid(row=0, column=0, sticky="nsew")

        group_b = self.create_group_b(frame)
        group_b.grid(row=1, column=0, sticky="nsew")

        frame.columnconfigure(0, weight=1)
        frame.rowconfigure(0, weight=1)
        frame.rowconfigure(1, weight=1)

    def create_group_a(self, frame):
        inner_frame = tk.LabelFrame(frame, text="Label")
        text = self.create_text_with_scrollbar(inner_frame)
        text.pack(fill="both")
        return inner_frame

    def create_group_b(self, frame):
        button = tk.Button(frame, text="Button")
        return button

    def create_text_with_scrollbar(self, frame):
        text_frame = tk.Frame(frame)
        text_frame.grid_rowconfigure(0, weight=1)
        text_frame.grid_columnconfigure(0, weight=1)

        text = tk.Text(text_frame)
        text.grid(row=0, column=0, sticky="nsew")

        scrollbar = tk.Scrollbar(text_frame, command=text.yview)
        scrollbar.grid(row=0, column=1, sticky="nsew")
        text['yscrollcommand'] = scrollbar.set

        return text_frame


if __name__ == "__main__":
    master = tk.Tk()
    Dialog(master)
    tk.mainloop()

Are there any specific guidelines around on code structuring in such cases? Does anybody have any advice on how to better structure such code?

Upvotes: 0

Views: 630

Answers (1)

Matthias Schreiber
Matthias Schreiber

Reputation: 2527

What I usually do is to write a new class for every group. Those classes inherit from Frame. The end result will look something like this:

class MainFrame(Frame):
    def __init__(self, *args, **kwargs):
        super().__init__(self, *args, **kwargs)
        self.first_sub = FirstSubFrame(self)
        self.second_sub = SecondSubFrame(self)

        self.first_sub.grid()
        self.second_sub.grid()


class FirstSubFrame(Frame):
    def __init__(self, *args, **kwargs):
        super().__init__(self, *args, **kwargs)
        self.possibly_another_subframe = PossibleOtherFrame(self)
        self.awesome_button = tkinter.Button()

        self.possibly_another_subframe.grid()
        self.awesome_button.grid()

...

I hope this helps.

Upvotes: 2

Related Questions