# First time using Tkinter

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):
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()


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."""
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)

• In Python, it's also frowned upon to import * instead of the specific things to be used (e.g. from math import sqrt) Jun 22 '17 at 10:56
• @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. Jun 22 '17 at 11:21
• 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. Jun 22 '17 at 11:27
• 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. Jun 22 '17 at 11:48
• @Bryan Edited the answer to state that. Jun 22 '17 at 12:57