Here are some examples:
Type 1:
#!/bin/sh
OPENEV_HOME=`dirname $0`/..
# Setup Environment Variables for OpenEV
PYTHONHOME=${OPENEV_HOME}
PYTHONPATH=${OPENEV_HOME}/pymod:${PYTHONPATH}
GEOTIFF_CSV=${OPENEV_HOME}/share/gdal
LD_LIBRARY_PATH=${OPENEV_HOME}/lib:${LD_LIBRARY_PATH}
PATH=${OPENEV_HOME}/bin:${PATH}
# check for accelerated hardware flag
if [ "${1}" = "-h" ]; then
shift
echo "Setup for user installed hardware acceleration"
else
echo "Default software rendering mode (use -h if accelerated video card installed)."
LD_LIBRARY_PATH=${OPENEV_HOME}/lib/Mesa:${LD_LIBRARY_PATH}
fi
export PYTHONHOME PYTHONPATH LD_LIBRARY_PATH PATH OPENEV_HOME GEOTIFF_CSV
# Run OpenEV
${OPENEV_HOME}/pymod/openev.py "$@"
This one will run without requiring a setup script to be sourced,
because it sets all the environment variables it needs. This is
the type of script included in Frank Warmerdam's ftp site distributions.
Type 2:
#!/bin/sh
${PYTHONHOME}/bin/python ${OPENEVHOME}/pymod/openev.py $*
This type assumes that a setup script (eg. .cshrc) has set all the necessary
variables, and simply launches OpenEV.
import gviewapp
import gview
import gtk
import sys
import os
import getopt
if __name__ == '__main__':
# get command line options and args
# openev -m menufile -i iconfile -t toolfile image1 image2 ......
(options, ifiles) = getopt.getopt(sys.argv[1:], 'm:i:t:p:')
if os.path.isdir(os.path.join(gview.home_dir, 'config')):
mfile = os.path.join(gview.home_dir, 'config', 'DefaultMenuFile.xml')
ifile = os.path.join(gview.home_dir, 'config', 'DefaultIconFile.xml')
pfile = os.path.join(gview.home_dir, 'config', 'DefaultPyshellFile.xml')
else:
mfile=None
ifile=None
pfile=None
tfile = None
for opt in options[0:]:
if opt[0] == '-m':
mfile=opt[1]
elif opt[0] == '-i':
ifile=opt[1]
elif opt[0] == '-p':
pfile=opt[1]
elif opt[0] == '-t':
tfile=opt[1]
app = gviewapp.GViewApp(toolfile=tfile,menufile=mfile,iconfile=ifile,pyshellfile=pfile)
gview.app = app # handle to the application for other modules to use
app.subscribe('quit',gtk.mainquit) # connect to gtk's quit mechanism
app.show_layerdlg() # show layer dialog
app.new_view(None) # create initial view window
app.do_auto_imports() # imports modules specified in preferences
for item in ifiles:
app.file_open_by_name(item) # open command line files
gtk.mainloop() # start the main event loop
class GvPoiTool(GvTool):
"""Point of Interest Selection Tool
Signals:
poi-changed -- generated when the POI has been changed.
"""
get_type = _gv.gv_poi_tool_get_type
def __init__(self, _obj=None):
if _obj: self._o = _obj; return
self._o = _gv.gv_poi_tool_new()
def get_point(self):
""" Returns the current POI """
return _gv.gv_poi_tool_get_point(self._o)
def set_point(self, point):
""" Sets the current POI.
point -- a tuple (column, row)
"""
return _gv.gv_poi_tool_new_point(self._o, point)
It inherits from the GvTool class:
class GvTool(_gtk.GtkObject):
get_type = _gv.gv_tool_get_type
def __init__(self, _obj=None):
if _obj: self._o = _obj; return
def activate(self, view):
_gv.gv_tool_activate(self._o, view._o)
def deactivate(self, view):
_gv.gv_tool_deactivate(self._o, view._o)
def get_view(self):
v_o = _gv.gv_tool_get_view(self._o)
if v_o is None:
return None
else:
return GvViewArea(_obj=v_o)
def set_boundary(self, boundary):
"""Set constraint rectangle.
boundary -- boundary is a tuple in the form (column,row,width,height)
"""
return _gv.gv_tool_set_boundary(self._o, boundary)
You can connect to the POI tool's poi-changed signal using the connect
function:
class my_object:
def __init__(self):
# The poi tool is stored in the main application's toolbar:
# Get a handle to the main application through gview (gview.app
# is set to the main application in openev.py). This makes
# use of the fact that every module is only loaded once in
# an application, unless the "reload" command is called
# on the module. All subsequent imports point to the same
# space in memory. This means that setting gview.app in
# openev.py results in app being accessible wherever gview is
# loaded.
# The application is sometimes passed as an argument
# to make it less confusing in OpenEV's tools, but the
# end effect is the same.
import gview
gview.app.toolbar.poi_tool.connect('poi-changed',self.my_update_cb)
def my_update_cb(self,*args)
poi_info = self.app.toolbar.get_poi()
txt=str(poi_info[0])+' '+str(poi_info[1])
This connects the poi tool's "poi-changed" signal to your object's
"my_update_cb" callback. Note that the poi tool's "connect" function
is inherited from gtk.GtkObject through the GvTool base class.
The top-level application is the GViewApp class in gviewapp.py. It does not have its own gui, but initializes the layer dialog, view manager, selection manager, toolbar, tools, and preferences. The first view window is launched through a call to the GViewApp's "new_view" function, which creates a new GvViewWindow and adds tool menu entries to it. gviewapp.py also contains the code for the edit toolbar and preference dialog GUIs.
gvviewwindow.py contains the code to create an OpenEV view. This consists of a GtkWindow with an embedded menubar, icon bar, and GvViewArea (the black area- see gview.py for the wrappers, gvviewarea.c for the nitty-gritty).
Other python files that provide GUIs include layerdlg.py (the layer dialog), oeattedit.py (the vector attributes dialog launched from the edit menu), gvvectorpropdlg.py (the vector properties dialog launched by right clicking on a vector file in the layer dialog), and gvrasterpropdlg.py (the raster properties dialog).
"""
MODULE
gvsignaler
DESCRIPTION
Provides an event subscription/notification mechanism a bit like
Gtk signal handling. Classes which derive from Signaler can
publish a list of named signals. These signals can then be
attached to arbitrary callback methods/functions using subscribe().
More than one callback function per signal can be attached.
The Signaler executes the callback functions with the notify()
method.
Arguments to the callback functions are (in order):
1. The Signaler instance.
2. Any signal specific arguments provided to notify().
3. Subscriber baggage arguments provided to subscribe().
The baggage arguments act like the 'data' argument of Gtk signals.
"""
class UnpublishedSignalError(Exception): pass
class SignalExistsError(Exception): pass
class Signaler:
"Base class for objects with published signals"
signal = {} # Prevents AttributeErrors
def publish(self, *sigs):
"Publish one or more named signals"
if not self.__dict__.has_key('signal'):
self.signal = {}
for s in sigs:
if self.signal.has_key(s):
raise SignalExistsError
self.signal[s] = [0, []] # Blocked flag, handlers list
def subscribe(self, name, meth, *args):
"Attach a callback function/method to a signal"
try:
self.signal[name][1].append((meth, args))
except KeyError:
raise UnpublishedSignalError
def unsubscribe(self, name, meth):
"Remove a callback function/method for a named signal"
try:
l = len(self.signal[name][1])
for si in range(l):
if self.signal[name][1][si][0] == meth:
del self.signal[name][1][si]
break
except KeyError:
raise UnpublishedSignalError
def notify(self, name, *args):
"Execute callbacks attached to the named signal"
try:
sig = self.signal[name]
except KeyError:
raise UnpublishedSignalError
# Check for blocked signal
if sig[0] == 0:
for s in sig[1]:
apply(s[0], (self,) + args + s[1])
def block(self, name):
"Prevent a signal from being emitted"
try:
self.signal[name][0] = 1
except KeyError:
raise UnpublishedSignalError
def unblock(self, name):
"Allows a blocked signal to be emitted"
try:
self.signal[name][0] = 0
except KeyError:
raise UnpublishedSignalError
An object of this class stores a dictionary of signals that it will recognize.
A new signal is added to the dictionary using the "publish" function, and
the signal is emitted using the "notify" function. Another object can
connect to this signal using the "subscribe" function, which appends the
desired callback (passed through the subscribe arguments) to the list of
callbacks for that signal. "notify" cycles through all attached callbacks
for a given signal, applying them. The block/unblock functions are used
to temporarily prevent the callbacks from being executed. This is similar
to the gtk signaling mechanism, with the difference that the gtk signals
are defined at the c-level, and are emitted and connected to through
python wrappers. The gtk mechanism uses the terms "connect" and "emit"
rather than "subscribe" and "notify". Some objects inherit both mechanisms,
for example the Layer Dialog class:
class LayerDlg(GtkWindow,gvsignaler.Signaler):
def __init__(self):
GtkWindow.__init__(self)
self.set_title('Layers')
self.set_usize(250, 500)
self.set_border_width(3)
self.set_policy(TRUE,TRUE,FALSE)
self.connect('delete-event',self.close)
shell = GtkVBox(spacing=3)
self.add(shell)
# Bunch of other code...
# Layer list
layerbox = GtkScrolledWindow()
shell.pack_start(layerbox)
if self.thumbnail:
layerlist = GtkCList(cols=3)
else:
layerlist = GtkCList(cols=2)
layerbox.add_with_viewport(layerlist)
layerlist.set_shadow_type(SHADOW_NONE)
layerlist.set_selection_mode(SELECTION_SINGLE)
layerlist.set_row_height(THUMB_H + 4)
layerlist.set_column_width(0, EYE_W)
if self.thumbnail:
layerlist.set_column_width(1, THUMB_W + 4)
layerlist.connect('select-row', self.layer_selected)
layerlist.connect('button-press-event', self.list_clicked)
# Bunch of other code...
# Publish signals
self.publish('active-view-changed')
In this case, 'delete-event' is a gtk signal (the little x on the
layer dialog box being clicked), as are 'select-row' and
'button-press-event', but 'active-view-changed' is
a Signaler signal.
As a historical note, the GViewApp class used to be in openev.py, then was separated out to its own gviewapp.py file.