WxPython: How should I organize the data for each widget in the controller?

I have a widget that displays the file system hierarchy for easy viewing (basically, a tree control and some toolbar buttons associated with it, such as "update"). Each of these widgets has a set of basic directories to display (recursively). Suppose a user can create instances of widgets that they find convenient. Please note that these widgets do not correspond to any business data - they are model independent.

Where should the set of basic directories (for each widget) be located in a good MVC design?

When the update button is pressed, the event is blocked by the controller, and the event contains the corresponding file system widget. The controller determines the base directories for this particular widget (in some way), goes through this directory path, and passes the widget some data for rendering.

Two places that I can remember for storing basic directories:

  • A simple solution: make the base directories of the instance variable in the widgets and ask the controller to manipulate it to save the state for this widget. However, there is a conceptual problem with this: since the widget never looks at this instance variable, you simply project one of the controller functions onto the widget.
  • A more complex solution (technically, possibly conceptually): keep the mapping {widget: base_directory_set} in the controller with weak key links.

The second method allows you to simplify the expansion of controller responsibilities later, because it makes sense to do things in the controller - for example, if I decided that later I wanted to define a set of all the basic directories for all these widgets.

Maybe there is some MVC knowledge that I'm missing that solves this problem well.

+4
source share
3 answers

The anomaly (in terms of MVC) that makes this design difficult to create MVC-compliant is that you want to display information that, in your concept, "does not live in the model." In MVC there is no such thing as “information that does not live in the model”: its conceptual root: “models contain all the information, the views simply perform presentation tasks, the controllers mediate user interaction.”

It is possible that the information you display does not "correspond to any business data", but (in the worldview of MVC) this means that it does not mean that the information is "model independent" "because there is no such thing - it simply means what do you need another class of model (besides what you use to store "business data") to store this "non-business data" !-)

So, when the user “creates a widget instance” (creates a catalog view, presumably by some user action on some main / coordinating view, possibly on another existing widget, if “cloning” is one way to create a widget instance ), the controller responsible for creating both the widget object and the instance of the "catalog display model class", and establishing the relationship between them (usually by setting a link to the corresponding model instance in the widget), as well as a model for the initial loading of information. When a user’s action in widgets implies an action on a model, the controller extracts a link to the model instance from the widget participating in the event and sends this instance to the appropriate requests (this is a model model that allows the view [s] interested in this to know about changes in information - usually , with the help of some observer pattern, this is definitely not a business controller for delivering information with information - this is really a very different approach from MVC!).

Does the cost of architectural investment correspond to MVC, in your case, compared to a tougher approach, when information flows are less pristine, and the model that should be there simply does not exist? I am a pragmatist, and I definitely do not worship the MVC altar, but I think that in this case (relatively small) investments in sound, a clear architecture can really extinguish itself in abundance. It’s about anticipating the likely directions of change — for example, what functionality that you don’t need right now (but may well get into the picture soon after) will be trivial if you go along the proper MVC route and be an ad hoc kludges nightmare otherwise (or require a somewhat painful reorganization of the entire architecture)? All kinds of possible things, from the desire to display the same catalog information in different widgets, to have a smarter model of viewing “catalog information”, which can be automatically updated as necessary (and provide new information directly to interested views using a regular observer template without involvement of the controller), are natural light and trivial with the MVC (hey, that MVC whole point, after all, so it's not surprising -!), kludgy and fragile with ad-hoc architecture corner at Lamy - a small investment, a large potential rewards, go for it!

You can see from the volume in the previous paragraph that I don’t worship the altar of “extreme programming” - as a pragmatist, I’ll do a bit of “design ahead” (especially from the point of view of inputting a clean, flexible, extensible architecture, from the very beginning, even if it’s not necessary now) - precisely because, in my experience, a little prudent and very modest investment, especially on the architectural facade, pays for itself many times over (in such various currencies as scalability, flexibility, expandability, maintainability awesomeness, security, etc., although not all of them will apply to all projects - for example, in your case, security and scalability are not really a concern ... but other aspects are likely to be! -).

Just for the sake of generality, let me note that this pragmatic attitude of mine does not justify the excessive energy and time spent on collecting architecture (by the definition of the word "excessive" ;-) - acquaintance with several fundamental architectural templates (and MVC is certainly one of them ) often reduce the initial investment in terms of time and effort - as soon as you understand that such a classic architecture will serve you well, because in this case it is very easy to see how to implement it (for example, reject the idea of ​​"MVC without M"!), and in fact, it does not take much more code compared to the most complex and fastest ad-hoccest shortcuts! -)

