Python 2.7 - How do I use an Observer in a Tkinter GUI, where you switch between frames? Python 2.7 - How do I use an Observer in a Tkinter GUI, where you switch between frames? tkinter tkinter

Python 2.7 - How do I use an Observer in a Tkinter GUI, where you switch between frames?


Since I wasn't able to implement an Observer to watch widgets like the ttk.Combobox, I've decided to create a workaround. Here are the steps I took, in order to achieve a MVC architecture from Bryan Oakleys example (link is in the question), which refreshes its model class via the controller class, whenever a user takes an action in the view (GUI).

Step 1: Add a model class

First, in order to use a MVC architecture, we have to seperate the code into model, view and control. In this example, model is class Model:, control is class PageControl(tk.Tk): and view are the pages class StartPage(tk.Frame), PageOne(tk.Frame) and PageTwo(tk.Frame).

Step 2: Set up your model class

Now we have to decide on which variables we want to have in the model class. In this example, we have directories and keys (status of the comboboxes), which we want to save in dictionaries. After setting them up empty, all we have to do is add setters and getters for each variable, so we can refresh data in model and also retrieve some, if we want. Additionally, we could implement delet methods for each variable, if we wanted to.

Step 3: Add push and pull methods to the control class

Now that there is a model class, we can refrence it via e. g. self.model = Model() in PageControl(tk.Tk) (control). Now we have the basic tools to set data in Model via e. g. self.model.set_keys(self.shared_keys) and also get data from Model. Since we want our control class to do that, we need some methods, that can achieve this. So we add the push and pull methods to the PageControl (e. g. def push_key(self)), which in turn can be refrenced from view (StartPage, PageOne, PageTwo) via controller.

Step 4: Add your widgets to the view class

Now we have to decide on which widgets shall be on which page and what you want them to do. In this example, there are buttons for navigation, which for the sake of the task can be ignored, two comboboxes and a button, which opens a file dialog.

Here, we want the comboboxes to refresh their status whenever it is changed and send the new status via controller to the model. Whereas the Open button of PageOne shall open a file dialog, where the user then selects files he/she wants to open. The directories we got from this interaction then shall be send via controller to model.

Step 5: Get all your functionality into the controller class

Since there is a controller variable, we can use it to refrence methods, which are in the controller class. This way, we can outsource all our methods from the pages into the controller and reference them via self.controller.function_of_controller_class. But we have to be aware, that methods, which are bound to commands via lambda: can't return any values, but they are also not called on programme startup. So keep that in mind.

Step 6: Set up your bindings and wrappers

Here we have to set up the .bind() for our comboboxes. Since the controller allready is set up to store data and the comboboxes have a textvariable, we can use this to gather information about the status of the comboboxes via combobox.bind(<<ComboboxSelect>>). All we have to do is to set up a wrapper which is called, whenever combobox.bind(<<ComboboxSelect>>) is throwing an event.

Closing statement

Now we have it, a programme based on Bryan Oakleys example of "How to get variable data from a class", which utilises a model, which is updated via controller whenever the user takes a corresponding action in the view. Unfortunately it doesn't utilise a Observer class, as first intended, but I'll keep working on it and update this, when I've found a satisfying solution.