1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
|
===================
Pyface Applications
===================
.. py:currentmodule:: pyface.application
Pyface provides a collection of classes suitable for representing an
application. Although the classes are principally designed to work with
GUI-based applications, the base class :py:class:`Application` class does not
and so can be used as the basis for command-line or server applications with
a shared codebase with a GUI application.
Additionally, the application classes are designed to be forward-compatible
with Envisage application classes so applications developed using this
framework can easily be refactored to take advantage of the Envisage's plug-in
extensibility if that should be required.
Application Interface
=====================
The core of the :py:class:`Application` class' API are three methods:
:py:meth:`Application.run`, :py:meth:`Application.start`, and
:py:meth:`Application.stop`. The :py:meth:`Application.run` method is the
entry-point of the application, and performs the following steps:
1. calls the :py:meth:`Application.start` method to initialize the
application's state.
2. if the start is successful, calls an internal :py:meth:`Application._run`
method which does the actual work (such as running the GUI event loop).
3. when the :py:meth:`Application._run` method returns, calls
:py:meth:`Application.stop` to release any resources used by the application
and de-initialize as needed.
Subclasses of the base :py:class:`Application` class will likely override all
three of these methods, but :py:class:`pyface.gui_application.GUIApplication`
subclasses may be able to avoid having to touch them, depending on what
addition resources they need to access.
In addition to these three methods, there is an :py:meth:`Application.exit`
method that can be called by code that wants to halt the application at that
point. For the base class this simply raises an :py:class:``ApplicationExit``
exception, but for event loop based classes it may instead call appropriate
toolkit code to close open windows and stop the application event loop.
During this life-cycle, the application will emit various Traits events
indicating the state that it is currently in. The sequence of events is
normally :py:attr:`Application.starting`, :py:attr:`Application.started`
:py:attr:`Application.application_initialized`,
:py:attr:`Application.stopping`, and :py:attr:`Application.stopped`
In addition to the core methods and events, the :py:class:`Application` class
has some traits for metadata about the application, primarily the
human-readable application name, a description of the application, and a
globally unique application id. The application also has traits holding
platform-dependent "home" and "user" directory paths, which by default are
provided by :py:mod:`traits.etsconfig` which give reasonable platform-dependent
results.
Application Example
-------------------
A simple command-line application might look something like this::
import argparse
from pyface.application import Application
from traits.api import Str
class HelloApplication(Application):
""" Simple application subclass that greets a location. """
#: The location being greeted.
location = Str("world")
def _run(self):
super()._run()
print("Hello "+self.location)
def main():
app = HelloApplication()
parser = argparse.ArgumentParser(description=app.description)
parser.add_argument('location', nargs='?', default=app.location,
help="the location to greet")
parser.parse_args(namespace=app)
app.run()
if __name__ == '__main__':
main()
GUIApplication Interface
========================
.. py:currentmodule:: pyface.gui_application
The :py:class:`GUIApplication` subclass is the base class to use for
Pyface-based GUI applications. This class invokes the Pyface toolkit's event
loop in the :py:meth:`GUIApplication._run` method, and stops it in the
:py:meth:`GUIApplication._exit` method.
The class has code that tracks application windows through their lifecycle.
The application has a list :py:attr:`GUIApplication.windows` of all known
windows. Windows can be added to the list with the
:py:meth:`GUIApplication.add_window` method which also handles opening the
window. Windows are automatically removed from the list when they are closed.
In addition the class has a :py:meth:`GUIApplication.create_window` method
which by default calls the :py:attr:`GUIApplication.window_factory` attribute
and handles setting titles, icons and sizing of the created windows. Windows
created by :py:meth:`GUIApplication.create_window` still need to be added to
the application's list of windows via :py:meth:`GUIApplication.add_window`.
The :py:meth:`GUIApplication.start` method of the class must ensure that there
is at least one open window by the point that the event loop starts,
particularly with the WxPython backend. The default
:py:meth:`GUIApplication.start` method calls
:py:meth:`GUIApplication._create_windows` to perform the initial set-up of open
windows. The default behaviour is to call the
:py:meth:`GUIApplication.create_windows` method and then add that window.
In most cases to use the base :py:class:`GUIApplication` class, you will want
to:
* create a subclass of :py:class:`~pyface.application_window.ApplicationWindow`
that at least overrides the
:py:meth:`~pyface.application_window.ApplicationWindow._create_contents`
method to create the desired user interface. Ideally this window should be
able to work without needing an application, as this helps with reusability.
* create a window factory function that taskes the application and arbitrary
other keyword arguments and creates an instance of the
:py:class:`~pyface.application_window.ApplicationWindow` subclass along with
any additional application-dependent state that is required. This can
include application-dependent menus, toolbars, etc. as well as other state
injected by from application.
While the :py:class:`GUIApplication` class can be used without subclassing, for
complex applications it is likely that the a subclass will need to be used,
and will likely override the :py:meth:`~GUIApplication.start`,
:py:meth:`~GUIApplication.stop` and :py:meth:`~GUIApplication.create_window`
methods to perform additional application-specific customization.
GUIApplication Example
----------------------
The following example shows how to build a simple but functional
:py:class:`GUIApplication` which provides an interactive Python shell. The
application has two parts: a
:py:class:`pyface.application_window.ApplicationWindow` subclass which is
responsible for creating the Python shell widget, and a window factory which
is responsible for creating the windows and populating the menu bar.
The application window subclass looks like this::
from pyface.api import ApplicationWindow, PythonShell
from traits.api import Instance
class PythonShellWindow(ApplicationWindow):
""" An application window that displays a simple Python shell. """
#: The title of the window.
title = "Python Shell"
#: The Python shell widget to use.
shell = Instance('pyface.i_python_shell.IPythonShell')
def _create_contents(self, parent):
""" Create the shell widget. """
self.shell = PythonShell(parent)
return self.shell.control
Note that we don't (and shouldn't) need the application to be available for
this class to work - it is a perfectly good stand-alone class that can
potentially be re-used in many different contexts.
While the GUI application window subclass looks like this::
from pyface.api import GUIApplication
from pyface.action.api import (
AboutAction, CloseWindowAction, CreateWindowAction, ExitAction, Group,
MenuBarManager, MenuManager
)
from python_shell_window import PythonShellWindow
def create_python_shell_window(application, **kwargs):
window = PythonShellWindow()
window.menu_bar_manager = MenuBarManager(
MenuManager(
Group(CreateWindowAction(application=application)),
Group(
CloseWindowAction(window=window),
ExitAction(application=application),
),
name='&File',
),
MenuManager(
AboutAction(application=application),
name='&Help',
)
)
return window
def main():
app = GUIApplication(
name="Python Shell",
description="An example application that provides a Python shell.",
icon='python_icon',
logo='python_logo',
window_factory=create_python_shell_window,
)
app.run()
if __name__ == '__main__':
main()
A more complete version of this can be found in the Pyface examples.
TasksApplication Interface
==========================
.. py:currentmodule:: pyface.tasks.tasks_application
The :py:class:`TasksApplication` class works in a similar way to the
:py:class:`~pyface.gui_application.GUIApplication` class, but instead of the
supplying a window factory, instead you provide one or more
:py:class:`TaskFactory` instances which provide information about the
different Tasks that are available for each window.
In addition the :py:class:`TasksApplication` has traits that hold extra
application-specific :py:class:`~pyface.actions.action.Action`s via the
:py:class:`~pyface.tasks.actions.schema_addition.SchemaAddition` mechanism,
and :py:class:`~pyface.tasks.dock_pane.DockPane` via factories for creating
the dock panes.
A complete :py:class:`TasksApplication` can be as simple as::
from pyface.tasks.api import TaskFactory, TasksApplication
from python_editor_task import PythonEditorTask
def main():
app = TasksApplication(
id="example_python_editor_application",
name="Python Editor",
description=(
"An example Tasks application that provides a Python editor."
),
icon='python_icon',
logo='python_logo',
task_factories=[
TaskFactory(
id='example.python_editor_task',
name="Python Editor",
factory=PythonEditorTask
)
],
)
# invoke the mainloop
app.run()
if __name__ == '__main__':
main()
A more complete version of this can be found in the Pyface examples.
|