+2
source

Based on how the MVC methodology works, I suggest you move on with changing the first solution you proposed:

make the base directories of the instance variable in the widgets and force the controller to manipulate it in order to preserve the state for this widget.

Why? You stated that widgets are model independent, but in fact they refer to models? If you do not bind your widgets to your models, you deviate from the basic concept of MVC.

I have no knowledge of wxPython, so I can't talk about how it complies with MVC, if at all. It also seems to me that you should consider integrating the widget into models or treating them as models themselves.

So, assuming that in this context widgets are actually part of your model hierarchy, this may not be just a simple solution, as you said, but the right one.

Since one of the basic foundations of MVC maintains a loose connection between each part, you always want to isolate your business logic from data input and presentation. Saving widgets that are displayed separately from models breaks this, so using any information methods in your controller is not suitable. You want the model to contain everything you need to control or display the controller when presenting data in your views.

Have you considered creating a superclass for all widgets so that there is a common set of methods that they always inherit?

Example:

 import os WIDGET_PREFIX = '/tmp' class Widget: def __init__(self, name): self.name = name self.widget_prefix = WIDGET_PREFIX self.dirs = os.walk(os.path.join(self.widget_prefix, name)) def _get_base_directory_set(self): return self.dirs base_directory_set = property(_get_base_directory_set) 

Hope this at least gives you something to think about.

+1
source

The decision I just made is "controllers for each widget." (Perhaps an existing name exists for this.) It delegates a “parent” controller for any functions of the UI, but exists to manage widgets and link any relevant data based on each widget.

The widget controller concept allows you to avoid projecting any irrelevant properties onto the widget itself. You can expand these controllers to register / unregister managed widgets when creating / destroying those moments when you want to perform an operation with a large number of widgets, thereby avoiding weakref magic.

For instance:

 class FSBrowserController(wx.EvtHandler): """Widget-specific controller for filesystem browsers. :ivar parent: Parent controller -- useful when UI-wide control is necessary to respond to an event. """ def __init__(self, parent, frame, tree_ctrl, base_dirs): self.parent = parent self.frame = frame self.tree_ctrl = tree_ctrl self.base_dirs = base_dirs frame.Bind(EVT_FS_REFRESH, self.refresh) frame.Bind(wx.EVT_WINDOW_DESTROY, self._unregister) self.refresh() self._register() def _register(self): """Register self with parent controller.""" self.parent._fsb_controllers.append(self) def _unregister(self, event): """Unregister self with parent controller.""" if event.GetEventObject() == self.frame: self.parent._fsb_controllers.remove(self) def refresh(self, event=None): """Refresh the :ivar:`tree_ctrl` using :ivar:`base_dirs`.""" raise NotImplementedError class Controller(wx.EvtHandler): """Main controller for the application. Handles UI-wide behaviors. """ def __init__(self): self._fsb_controllers = [] fsb_frame = FSBrowserFrame(parent=None) FSBrowserController(self, fsb_frame, fsb_frame.tree_ctrl, initial_base_dirs) fsb_frame.Show() 

Thus, when the FSBrowserFrame is destroyed, the controller and its associated data will naturally disappear with it.

0
source

All Articles