Creating A Simple Gui Using Tkinter, And Having A Small Problem
Solution 1:
If you're trying to learn OOP, you're learning bad habits with this code.
Let's take a look at this code:
classSubmit(Button):def__init__(self, master):
super().__init__()
self.master = master
Button(text='Submit', background='black', foreground='light green', highlightthickness=0,
border=0)
Button.pack(self)
First, because you inherit from Button
, this class is aButton
. You then call Button(text=...)
which creates another button, so now you have two. If you're going to inherit from some other class, you don't need to create a second instance of that same class.
Also, these two lines are wrong:
super().__init__()
self.master = master
You need to pass master
to the __init__
of the superclass. The master is more than just an attribute, it's an integral part of the definition of the widget. It affects how the widget will appear. It must be passed to the superclass in order for the widget to be properly initialized.
Also, this is slightly more subjective, but you should not be calling Button.pack(self)
from within the definition of Submit
. One of the main reasons for objects is to make reusable components. By having a widget call pack
(or grid
or place
) on itself severely limits its re-usability. By calling pack
inside Submit
, it prevents you from using it or moving it to some other location in your UI which uses grid
. That is an unnecessary constraint.
In my experience, the overall layout of a UI will change during development. What if you decide that you want to switch from pack
to grid
because you've designed to change the layout? The way you have written this code, you will have to modify every single class.
Instead, code that creates a widget should be responsible for calling pack
, grid
, or place
. That means moving the call outside of the class and into the code that instantiates the class. This way, if you choose to use grid
, or stay with pack
but use some extra frames for organization, you only have to change the one function that creates each widget, rather than having to change every widget itself.
For example, the Submit
button class should more look like this:
classSubmit(Button):def__init__(self, master):
super().__init__(master)
self.configure(text='Submit', background='black', foreground='light green',
highlightthickness=0, border=0)
Then, in the same code where it's created, that's where you call pack
submit = Submit(root)
...
submit.pack(...)
If you later decide to switch to grid
, all you have to change is that last block of code.
Solution 2:
I'm not sure if there's just a single thing that's preventing the Submit button from being displayed, nor why you're deriving specialized widget subclasses that do nothing but hardcode some option settings into themselves — but, in general, you're not doing it correctly especially with respect to calling the superclass __init__()
and configuring the instance inside each derived class' own __init__()
.
The reason this is a less than ideal way of doing things is because it's going to require different subclasses for every, say Button
widget, your application needs — when all that's really required are instances of a single Button
class with different values assigned to its attributes (which tkinter
calls "options").
Subclassing should only be used when the actual code needs to be different. See the Definitions of subclass section of wikipedia article on Classes.
So, in my opinion you should instead just create instance of the stock tkinter
widget and assign the options you want each to have when you create the instances. This is the way it's usually done and would be a lot simpler.
Anyway, here's how to do implement your approach correctly, which also happens to fix the Button
not displaying issue:
import tkinter as tk
from tkinter import *
import tkinter.ttk as ttk
class Window(Frame):
def __init__(self, master):
super().__init__(master)
self.master = master
master.title('Learning Python')
master.config(background='black')
master.geometry('900x200')
master.resizable(0, 0)
class Submit(Button):
def __init__(self, master):
super().__init__(master)
self.master = master
self.config(text='Submit', background='black', foreground='light green',
highlightthickness=0, border=0)
self.pack()
class ProgressBar(ttk.Progressbar):
def __init__(self, master):
super().__init__(master)
self.master = master
self.config(orient='horizontal')
self.pack(fill=tk.BOTH)
class PagesRead(Label):
def __init__(self, master):
super().__init__(master)
self.master = master
self.config(text='How many page(s) did you read?', background='black',
foreground='light green')
self.pack()
class EntryBox(Entry):
def __init__(self, master):
super().__init__(master)
self.master = master
self.pack()
if __name__ == '__main__':
root = tk.Tk()
app = Window(root)
bar = ProgressBar(root)
pages = PagesRead(root)
entry = EntryBox(root)
submit = Submit(root)
app.mainloop()
Screenshot
Post a Comment for "Creating A Simple Gui Using Tkinter, And Having A Small Problem"