tkinter Model-View-Controller: deeply-nested widgets calling the controller - python

I'm refactoring a tkinter GUI along a MVC design pattern. The Controller module imports a View class, and the View class makes requests to the Controller. I have a few ways of registering a change to an entry widget (StringVar trace, binding, etc.), but what if the widget is deeply nested and the callback is at a much higher level? What is the best way to have a request propagate upwards? For example, what if the View has a Frame that has a Frame that has a Widget that changes status?
The two solutions that occur to me are:
Russian Doll approach: Every inner layer is instantiated with either a reference to the View or the Controller, so the widget can directly make a request (e.g. to ViewReference.call_controller(input), or ControllerAlias.request(input). This leaves a trail of breadcrumbs from View to widget.
Family Tree approach: recursively call the parents and ask if they have an "ask controller to do thing" method. If not, ask their parents. This seems more fragile and awkward.

Related

what are some of the things within this tkinter program? [duplicate]

I want to understand what the below code means:
class PageOne(tk.Frame):
def __init__(self, parent, controller):
What are self, parent and controller? What is the role and scope of these tools here?
I believe self is similar to this in Java, but what's the use of parent and controller?
Later in the code flow I can see:
button1 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
There is a function already defined called show_frame, but why is the controller being used to call this function?
Roughly speaking, the original code1 attempted to use a pseudo-MVC (model, view and controller) architecture. Though without the "model" part -- there was just a "view" (some frames) and a "controller" (the main application). Hence, the reference to a controller object. The original code was actually written to show how to "stack" frames, so it's MVC implementation is very shallow and under-documented since that wasn't the point of the example.
To answer your specific questions:
self represents the current object. This is a common first parameter for any method of a class. As you suggested, it's similar to Java's this.
parent represents a widget to act as the parent of the current object. All widgets in tkinter except the root window require a parent (sometimes also called a master)
controller represents some other object that is designed to act as a common point of interaction for several pages of widgets. It is an attempt to decouple the pages. That is to say, each page doesn't need to know about the other pages. If it wants to interact with another page, such as causing it to be visible, it can ask the controller to make it visible.
You asked "There is a function already defined called show_frame, but why is the controller being used to call this function?" Notice that show_frame is defined in a separate class, in this case the main program class. It is not defined in the other classes. For the other classes to be able to call it, they must call it on an instance of the main class. That instance is named controller in the context of these other classes.
1 Note: even though you likely found the original code in an online tutorial, it originally came from this stackoverflow answer: Switch between two frames in tkinter

What would these GUI elements represent in MVC terms?

I have a Listbox in tkinter in this Listbox. We can choose an image, all images are in a array in the model, but I don't known if the Listbox corresponds to MVC "View" or a "Controller", and if it's a Controller, how to add an image that we have just imported to it in accordance with MVC.
The Listboxor any other widget in tkinter is both part of the view and part of the controller, in the sense that it is a view (obviously) but it is also acting as a controller when you register callbacks in your code, and the widget catches relevant user interactions (events) and directs them to the registered code (with the help of tkinter event mainloop).
What you can do if you like, is to put your business code in a separated module (your model), make your tkinter registered callbacks call the functions in the model, and if the model changes because of that, update the widgets (the view) by notification, using the observer pattern (see a Python example) here. Essentially you keep a list of observers in the model, and when the model changes you'll call an update() or notify() method of them.
That will require you more work, which is a drawback in many cases, but has the power of updating your UI automatically anytime a change in the model affects some widget.
Note that I am not recommending all that work for simple cases (like using a few controls), unless you have good reasons for it. Wanting to use MVC looks like a desire to really separate concerns, but evaluate the effort first...

GUI: Vertical list of arbitrary elements with TkInter

Sorry if complete basic question. I'm doing my first steps with TkInter, trying to develop a GUI interface to a video library (I do have experience though with WPF/XAML, the MVVM paradigm, and to some extent with html/css).
I would like to have a horizontal list, scroll-able, of custom elements. Each element will have video data, including metadata (length, bitrate, etc.), a picture (thumbnail), and some action buttons (play, delete, mark, etc.). Ideally I also want to have dragging handle, to rearrange the order of the videos.
I'm looking, but cannot find, what should be the equivalent of element in WPF, with binding to data and templates. Is that even exist in Tk, or is it too ambitious requirement for a portable, free framework?
Even if templates don't exist in Tk, I still can manage by populating the parent control manually (e.g. similar to HTML's elements - each has many controls) - but I couldn't event find a list of arbitrary widgets.
Is two way binding exists (e.g. adding an item to the list of items, should automatically update the UI)?
Is Tk the right direction? The underlying logic is in python, so I'm looking for a python friendly solution. Iron Python with WPF would be the obvious solution, but I want to be portable, and Iron Python's current state isn't very promising, and I'm using libraries not supported by Iron Python.
The most common way to make a custom element is to subclass Frame. You can put whatever you want in that frame (image, buttons, etc), and then you can treat the whole thing as a single GUI element.
import Tkinter as tk
...
class CustomElement(tk.Frame):
def __init__(self, parent, meta, image_file, ...):
tk.Frame.__init__(self, parent)
# <create widgets for image, metadata, etc here>
You can then create a custom widget that acts as a container for these items. For example, you can use a canvas which makes it easy to line this objects up horizontally, and to which you can attach a scrollbar.
Finally, tkinter has a robust event management system that makes it possible to move things around with drag and drop. There isn't any built-in drag and drop per se, but you can create your own grab handles and custom bindings for click and release to implement it.
For an example of moving things on a canvas with the mouse, see this answer: https://stackoverflow.com/a/6789351/7432

