How to hook your ViewerParcel into Chandler
This tutorial is out of date. We will start on a new one around 15 December. Sorry!
Chandler will connect your ViewerParcel up seamlessly, but only if you give things names such that it knows where to look. (
Also note that this API will change, so don't get too attached to it.)
ViewerParcels use a modified Model-View-Controller architecture, where the Model is a subclass of ViewerParcel and the View is a subclass of wxViewerParcel. (The Chandler View also often has elements of the Controller, so it's not a perfect example of Model-View-Controller.)
If you want to make a "foo" ViewerParcel, the easiest thing to do is to follow this recipe:
1. Make a home
Create the directory
osaf/chandler/Chandler/parcels/foo
Starting with the 15 July 2003 snapshot, you should create two layers of directory -- one for all your parcels and one for this specific parcel, e.g.
osaf/chandler/Chandler/parcels/MabelGarcia and
osaf/chandler/Chandler/parcels/MabelGarcia/foo. The extra directory will help avoid namespace collisions.
Starting on about 20 July 2003, you can also keep your parcel outside of the Chandler tree. (This is useful if you want to avoid moving around parcel directory when you download multiple versions of the Chandler code.) See
ParcelLoading if you want to do that; the rest of this tutorial will assume that you put your parcel into an appropriate subdirectory of
osaf/chandler/Chandler/parcels/
2. Go home
Move to the directory you just created, e.g.
cd osaf/chandler/Chandler/parcels/foo
or
cd osaf/chandler/Chandler/parcels/MabelGarcia/foo
3. Create files
You need to create the files
__init__.py
Foo.py
Foo.xrc
(Note that the wiki italicizes words wrapped in underscores, so in the rest of this page, I will call the first file "the init file".)
Note that you
must use the same stem (in this case, "Foo") for both the file with the model (Foo.py) and the XRC file (Foo.xrc).
3.1 Init file
In the init file, insert a line
parcelClass = "Foo.FooModel"
This tells Chandler's application to look for the class "FooModel" in the file "Foo.py".
3.2 Foo.py
In
Foo.py, you need to import some classes and create two new classes
- FooModel as a subclass of ViewerParcel. This is the "Model" in the "Model-View-Controller" way of looking at the universe.
- wxFooViewer as a subclass of wxViewerParcel. This is sort of a combination of the "View" and the "Controller" in the "Model-View-Controller" way of looking at the universe.
3.2.1 Import classes
You need to import a classes from the Chandler application framework. At the beginning of
Foo.py, make sure you have these lines:
from application.Application import app
from application.ViewerParcel import *
3.2.2 FooModel class
The
FooModel class holds the Model, the data. Chandler will automatically store any data in class
FooModel in an object store.
(Note that there are two object stores: the one that holds the model's information and another that is the Chandler Respository. The Chandler Repository might live on a remote computer, but the model data store needs to be local. If the network goes down, you want to still be able to make your UI work.)
In
FooModel's
__init__
method, there needs to be a line:
ViewerParcel.__init__(self)
3.3.2.1
There are two ways to set the name of your ViewerParcel in the
SidebarSpec. The easiest one, is to add a line to
init that sets the displayName:
self.displayName = _('Foo')
(The underscore and parentheses are for internationalization, which is discussed in
the internationalization section.)
The other way to set the
displayName is with a label in the XRC file, which we'll show
later.
3.2.3 wxFooViewer class
The
wxFooViewer class handles the user interface interaction. In the method
OnInit, its initialization routine, you need to connect your event handlers to all the events that could happen as a result of user actions. (The event handlers are other methods in the
wxFooViewer class.)
HookingUpEvents shows how to do the event wiring.
WxWindows developers, note that wxFooViewer is a subclass of wxPanel, so this is where you plug in your UI elements.
3.3 Foo.xrc
Foo.xrc is an
XRC file. XRC is an XML-based language for describing the layout of a window. (If you are unfamiliar with XRC files see the
section on building XRC files.)
There are two constraints that are special about using XRC with Chandler.
3.3.1 wxPanel subclass and name
The top-level object must look like this:
<object class="wxPanel" subclass="parcels.foo.Foo.wxFooViewer" name="FooViewer">
3.3.2 wxMenu name and label
If you want your ViewerParcel to have menu items, in the XRC file, the menu must have the name of "ViewerParcelMenu", as in this example:
...
<object class="wxMenu" name="ViewerParcelMenu">
<label>Foo Parcel</label>
<object class="wxMenuItem" name="FirstFooMenuItem">
<label>First Foo</label>
</object>
</object>
...
The
subclass attribute tells Chandler where to find the event handlers -- in directory
parcels/foo, file
Foo, class
wxFooViewer.
3.3.2.1
As mentioned
earlier, you can set the "display name" of the parcel in the XRC file. To do so, give the ViewerParcelMenu a label:
...
<object class="wxMenu" name="ViewerParcelMenu">
<label>Foo Parcel</label>
...
Chandler will use this label as the "diplay name" - the name of this parcel in the
SidebarSpec.
5. Get ready to troubleshoot
Go read
TroubleShooting?. It will help you figure out why things aren't working if they don't work on the first try.
Example
Here is the skeleton of the Foo ViewerParcel so far:
| file |
source |
__init__.py |
parcelClass = "Foo.FooModel"
|
|
Foo.py |
from application.Application import app
from application.ViewerParcel import *
class FooModel(ViewerParcel):
def __init__(self):
ViewerParcel.__init__(self)
self.displayName = _('FooParcel')
... more ...
class wxFooViewer(wxViewerParcel):
def OnInit(self):
EVT_MENU(self, XRCID('FirstFooMenuItem'), self.OnFirstFoo)
def OnFirstFoo(self, event):
do something
|
| Foo.xrc |
<?xml version="1.0" encoding="ISO-8859-1"?>
<resource version="2.4.0.0">
<object class="wxPanel" subclass="parcels.foo.Foo.wxFooViewer" name="Foo">
</object>
<object class="wxMenu" name="ViewerParcelMenu">
<object class="wxMenuItem" name="FirstFooMenuItem">
<label>First Foo</label>
</object>
</object>
</resource>
|
You can also download example files:
--
DuckySherwood - 12 May 2003
Find some place for this snippet of John's:
Sometime it's useful to have a place for data that is associated with a
ViewerParcel?, but can't be persisted, e.g. an open file handle. In the past this was hard to do because the wxViewerParcel's were destroyed and reconstructed each time they were viewed. So, now, if you implement
OnInitData?(self) in your wxViewerParcel, you'll get called the first time your parcel is viewed and a dictionary, named "data" (accessed like self.data) is available for you to store anything you want. Even if your wxViewerParcel is created and destroyed, it will be guaranteed to contain your data.
--
DuckySherwood - 12 May 2003
Note - To get this example to work, I needed to change line 7 of Foo.py to:
self.displayName = _('Foo')
Otherwise, was very helpful, thanks!
--
DietrichAyala 22 May 2003