Reputation: 1949
Inspired by this 300+ vote closed Q&A: Best way to structure a tkinter application?, I'm looking to avoid explicitly using root
in a function within a class. I think it should be implicitly declared through self
or parent
or something like that. Here is the code in question:
I have this code...
self.label_this = tk.StringVar()
self.label_last = tk.StringVar()
self.label_total = tk.StringVar()
tk.Label(count_frame, textvariable=self.label_this, \
font=(None, MON_FONTSIZE)).pack(anchor=tk.W)
tk.Label(count_frame, textvariable=self.label_last, \
font=(None, MON_FONTSIZE)).pack(anchor=tk.W)
tk.Label(count_frame, textvariable=self.label_total, \
font=(None, MON_FONTSIZE)).pack(anchor=tk.W)
self.update_cnt_labels()
Then later on...
''' Get list of Window ID's on monitor now '''
new_windows = self.windows_on_monitor(new_windows)
new_windows_cnt = len(new_windows) / WIN_CNT
if self.old_windows_cnt == new_windows_cnt :
FlashMessage (self.label_this, "No new windows to remove...", \
3, 750, 250)
self.update_cnt_labels()
return
Then later on...
class FlashMessage:
def __init__(self, widget, message, count=5, on=500, off=300):
self.delay_show (1, widget, message)
for i in range(count):
self.delay_show (on, widget, "")
self.delay_show (off, widget, message)
def delay_show(self, ms, widget, message):
root.after(ms, widget.set(message))
root.update_idletasks()
I want to avoid using root
in the last two lines and use self
or something similar.
My program call chain is something like:
root = tk.Tk()
ResizingCanvas(mycanvas)
popup(event)
which is bound to <ButtonPress-1>
menu.tk_popup(event.x_root, event.y_root)
RemoveNewWindows()
remove()
FlashMessage()
(show above)self.delay_show()
(shown above)Each class and function has haphazard self
, positional parameters, *args
and **kwargs
which mostly serve no purpose. Indeed even the __init__
above might be unnecessary. This is a result of copying code all over stack overflow.
Every second word in the program seems to be self
but the word parent
is only used in the class ResizingCanvas()
. Do I have to propagate parent
down the call list and use it somehow?
Upvotes: 0
Views: 68
Reputation: 385980
You can call after
and update_idletasks
on any widget. There are many such functions that can be called on any widget but which have a global effect.
In your case, you'll need to pass some widget into the FlashMessage
constructor and save the reference. You can then use the reference to call the functions.
You're passing something called widget
that doesn't actually contain a widget. You need to rename it to something more appropriate (eg: var
), and then pass in an actual widget.
(Note: you also are calling after
incorrectly, which I've fixed in the following example)
For example:
class FlashMessage:
def __init__(self, widget, var, message, count=5, on=500, off=300):
self.widget = widget
...
def delay_show(self, ...):
self.widget.after(ms, var.set, message)
self.widget.update_idletasks()
Then, whenever you create an instance of FlashMessage
you need to add a widget as the first parameter.
For example, assuming that count_frame
is defined in the context where you create an instance of FlashMessage
and it is an actual widget, it might look something like this:
if self.old_windows_cnt == new_windows_cnt :
FlashMessage (count_frame, self.label_this, "No new windows to remove...", \
3, 750, 250)
self.update_cnt_labels()
return
Upvotes: 1