Understanding parent and controller in Tkinter __init__

I want to understand what the below code means:
class PageOne(tk.Frame):
def __init__(self, parent, controller):
What are self, parent and controller? What is the role and scope of these tools here?
I believe self is similar to this in Java, but what's the use of parent and controller?
Later in the code flow I can see:
button1 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
There is a function already defined called show_frame, but why is the controller being used to call this function?
Roughly speaking, the original code1 attempted to use a pseudo-MVC (model, view and controller) architecture. Though without the "model" part -- there was just a "view" (some frames) and a "controller" (the main application). Hence, the reference to a controller object. The original code was actually written to show how to "stack" frames, so it's MVC implementation is very shallow and under-documented since that wasn't the point of the example.
To answer your specific questions:
self represents the current object. This is a common first parameter for any method of a class. As you suggested, it's similar to Java's this.
parent represents a widget to act as the parent of the current object. All widgets in tkinter except the root window require a parent (sometimes also called a master)
controller represents some other object that is designed to act as a common point of interaction for several pages of widgets. It is an attempt to decouple the pages. That is to say, each page doesn't need to know about the other pages. If it wants to interact with another page, such as causing it to be visible, it can ask the controller to make it visible.
You asked "There is a function already defined called show_frame, but why is the controller being used to call this function?" Notice that show_frame is defined in a separate class, in this case the main program class. It is not defined in the other classes. For the other classes to be able to call it, they must call it on an instance of the main class. That instance is named controller in the context of these other classes.
1 Note: even though you likely found the original code in an online tutorial, it originally came from this stackoverflow answer: Switch between two frames in tkinter

python widget creation using self on button

I was hoping some one could explain to me the difference and reason behind why I keep coming across two different methods for which people place buttons into the widget? I sometimes see
button = Button('Button', self)
or
self.spinner = QtGui.QSpinBox()
I just want to know whats the difference, is one more beneficial than the other? When to use which in what scenarios and why? Does the position of 'self' affect this in the widget some how?
Assuming you only care about PyQt and PySide…
There are two different places that self appears in your examples, which mean very different things.
First, as an argument to the constructor:
Every widget's constructor has a parent parameter, with a default value of None.
There are three reasons to leave out the parent:
You're going to assign the widget to a layout or other parent after creation.
You're creating a top-level window.
You're creating a special-purpose widget like QDesktopWidget.
If none of these are true, you need to pass a parent. If self is a widget, and the thing you're creating is a child of that widget, you will pass self as the parent.
Here's an example of the first alternative:
self.spinner = QtGui.QSpinBox()
hbox = Qt.QHBoxLayout()
hbox.addWidget(self.spinner)
self.addLayout(hbox)
We can't pass a parent to QSpinBox at construction time because its parent doesn't exist yet. So, we leave it off, and addWidget it to a layout object later.
This is all explained early in most tutorials for PySide or PyQt, like First programs in PySide and Layout management in PySide.
Meanwhile, one of your examples stores the widget in self.spinner, making it an instance attribute on self, which means we can refer to it later. For example, if some other method (like the signal handler for a button) wants to adjust the spinner's value, it can access it as self.spinner.
If you will never need to refer to the child widget in your code after the current function, you don't need to store it.
This part is explained in the Classes chapter in the Python tutorial.

Categories

Resources