Georg Brandl | 116aa62 | 2007-08-15 14:28:22 +0000 | [diff] [blame] | 1 | |
| 2 | :mod:`FrameWork` --- Interactive application framework |
| 3 | ====================================================== |
| 4 | |
| 5 | .. module:: FrameWork |
| 6 | :platform: Mac |
| 7 | :synopsis: Interactive application framework. |
| 8 | |
| 9 | |
| 10 | The :mod:`FrameWork` module contains classes that together provide a framework |
| 11 | for an interactive Macintosh application. The programmer builds an application |
| 12 | by creating subclasses that override various methods of the bases classes, |
| 13 | thereby implementing the functionality wanted. Overriding functionality can |
| 14 | often be done on various different levels, i.e. to handle clicks in a single |
| 15 | dialog window in a non-standard way it is not necessary to override the complete |
| 16 | event handling. |
| 17 | |
| 18 | Work on the :mod:`FrameWork` has pretty much stopped, now that :mod:`PyObjC` is |
| 19 | available for full Cocoa access from Python, and the documentation describes |
| 20 | only the most important functionality, and not in the most logical manner at |
| 21 | that. Examine the source or the examples for more details. The following are |
| 22 | some comments posted on the MacPython newsgroup about the strengths and |
| 23 | limitations of :mod:`FrameWork`: |
| 24 | |
| 25 | |
| 26 | .. epigraph:: |
| 27 | |
| 28 | The strong point of :mod:`FrameWork` is that it allows you to break into the |
| 29 | control-flow at many different places. :mod:`W`, for instance, uses a different |
| 30 | way to enable/disable menus and that plugs right in leaving the rest intact. |
| 31 | The weak points of :mod:`FrameWork` are that it has no abstract command |
| 32 | interface (but that shouldn't be difficult), that its dialog support is minimal |
| 33 | and that its control/toolbar support is non-existent. |
| 34 | |
| 35 | The :mod:`FrameWork` module defines the following functions: |
| 36 | |
| 37 | |
| 38 | .. function:: Application() |
| 39 | |
| 40 | An object representing the complete application. See below for a description of |
| 41 | the methods. The default :meth:`__init__` routine creates an empty window |
| 42 | dictionary and a menu bar with an apple menu. |
| 43 | |
| 44 | |
| 45 | .. function:: MenuBar() |
| 46 | |
| 47 | An object representing the menubar. This object is usually not created by the |
| 48 | user. |
| 49 | |
| 50 | |
| 51 | .. function:: Menu(bar, title[, after]) |
| 52 | |
| 53 | An object representing a menu. Upon creation you pass the ``MenuBar`` the menu |
| 54 | appears in, the *title* string and a position (1-based) *after* where the menu |
| 55 | should appear (default: at the end). |
| 56 | |
| 57 | |
| 58 | .. function:: MenuItem(menu, title[, shortcut, callback]) |
| 59 | |
| 60 | Create a menu item object. The arguments are the menu to create, the item title |
| 61 | string and optionally the keyboard shortcut and a callback routine. The callback |
| 62 | is called with the arguments menu-id, item number within menu (1-based), current |
| 63 | front window and the event record. |
| 64 | |
| 65 | Instead of a callable object the callback can also be a string. In this case |
| 66 | menu selection causes the lookup of a method in the topmost window and the |
| 67 | application. The method name is the callback string with ``'domenu_'`` |
| 68 | prepended. |
| 69 | |
| 70 | Calling the ``MenuBar`` :meth:`fixmenudimstate` method sets the correct dimming |
| 71 | for all menu items based on the current front window. |
| 72 | |
| 73 | |
| 74 | .. function:: Separator(menu) |
| 75 | |
| 76 | Add a separator to the end of a menu. |
| 77 | |
| 78 | |
| 79 | .. function:: SubMenu(menu, label) |
| 80 | |
| 81 | Create a submenu named *label* under menu *menu*. The menu object is returned. |
| 82 | |
| 83 | |
| 84 | .. function:: Window(parent) |
| 85 | |
| 86 | Creates a (modeless) window. *Parent* is the application object to which the |
| 87 | window belongs. The window is not displayed until later. |
| 88 | |
| 89 | |
| 90 | .. function:: DialogWindow(parent) |
| 91 | |
| 92 | Creates a modeless dialog window. |
| 93 | |
| 94 | |
| 95 | .. function:: windowbounds(width, height) |
| 96 | |
| 97 | Return a ``(left, top, right, bottom)`` tuple suitable for creation of a window |
| 98 | of given width and height. The window will be staggered with respect to previous |
| 99 | windows, and an attempt is made to keep the whole window on-screen. However, the |
| 100 | window will however always be the exact size given, so parts may be offscreen. |
| 101 | |
| 102 | |
| 103 | .. function:: setwatchcursor() |
| 104 | |
| 105 | Set the mouse cursor to a watch. |
| 106 | |
| 107 | |
| 108 | .. function:: setarrowcursor() |
| 109 | |
| 110 | Set the mouse cursor to an arrow. |
| 111 | |
| 112 | |
| 113 | .. _application-objects: |
| 114 | |
| 115 | Application Objects |
| 116 | ------------------- |
| 117 | |
| 118 | Application objects have the following methods, among others: |
| 119 | |
| 120 | |
| 121 | .. method:: Application.makeusermenus() |
| 122 | |
| 123 | Override this method if you need menus in your application. Append the menus to |
| 124 | the attribute :attr:`menubar`. |
| 125 | |
| 126 | |
| 127 | .. method:: Application.getabouttext() |
| 128 | |
| 129 | Override this method to return a text string describing your application. |
| 130 | Alternatively, override the :meth:`do_about` method for more elaborate "about" |
| 131 | messages. |
| 132 | |
| 133 | |
| 134 | .. method:: Application.mainloop([mask[, wait]]) |
| 135 | |
| 136 | This routine is the main event loop, call it to set your application rolling. |
| 137 | *Mask* is the mask of events you want to handle, *wait* is the number of ticks |
| 138 | you want to leave to other concurrent application (default 0, which is probably |
| 139 | not a good idea). While raising *self* to exit the mainloop is still supported |
| 140 | it is not recommended: call ``self._quit()`` instead. |
| 141 | |
| 142 | The event loop is split into many small parts, each of which can be overridden. |
| 143 | The default methods take care of dispatching events to windows and dialogs, |
| 144 | handling drags and resizes, Apple Events, events for non-FrameWork windows, etc. |
| 145 | |
| 146 | In general, all event handlers should return ``1`` if the event is fully handled |
| 147 | and ``0`` otherwise (because the front window was not a FrameWork window, for |
| 148 | instance). This is needed so that update events and such can be passed on to |
| 149 | other windows like the Sioux console window. Calling :func:`MacOS.HandleEvent` |
| 150 | is not allowed within *our_dispatch* or its callees, since this may result in an |
| 151 | infinite loop if the code is called through the Python inner-loop event handler. |
| 152 | |
| 153 | |
| 154 | .. method:: Application.asyncevents(onoff) |
| 155 | |
| 156 | Call this method with a nonzero parameter to enable asynchronous event handling. |
| 157 | This will tell the inner interpreter loop to call the application event handler |
| 158 | *async_dispatch* whenever events are available. This will cause FrameWork window |
| 159 | updates and the user interface to remain working during long computations, but |
| 160 | will slow the interpreter down and may cause surprising results in non-reentrant |
| 161 | code (such as FrameWork itself). By default *async_dispatch* will immediately |
| 162 | call *our_dispatch* but you may override this to handle only certain events |
| 163 | asynchronously. Events you do not handle will be passed to Sioux and such. |
| 164 | |
| 165 | The old on/off value is returned. |
| 166 | |
| 167 | |
| 168 | .. method:: Application._quit() |
| 169 | |
| 170 | Terminate the running :meth:`mainloop` call at the next convenient moment. |
| 171 | |
| 172 | |
| 173 | .. method:: Application.do_char(c, event) |
| 174 | |
| 175 | The user typed character *c*. The complete details of the event can be found in |
| 176 | the *event* structure. This method can also be provided in a ``Window`` object, |
| 177 | which overrides the application-wide handler if the window is frontmost. |
| 178 | |
| 179 | |
| 180 | .. method:: Application.do_dialogevent(event) |
| 181 | |
| 182 | Called early in the event loop to handle modeless dialog events. The default |
| 183 | method simply dispatches the event to the relevant dialog (not through the |
| 184 | ``DialogWindow`` object involved). Override if you need special handling of |
| 185 | dialog events (keyboard shortcuts, etc). |
| 186 | |
| 187 | |
| 188 | .. method:: Application.idle(event) |
| 189 | |
| 190 | Called by the main event loop when no events are available. The null-event is |
| 191 | passed (so you can look at mouse position, etc). |
| 192 | |
| 193 | |
| 194 | .. _window-objects: |
| 195 | |
| 196 | Window Objects |
| 197 | -------------- |
| 198 | |
| 199 | Window objects have the following methods, among others: |
| 200 | |
| 201 | |
| 202 | .. method:: Window.open() |
| 203 | |
| 204 | Override this method to open a window. Store the MacOS window-id in |
| 205 | :attr:`self.wid` and call the :meth:`do_postopen` method to register the window |
| 206 | with the parent application. |
| 207 | |
| 208 | |
| 209 | .. method:: Window.close() |
| 210 | |
| 211 | Override this method to do any special processing on window close. Call the |
| 212 | :meth:`do_postclose` method to cleanup the parent state. |
| 213 | |
| 214 | |
| 215 | .. method:: Window.do_postresize(width, height, macoswindowid) |
| 216 | |
| 217 | Called after the window is resized. Override if more needs to be done than |
| 218 | calling ``InvalRect``. |
| 219 | |
| 220 | |
| 221 | .. method:: Window.do_contentclick(local, modifiers, event) |
| 222 | |
| 223 | The user clicked in the content part of a window. The arguments are the |
| 224 | coordinates (window-relative), the key modifiers and the raw event. |
| 225 | |
| 226 | |
| 227 | .. method:: Window.do_update(macoswindowid, event) |
| 228 | |
| 229 | An update event for the window was received. Redraw the window. |
| 230 | |
| 231 | |
| 232 | .. method:: Window.do_activate(activate, event) |
| 233 | |
| 234 | The window was activated (``activate == 1``) or deactivated (``activate == 0``). |
| 235 | Handle things like focus highlighting, etc. |
| 236 | |
| 237 | |
| 238 | .. _controlswindow-object: |
| 239 | |
| 240 | ControlsWindow Object |
| 241 | --------------------- |
| 242 | |
| 243 | ControlsWindow objects have the following methods besides those of ``Window`` |
| 244 | objects: |
| 245 | |
| 246 | |
| 247 | .. method:: ControlsWindow.do_controlhit(window, control, pcode, event) |
| 248 | |
| 249 | Part *pcode* of control *control* was hit by the user. Tracking and such has |
| 250 | already been taken care of. |
| 251 | |
| 252 | |
| 253 | .. _scrolledwindow-object: |
| 254 | |
| 255 | ScrolledWindow Object |
| 256 | --------------------- |
| 257 | |
| 258 | ScrolledWindow objects are ControlsWindow objects with the following extra |
| 259 | methods: |
| 260 | |
| 261 | |
| 262 | .. method:: ScrolledWindow.scrollbars([wantx[, wanty]]) |
| 263 | |
| 264 | Create (or destroy) horizontal and vertical scrollbars. The arguments specify |
| 265 | which you want (default: both). The scrollbars always have minimum ``0`` and |
| 266 | maximum ``32767``. |
| 267 | |
| 268 | |
| 269 | .. method:: ScrolledWindow.getscrollbarvalues() |
| 270 | |
| 271 | You must supply this method. It should return a tuple ``(x, y)`` giving the |
| 272 | current position of the scrollbars (between ``0`` and ``32767``). You can return |
| 273 | ``None`` for either to indicate the whole document is visible in that direction. |
| 274 | |
| 275 | |
| 276 | .. method:: ScrolledWindow.updatescrollbars() |
| 277 | |
| 278 | Call this method when the document has changed. It will call |
| 279 | :meth:`getscrollbarvalues` and update the scrollbars. |
| 280 | |
| 281 | |
| 282 | .. method:: ScrolledWindow.scrollbar_callback(which, what, value) |
| 283 | |
| 284 | Supplied by you and called after user interaction. *which* will be ``'x'`` or |
| 285 | ``'y'``, *what* will be ``'-'``, ``'--'``, ``'set'``, ``'++'`` or ``'+'``. For |
| 286 | ``'set'``, *value* will contain the new scrollbar position. |
| 287 | |
| 288 | |
| 289 | .. method:: ScrolledWindow.scalebarvalues(absmin, absmax, curmin, curmax) |
| 290 | |
| 291 | Auxiliary method to help you calculate values to return from |
| 292 | :meth:`getscrollbarvalues`. You pass document minimum and maximum value and |
| 293 | topmost (leftmost) and bottommost (rightmost) visible values and it returns the |
| 294 | correct number or ``None``. |
| 295 | |
| 296 | |
| 297 | .. method:: ScrolledWindow.do_activate(onoff, event) |
| 298 | |
| 299 | Takes care of dimming/highlighting scrollbars when a window becomes frontmost. |
| 300 | If you override this method, call this one at the end of your method. |
| 301 | |
| 302 | |
| 303 | .. method:: ScrolledWindow.do_postresize(width, height, window) |
| 304 | |
| 305 | Moves scrollbars to the correct position. Call this method initially if you |
| 306 | override it. |
| 307 | |
| 308 | |
| 309 | .. method:: ScrolledWindow.do_controlhit(window, control, pcode, event) |
| 310 | |
| 311 | Handles scrollbar interaction. If you override it call this method first, a |
| 312 | nonzero return value indicates the hit was in the scrollbars and has been |
| 313 | handled. |
| 314 | |
| 315 | |
| 316 | .. _dialogwindow-objects: |
| 317 | |
| 318 | DialogWindow Objects |
| 319 | -------------------- |
| 320 | |
| 321 | DialogWindow objects have the following methods besides those of ``Window`` |
| 322 | objects: |
| 323 | |
| 324 | |
| 325 | .. method:: DialogWindow.open(resid) |
| 326 | |
| 327 | Create the dialog window, from the DLOG resource with id *resid*. The dialog |
| 328 | object is stored in :attr:`self.wid`. |
| 329 | |
| 330 | |
| 331 | .. method:: DialogWindow.do_itemhit(item, event) |
| 332 | |
| 333 | Item number *item* was hit. You are responsible for redrawing toggle buttons, |
| 334 | etc. |
| 335 | |