5
\$\begingroup\$

This is my first time using Tkinter and really trying to get use to using classes in Python. I wonder if I'm using self entirely too much, but here is my code:

from Tkinter import *

class MainFrame(object):
    def __init__(self):
        self.display()
    #display all the labels for the main frame
    def labels(self):
        #adding x-cord label
        x_cord_label = Label(self.top, text = 'X-Coordinate').grid(row=0,column = 0)
    #calls the visible features
    def display(self):
        self.top = Tk()
        self.labels()
        self.entries()
        self.buttons()
        #must remain at bottom or wont be displayed
        self.top.mainloop()


    #display all the entry boxes for the main frame
    def entries(self):
        x_cord_entry = Entry(self.top,bd=5).grid(row=0,column = 1)

    def buttons(self):
        x_cord_button = Button(self.top, text = 'Enter').grid(row=0,column = 2)

I am planning on main just having the mainframe being generated.

main.py
from mainFrame import MainFrame
def main():
    window = MainFrame()


if __name__=="__main__":
    main()
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

Python has a set of rules for how documentation strings should look like. These strings are called docstrings in Python and the corresponding PEP is PEP257. You basically just move your comments from above the function name inside and make them strings:

def display(self):
    """Calls the visible features."""
    self.top = Tk()
    self.labels()
    self.entries()
    self.buttons()
    # must remain at bottom or wont be displayed
    self.top.mainloop()

Python also has an official style-guide, PEP8, which recommends adding a single space after the # in a comment, as well as using a single blank line between class methods (and two between class or normal function definitions). It also recommends using a space after a comma in an argument list, but no spaces surrounding = for keyword arguments.

Your method display could be moved completely to the __init__, but it is also fine as a separate method, in case you ever want to call it again to reset your application / display it again after changing some values. I would swap the display and labels methods, though, it makes for easier reading.

Regarding your doubt if you are overusing self, i think you are rather underusing it than overusing. I'm not exactly sure how Tkinter handles objects, but in Python in general, objects can and will be garbage-collected once they go outside of scope. So, after e.g. the method labels ran, the local variable x_coord_label will be removed and the associated object deleted (unless it is still being referenced from somewhere else, like the Tk main loop for example). So I would store these labels/buttons etc also as class members. This is handy if you ever want to modify them as well (changing the text label on a button is a quite regular feature...).

In general, you should avoid using from X import *, because it clutters your global namespace and might lead to name conflicts. With Tkinter, many people use it anyway, mostly because one tends to use a lot of its functions, so selectively importing from TKinter import Button, Label, ... becomes too long and unreadable and always writing Tkinter.Button is also quite verbose. As a compromise you can use import Tkinter as tk, which is shorter and still has its own namespace.

Final code:

import Tkinter as tk


class MainFrame(object):

    def __init__(self):
        self.display()

    def display(self):
        """Calls the visible features."""
        self.top = tk.Tk()
        self.labels()
        self.entries()
        self.buttons()
        # must remain at bottom or wont be displayed
        self.top.mainloop()

    def labels(self):
        """Display all the labels for the main frame."""
        # adding x-cord label
        self.x_cord_label = tk.Label(
            self.top, text='X-Coordinate').grid(row=0, column=0)

    def entries(self):
        """Display all the entry boxes for the main frame."""
        self.x_cord_entry = tk.Entry(self.top, bd=5).grid(row=0, column=1)

    def buttons(self):
        self.x_cord_button = tk.Button(
            self.top, text='Enter').grid(row=0, column=2)

If you want to extend this further, you probably want to add more than one button. In this case, you will need to decide on a datastructure to hold your texts and buttons. So in the end it might look more like this:

class MainFrame(object):

    def __init__(self, button_texts):
        self.button_texts = button_texts
        self.top = tk.Tk()
        self.setup_rows()
        self.top.mainloop()

    def setup_rows(self):
        """
        Display all the rows with labels, entries and buttons
        for the main frame.
        """
        self.rows = []
        top = self.top
        for i, text in enumerate(self.button_texts):
            row = [tk.Label(top, text=text).grid(row=i, column=0),
                   tk.Entry(top, bd=5).grid(row=i, column=1),
                   tk.Button(top, text='Enter').grid(row=i, column=2)]
            self.rows.append(row)
\$\endgroup\$
5
  • 1
    \$\begingroup\$ In Python, it's also frowned upon to import * instead of the specific things to be used (e.g. from math import sqrt) \$\endgroup\$
    – code_dredd
    Jun 22, 2017 at 10:56
  • \$\begingroup\$ @ray Normally I would agree 100%, but with Tkinter this is quite often done anyway, because one uses quite a lot of its functions, so explicit importing from would be too long and always writing Tkinter would be too lengthy. I'll edit it to use import Tkinter as tk, as a compromise, though. \$\endgroup\$
    – Graipher
    Jun 22, 2017 at 11:21
  • \$\begingroup\$ I understand. I think just noting this as an Tk-specific exception would be enough. I tried to use Tk once. After needing ~20 minutes to produce a main window with a single button I said "!@$ this !@#" and used PyQt instead. \$\endgroup\$
    – code_dredd
    Jun 22, 2017 at 11:27
  • \$\begingroup\$ I agree with @ray. To cut down on typing use import tkinter as tk and then use tk.Button, etc. It makes the code easier to maintain, easier to read, etc. \$\endgroup\$ Jun 22, 2017 at 11:48
  • \$\begingroup\$ @Bryan Edited the answer to state that. \$\endgroup\$
    – Graipher
    Jun 22, 2017 at 12:57

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.