0
\$\begingroup\$

I'm trying to make the following code meaningful as much as possible, using inheritance. The purpose is for learning. The App class is the most super class. And the Tabs class has inherited it. Can I make the following code more meaningful and break it for more better classes? Instead of creating notebook = self.notebook for all the Tabs class methods, can't I initialize it in the Tab class's init method. When it is done notebook was non recognizable. I need all the tabs background color to be same. Hence, if I can mention it in the Tabs class's init method and convert its other methods(about, ..., visualize) into child classes of Tabs class, will it be a good suggestion? kindly help

import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk
from tkinter.filedialog import askopenfile
from tkinter.font import Font


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        # intializing the window
        
        self.title("Data Visualization")

        # configuring size of the window
        self.geometry('800x650')
        
        # this removes the maximize button
        self.resizable(0,0)

        # Styling the tabs
        s = ttk.Style()
        s.theme_create('pastel', settings={
            ".": {
                "configure": {
                    "background": '#ffffff', # All except tabs
                    "font": 'red'
                }
            },
            "TNotebook": {
                "configure": {
                    "background":'#848a98', # Your margin color
                    "tabmargins": [5, 5, 4, 4], # margins: left, top, right, separator
                }
            },
            "TNotebook.Tab": {
                "configure": {
                    "background": '#d9ffcc', # tab color when not selected
                    "padding": [10, 2], # [space between text and horizontal tab-button border, space between text and vertical tab_button border]
                    "font":"white"
                },
                "map": {
                    "background": [("selected", '#ccffff')], # Tab color when selected
                    "expand": [("selected", [1, 1, 1, 0])] # text margins
                }
            }
        })

        s.theme_use('pastel')
        #s.theme_use('default')
        s.configure('TNotebook.Tab', font=('URW Gothic L','13','bold'))
        #s.map("TNotebook", background= [("selected", "#ffffff")])
   

         #Create Tab Control
        
        self.notebook = ttk.Notebook(self)
        

    
class Tabs(App):
    
    def __init__(self):
        super().__init__()
    
    def about(self):
        
        my_font = Font(
            family = 'Arial',
            size = 15,
            weight = 'bold',
            slant = 'roman',
            underline = 0,
            overstrike = 0
        )
    
        my_font2 = Font(
            family = 'Arial',
            size = 11,
            #weight = 'bold',
            slant = 'roman',
            underline = 0,
            overstrike = 0
        )

        notebook = self.notebook
        f1 = tk.Frame(notebook)#,background="#FFFAF0")
        
                
        #logo
        logo = Image.open('airport.jpg')
        #Resize the Image using resize method
        resized_image= logo.resize((600,300), Image.ANTIALIAS)
        logo = ImageTk.PhotoImage(resized_image)
        logo_label = ttk.Label(f1,image=logo,relief="raised")
        logo_label.image = logo
        #logo_label.grid(column=3, row=0)
        logo_label.place(relx=0.12,rely=0.1) # using place
        notebook.add(f1, text="About" )
 
        
        # Tab1
        ttk.Label(f1, text="Airports, Airport-frequencies and Runways analysis", font=my_font).place(relx=0.2,rely=0.03)

        #text box
        
        text_box = tk.Text(f1, height =10,font=my_font2)
        text_box.insert(1.0,"""This application allows you to analyze Airports, Airport-frequencies and Runways of Europe.
        
        • Tab "Load and Save Actions" is to load the initial data set (which consists of three CSV files) and translate it into a suitable format. \n\n• Tab "Preprocess" is to clean and prepare the initial data set, managing inconsistences, \nerrors, missing values and any specific changes required. \n\n• Tab "Visualize" is to use the prepared data set to generate output and visualisations.""" )
        text_box.tag_configure("center", justify="center")
        text_box.tag_add("center", 1.0, "end")
        text_box.place(relx=0.1, rely=0.65)
        text_box.config(highlightthickness = 2, borderwidth=0,background='#FFFAFA')
        notebook.pack(expand=1, fill="both")
        
    def load_save(self):
        notebook = self.notebook
        f2 = tk.Frame(notebook,background="#ffffff")
        notebook.add(f2, text="Load and Save Actions" )
        
        
    def preprocess(self):
        notebook = self.notebook
        f3 = tk.Frame(notebook,background="#ffffff")
        notebook.add(f3, text="Preprocess" )
        
        
    def visualize(self):
        notebook = self.notebook
        f4 = tk.Frame(notebook,background="#ffffff")
        notebook.add(f4, text="Visualize" )
    

if __name__ == "__main__":
    

    tabs=Tabs()
    tabs.about()
    tabs.load_save()
    tabs.preprocess()
    tabs.visualize()
    tabs.mainloop()
\$\endgroup\$
1
  • \$\begingroup\$ Please edit your question so that the title describes the purpose of the code, rather than its mechanism. We really need to understand the motivational context to give good reviews. Thanks! \$\endgroup\$ Apr 22, 2022 at 21:17

1 Answer 1

1
\$\begingroup\$

meaningful as much as possible, using inheritance

Inheritance basically has no place here. Eventually, if your tab sections are larger and share more common elements, then perhaps having a Tab superclass would make sense, but it should absolutely not inherit from App.

