Posts: 20
Threads: 4
Joined: Sep 2018
The original question I had was about making a Tkinter label display the time, here. The reply [below, in code] that helped me with my problem, also provided me more problems. After two months of attempting to find an answer, here I am. So...
import time
import tkinter as tk
APP_TITLE = "The Time"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 200
APP_HEIGHT = 100
class Application(object):
def __init__(self, main_win):
self.main_win = main_win
self.time_var = tk.StringVar()
self.build()
def build(self):
tk.Label(self.main_win, textvariable=self.time_var, width=10, fg='blue',
font=('Helvetica', 30, 'bold')).pack(expand=True)
self.update_time()
def update_time(self):
self.time_var.set(time.strftime('%H:%M:%S'))
self.main_win.after(1000, self.update_time)
def main():
main_win = tk.Tk()
main_win.title(APP_TITLE)
#main_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
main_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
app = Application(main_win)
main_win.mainloop() Particularly, the part where "main_win" is both a part of the application class, and part of a function definition? What is going on here? Searches related to classes and variables always seem to give me tutorials on OOP, class inheritance, class variables, or whatever but not this particular problem.
class Application(object):
def __init__(self, main_win): # this line
self.main_win = main_win # and this line
def main():
main_win = tk.Tk() # combined with this line
app = Application(main_win) # and this line, confuse me
main_win.mainloop() The __init__ method's "self.main_win = main_win" confuses me, and when "main_win" is an argument of the init method it confuses me more... Especially when it is also an instance of the Tk() class?
Thank you for your time.
Posts: 12,030
Threads: 485
Joined: Sep 2016
Mar-12-2019, 08:58 AM
(This post was last modified: Mar-12-2019, 08:58 AM by Larz60+.)
If written this way, may be easier to understand
has default values for title, width, height, xpos and ypos
** Note ** Uses f-string which requires python 3.6 or newer.
In example title default is overridden.
import time
import tkinter as tk
class Application(object):
"""
Initialization with default values for title, width, height, xpos, ypos
any of which can be overidden.
Uses f-string which requires python 3.6 or newer.
"""
def __init__(self, parent, title='Application', width=200, height=100, xpos=200, ypos=200):
self.parent = parent
self.parent.title(title)
self.parent.geometry(f"{width}x{height}+{xpos}+{ypos}")
self.time_var = tk.StringVar()
self.build()
def build(self):
tk.Label(self.parent, textvariable=self.time_var, width=10, fg='blue',
font=('Helvetica', 30, 'bold')).pack(expand=True)
self.update_time()
def update_time(self):
self.time_var.set(time.strftime('%H:%M:%S'))
self.parent.after(1000, self.update_time)
def main():
# Create an instance of Tk named main_win
main_win = tk.Tk()
#override default title
title='The Time'
# create instance of Application (with initialization variables)
app = Application(main_win)
# standard tkinter mainloop
main_win.mainloop()
if __name__ == '__main__':
main()
Posts: 20
Threads: 4
Joined: Sep 2018
Question about this part... (pseudo-code):
class IsntImportant(Object):
def __init__(self, parent):
self.parent = parent Specifically lines 2 and 3, if it were not clear. 100% not sarcastic, just new and learning this stuff, and don't want to try and attempt to look like I know what I'm doing, because I don't. But some times attempting to explain what I think is going on can help me understand it...
Anyway, is this essentially saying something like, "when you create an instance of this class, give it a variable called 'parent' [or rather, 'nameOfInstancedThing_parent' behind the scenes], and set it equal to whatever was passed in upon creation"? Would a variable equal to that class in the example above, without a parent value assigned to it, default to "None" or throw an error?
Also (and in relation to Tk), would it be correct to say that if you have another instanced object of the same "Tk() type", with parent set to "None" by default, that this is how "pop-up" menus are constructed? A sub-class of the "Tk() class" whose value of the parent variable is "None" but still part of the program?
Thank you!
Posts: 12,030
Threads: 485
Joined: Sep 2016
written this way: def __init__(self, parent):
you must pass a value for parent when instantiating __init__(self, parent):.
if you write it like __init__(self, parent=None):
then parent is optional when creating an instance of __init__(self, parent):
example with default parent == 'woogie':
class IsntImportant(Object):
def __init__(self, parent='woogie'):
self.parent = parent
myclass = IsntImportant() # parent defaults to 'woogie'
myotherclass = IsntImportant(parent='main_win') # parent changed to 'main_win'
Posts: 20
Threads: 4
Joined: Sep 2018
Okay, so simply indenting code doesn't just magically change things into classes. I am now getting errors related to the __init__ method when attempting to insert code into the build() method(?) of the class for the Application. I guess I am having trouble understanding how the interactions between objects within the class works, or how channels of communication between widgets happen, based on some init method. I do have a working "partial" program in tkinter, which (as a demonstration of functionality) switches between a label and an entry widget based on what radio button is selected. The interaction between widgets being the variables that control their "logic" functions; ie, "When I click on this, it changes this." So I am understanding some of it.
But that was all done by just importing everything. "from tkinter import *" and then just working with it in the module as is, without classes. That doesn't seem to work now.
Do I need a build method for every widget?
And, for every widget that has a build method, has a counterpart in the init method which calls the corresponding build method?
And that "master init method" in the Application class holds the default values for each build method?
If all that is true, then I should see an increase of code in my "Application", and the "main()" wouldn't change at all?
Posts: 12,030
Threads: 485
Joined: Sep 2016
Quote:Okay, so simply indenting code doesn't just magically change things into classes. I am now getting errors related to the __init__ method when attempting to insert code into the build() method(?) of the class for the Application.
An example please.
Posts: 20
Threads: 4
Joined: Sep 2018
Sorry, no example can be provided. It was a bad line of questions on my part.
I am trying to understand the process by which widgets are added to the GUI using classes in this manner. Each widget will be fairly unique to each part of the GUI, and it seems that each frame will have its own __init__ method? Is the indentation level of each widget in the code, what determines which frame that widget belongs to? And how would frames within frames be handled? Or would one big build() method be the body of the program which places all the widgets on the screen? Can I just assign a variable as an object within an object, of a widget I want to display?
I don't have examples, because I don't know what to code. What goes where? Helps to know internals and stuff, and I'm not quite sure I understand all of that yet either, but still learning. Thank you very much for being patient with me, you've been answering all my questions just fine.
Posts: 12,030
Threads: 485
Joined: Sep 2016
Quote:I am trying to understand the process by which widgets are added to the GUI using classes in this manner.
You really should spend some time learning about classes in general.
a widget is a class as a matter of fact everything in python is a class
To show this, consider this example:
>>> a = 5
>>> type(a)
<class 'int'>
>>> a is an instance of class int
as for widgets:
>>> import tkinter
>>> root = tkinter.Tk()
>>> type(root)
<class 'tkinter.Tk'>
>>> label_a = tkinter.Label(text='abc')
>>> type(label_a)
<class 'tkinter.Label'>
>>> # If you want to see methods and attributes for Label:
>>> help(tkinter.Label)
... here are some tutorials on classes:
Class Basics
Class Intermediate: Inheritance
Class Intermediate: Operator Overloading
Classes [advanced]: Dependent attributes (and Descriptors)
Classes [advanced]: Descriptors (managed attributes)
Posts: 2,168
Threads: 35
Joined: Sep 2016
(Mar-22-2019, 09:05 PM)Ceegen Wrote: what determines which frame that widget belongs to? when a widget is created it is passed a parent, the created widgets __init__ method then set the passed in widget as it parent, the widget then belongs to the passed in parent.
Posts: 20
Threads: 4
Joined: Sep 2018
(Mar-22-2019, 11:33 PM)Larz60+ Wrote: Quote:I am trying to understand the process by which widgets are added to the GUI using classes in this manner.
You really should spend some time learning about classes in general.
a widget is a class as a matter of fact everything in python is a class
To show this, consider this example:
>>> a = 5
>>> type(a)
<class 'int'>
>>> a is an instance of class int
as for widgets:
>>> import tkinter
>>> root = tkinter.Tk()
>>> type(root)
<class 'tkinter.Tk'>
>>> label_a = tkinter.Label(text='abc')
>>> type(label_a)
<class 'tkinter.Label'>
>>> # If you want to see methods and attributes for Label:
>>> help(tkinter.Label)
... here are some tutorials on classes:
Class Basics
Class Intermediate: Inheritance
Class Intermediate: Operator Overloading
Classes [advanced]: Dependent attributes (and Descriptors)
Classes [advanced]: Descriptors (managed attributes)
Reading up...
Search results for OOP and Python related material is flooded with all sorts of Udemy-related things. The docs don't seem to explain things in a way I can understand it, as most documentation I've seen tries to explain as little as possible.
(Mar-23-2019, 12:16 AM)Yoriz Wrote: (Mar-22-2019, 09:05 PM)Ceegen Wrote: what determines which frame that widget belongs to? when a widget is created it is passed a parent, the created widgets __init__ method then set the passed in widget as it parent, the widget then belongs to the passed in parent.
Okay. I'm going to go try a few things now in the code and see if I really understand what you're saying.
If I have any more questions as a result of that, I'll just come back to this thread.
Thanks x2.
|