Can I make the following code more meaningful and break it for more better classes?

I have no idea what that means, but you'll either want one single class, or perhaps eventually one class per tab.

Otherwise:

Don't inherit from Tk; instantiate it (has-a, not is-a).

In a few places you've passed 0 where you should pass False. A mature IDE like PyCharm, or probably a type-checking tool like mypy, will tell you this. This includes the call to resizable.

Long, constant literals such as your style dictionary may be better-suited to values in effectively static scope.

Methods such as about should be

  • called by your constructor, not by the instantiating code;
  • named perhaps _make_preprocess or _setup_preprocess - not preprocess - since this isn't doing the preprocessing
  • marked private via leading underscore; and
  • type-hinted as returning None.

You know about tk's ability to process named colours like white, since you've used that - so why would you also be passing #ffffff? Prefer the former.

Some of your comments, such as # tab color when not selected, are fine since they're describing something non-obvious. Most others need to be deleted, particularly those like:

    logo_label.place() # using place

f2 is a bad name for at least two reasons. First, it's meaningless and should include the word "frame". Second: this method should work and make sense regardless of whether the frame is actually the second frame. The notebook does not need an index for its add call. So just call it frame.

Similarly, don't say my_font; this is actually the label_font.

I do not have your airport.jpg so for illustrative purposes I have substituted my own.

Suggested

import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk
from tkinter.font import Font


class App:
    TAB_SETTINGS = {
        '.': {
            'configure': {
                'background': 'white',  # All except tabs
                'font': 'red'
            }
        },
        'TNotebook': {
            'configure': {
                'background': '#848a98',  # Your margin color
                'tabmargins': [5, 5, 4, 4],  # margins: left, top, right, separator
            }
        },
        'TNotebook.Tab': {
            'configure': {
                'background': '#d9ffcc',  # tab color when not selected
                'padding': [10, 2],
                # space between text and horizontal tab-button border, space between text and vertical tab_button border
                'font': 'white'
            },
            'map': {
                'background': [('selected', '#ccffff')],  # Tab color when selected
                'expand': [('selected', [1, 1, 1, 0])]  # text margins
            }
        }
    }

    def __init__(self) -> None:
        root = self.root = tk.Tk()
        root.title('Data Visualization')
        root.geometry('800x650')

        # this removes the maximize button
        root.resizable(False, False)

        s = ttk.Style()
        s.theme_create('pastel', settings=self.TAB_SETTINGS)
        s.theme_use('pastel')
        s.configure('TNotebook.Tab', font=('URW Gothic L', '13', 'bold'))
        self.notebook = ttk.Notebook(root)

        self._make_about()
        self._make_load_save()
        self._make_preprocess()
        self._make_visualise()
        self.run = root.mainloop

    def _make_about(self) -> None:
        label_font = Font(
            family='Arial',
            size=15,
            weight='bold',
            slant='roman',
            underline=False,
            overstrike=False,
        )

        textbox_font = Font(
            family='Arial',
            size=11,
            slant='roman',
            underline=False,
            overstrike=False,
        )

        frame = tk.Frame(self.notebook)

        logo = Image.open('airplane.png')
        resized_image = logo.resize((600, 300), Image.ANTIALIAS)
        logo = ImageTk.PhotoImage(resized_image)
        logo_label = ttk.Label(frame, image=logo, relief='raised')
        logo_label.image = logo
        logo_label.place(relx=0.12, rely=0.1)
        self.notebook.add(frame, text='About')

        ttk.Label(
            frame,
            text='Airports, Airport-frequencies and Runways analysis',
            font=label_font,
        ).place(relx=0.2, rely=0.03)

        text_box = tk.Text(frame, height=10, font=textbox_font)
        text_box.insert(1.0, '''This application allows you to analyze Airports, Airport-frequencies and Runways of Europe.

• Tab "Load and Save Actions" is to load the initial data set (which consists of three CSV files) and translate it into a suitable format.

• Tab "Preprocess" is to clean and prepare the initial data set, managing inconsistences,
errors, missing values and any specific changes required.

• Tab "Visualize" is to use the prepared data set to generate output and visualisations.''')
        text_box.tag_configure('center', justify='center')
        text_box.tag_add('center', 1.0, 'end')
        text_box.place(relx=0.1, rely=0.65)
        text_box.config(highlightthickness=2, borderwidth=0, background='#FFFAFA')
        self.notebook.pack(expand=1, fill='both')

    def _make_load_save(self) -> None:
        frame = tk.Frame(self.notebook, background='white')
        self.notebook.add(frame, text='Load and Save Actions')

    def _make_preprocess(self) -> None:
        frame = tk.Frame(self.notebook, background='white')
        self.notebook.add(frame, text='Preprocess')

    def _make_visualise(self) -> None:
        frame = tk.Frame(self.notebook, background='white')
        self.notebook.add(frame, text='Visualize')


if __name__ == '__main__':
    app = App()
    app.run()

Output

airplane

\$\endgroup\$
1
  • \$\begingroup\$ Thank u vary much Reinderien.... Very useful insights \$\endgroup\$
    – Hiru
    Apr 23, 2022 at 7:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.