| 1 | ============================ |
| 2 | wxPython 2.5 Migration Guide |
| 3 | ============================ |
| 4 | |
| 5 | This document will help explain some of the major changes in wxPython |
| 6 | 2.5 since the 2.4 series and let you know what you need to do to adapt |
| 7 | your programs to those changes. Be sure to also check in the CHANGES_ |
| 8 | file like usual to see info about the not so major changes and other |
| 9 | things that have been added to wxPython. |
| 10 | |
| 11 | .. _CHANGES: CHANGES.html |
| 12 | |
| 13 | |
| 14 | wxName Change |
| 15 | ------------- |
| 16 | |
| 17 | The **wxWindows** project and library is now known as |
| 18 | **wxWidgets**. Please see here_ for more details. |
| 19 | |
| 20 | .. _here: http://www.wxwidgets.org/name.htm |
| 21 | |
| 22 | This won't really affect wxPython all that much, other than the fact |
| 23 | that the wxwindows.org domain name has changed to wxwidgets.org, |
| 24 | so mail list, CVS, and etc. addresses have also changed. We're going |
| 25 | to try and smooth the transition as much as possible, but I wanted you |
| 26 | all to be aware of this change if you run into any issues. |
| 27 | |
| 28 | |
| 29 | |
| 30 | Module Initialization |
| 31 | --------------------- |
| 32 | |
| 33 | The import-startup-bootstrap process employed by wxPython was changed |
| 34 | such that wxWidgets and the underlying gui toolkit are **not** |
| 35 | initialized until the wx.App object is created (but before wx.App.OnInit |
| 36 | is called.) This was required because of some changes that were made |
| 37 | to the C++ wxApp class. |
| 38 | |
| 39 | There are both benefits and potential problems with this change. The |
| 40 | benefits are that you can import wxPython without requiring access to |
| 41 | a GUI (for checking version numbers, etc.) and that in a |
| 42 | multi-threaded environment the thread that creates the app object will |
| 43 | now be the GUI thread instead of the one that imports wxPython. Some |
| 44 | potential problems are that the C++ side of the "stock-objects" |
| 45 | (wx.BLUE_PEN, wx.TheColourDatabase, etc.) are not initialized until |
| 46 | the wx.App object is created, so you should not use them until after |
| 47 | you have created your wx.App object. If you do then an exception will |
| 48 | be raised telling you that the C++ object has not been initialized |
| 49 | yet. |
| 50 | |
| 51 | Also, you will probably not be able to do any kind of GUI or bitmap |
| 52 | operation unless you first have created an app object, (even on |
| 53 | Windows where most anything was possible before.) |
| 54 | |
| 55 | **[Changed in 2.5.2.x]** All the Window and GDI (pen, bitmap, etc.) |
| 56 | class constructors and also many toplevel functions and static methods |
| 57 | will now check that a wx.App object has already been created and will |
| 58 | raise a wx.PyNoAppError exception if not. |
| 59 | |
| 60 | |
| 61 | |
| 62 | |
| 63 | SWIG 1.3 |
| 64 | -------- |
| 65 | |
| 66 | wxPython is now using SWIG 1.3.x from CVS (with several of my own |
| 67 | customizations added that I hope to get folded back into the main SWIG |
| 68 | distribution.) This has some far reaching ramifications: |
| 69 | |
| 70 | All classes derive from object and so all are now "new-style |
| 71 | classes." This also allows you to use mixin classes that are |
| 72 | new-style and to use properties, staticmethod, etc. |
| 73 | |
| 74 | Public data members of the C++ classes are wrapped as Python |
| 75 | properties using property() instead of using |
| 76 | __getattr__/__setattr__ hacks like before. Normally you shouldn't |
| 77 | notice any difference, but if you were previously doing something |
| 78 | with __getattr__/__setattr__ in derived classes then you may have |
| 79 | to adjust things. |
| 80 | |
| 81 | Static C++ methods are wrapped using the staticmethod() feature of |
| 82 | Python and so are accessible as ClassName.MethodName as expected. |
| 83 | They are still also available as top level functions named like |
| 84 | ClassName_MethodName as before. |
| 85 | |
| 86 | The relationship between the wxFoo and wxFooPtr classes have |
| 87 | changed for the better. Specifically, all instances that you see |
| 88 | will be wx.Foo even if they are created internally using wx.FooPtr, |
| 89 | because wx.FooPtr.__init__ will change the instance's __class__ as |
| 90 | part of the initialization. If you have any code that checks |
| 91 | class type using something like isinstance(obj, wx.FooPtr) you will |
| 92 | need to change it to isinstance(obj, wx.Foo). |
| 93 | |
| 94 | |
| 95 | |
| 96 | Binding Events |
| 97 | -------------- |
| 98 | |
| 99 | All of the EVT_* functions are now instances of the wx.PyEventBinder |
| 100 | class. They have a __call__ method so they can still be used as |
| 101 | functions like before, but making them instances adds some |
| 102 | flexibility that I expect to take advantave of in the future. |
| 103 | |
| 104 | wx.EvtHandler (the base class for wx.Window) now has a Bind method that |
| 105 | makes binding events to windows a little easier. Here is its |
| 106 | definition and docstring:: |
| 107 | |
| 108 | def Bind(self, event, handler, source=None, id=wxID_ANY, id2=wxID_ANY): |
| 109 | """ |
| 110 | Bind an event to an event handler. |
| 111 | |
| 112 | event One of the EVT_* objects that specifies the |
| 113 | type of event to bind. |
| 114 | |
| 115 | handler A callable object to be invoked when the event |
| 116 | is delivered to self. Pass None to disconnect an |
| 117 | event handler. |
| 118 | |
| 119 | source Sometimes the event originates from a different window |
| 120 | than self, but you still want to catch it in self. (For |
| 121 | example, a button event delivered to a frame.) By |
| 122 | passing the source of the event, the event handling |
| 123 | system is able to differentiate between the same event |
| 124 | type from different controls. |
| 125 | |
| 126 | id,id2 Used for menu IDs or for event types that require a |
| 127 | range of IDs |
| 128 | |
| 129 | """ |
| 130 | |
| 131 | Some examples of its use:: |
| 132 | |
| 133 | self.Bind(wx.EVT_SIZE, self.OnSize) |
| 134 | self.Bind(wx.EVT_BUTTON, self.OnButtonClick, theButton) |
| 135 | self.Bind(wx.EVT_MENU, self.OnExit, id=wx.ID_EXIT) |
| 136 | |
| 137 | |
| 138 | The wx.Menu methods that add items to a wx.Menu have been modified |
| 139 | such that they return a reference to the wx.MenuItem that was created. |
| 140 | Additionally menu items and toolbar items have been modified to |
| 141 | automatically generate a new ID if -1 is given, similar to using -1 |
| 142 | with window classess. This means that you can create menu or toolbar |
| 143 | items and event bindings without having to predefine a unique menu ID, |
| 144 | although you still can use IDs just like before if you want. For |
| 145 | example, these are all equivallent other than their specific ID |
| 146 | values:: |
| 147 | |
| 148 | 1. |
| 149 | item = menu.Append(-1, "E&xit", "Terminate the App") |
| 150 | self.Bind(wx.EVT_MENU, self.OnExit, item) |
| 151 | |
| 152 | 2. |
| 153 | item = menu.Append(wx.ID_EXIT, "E&xit", "Terminate the App") |
| 154 | self.Bind(wx.EVT_MENU, self.OnExit, item) |
| 155 | |
| 156 | 3. |
| 157 | menu.Append(wx.ID_EXIT, "E&xit", "Terminate the App") |
| 158 | self.Bind(wx.EVT_MENU, self.OnExit, id=wx.ID_EXIT) |
| 159 | |
| 160 | |
| 161 | If you create your own custom event types and EVT_* functions, and you |
| 162 | want to be able to use them with the Bind method above then you should |
| 163 | change your EVT_* to be an instance of wx.PyEventBinder instead of a |
| 164 | function. For example, if you used to have something like this:: |
| 165 | |
| 166 | myCustomEventType = wxNewEventType() |
| 167 | def EVT_MY_CUSTOM_EVENT(win, id, func): |
| 168 | win.Connect(id, -1, myCustomEventType, func) |
| 169 | |
| 170 | |
| 171 | Change it like so:: |
| 172 | |
| 173 | myCustomEventType = wx.NewEventType() |
| 174 | EVT_MY_CUSTOM_EVENT = wx.PyEventBinder(myCustomEventType, 1) |
| 175 | |
| 176 | The second parameter is an integer in [0, 1, 2] that specifies the |
| 177 | number of IDs that are needed to be passed to Connect. |
| 178 | |
| 179 | **[Changed in 2.5.2.x]** There is also an Unbind method added to |
| 180 | wx.EvtHandler that can be used to disconenct event handlers. It looks |
| 181 | like this:: |
| 182 | |
| 183 | def Unbind(self, event, source=None, id=wx.ID_ANY, id2=wx.ID_ANY): |
| 184 | """ |
| 185 | Disconencts the event handler binding for event from self. |
| 186 | Returns True if successful. |
| 187 | """ |
| 188 | |
| 189 | |
| 190 | |
| 191 | |
| 192 | The wx Namespace |
| 193 | ---------------- |
| 194 | |
| 195 | The second phase of the wx Namespace Transition has begun. That means |
| 196 | that the real names of the classes and other symbols do not have the |
| 197 | 'wx' prefix and the modules are located in a Python package named |
| 198 | wx. There is still a Python package named wxPython with modules |
| 199 | that have the names with the wx prefix for backwards compatibility. |
| 200 | Instead of dynamically changing the names at module load time like in |
| 201 | 2.4, the compatibility modules are generated at build time and contain |
| 202 | assignment statements like this:: |
| 203 | |
| 204 | wxWindow = wx._core.Window |
| 205 | |
| 206 | Don't let the "_core" in the name bother you. That and some other |
| 207 | modules are implementation details, and everything that was in the |
| 208 | wxPython.wx module before will still be in the wx package namespace |
| 209 | after this change. So from your code you would use it as wx.Window or |
| 210 | wxWindow if you import from the wxPython.wx module. |
| 211 | |
| 212 | A few notes about how all of this was accomplished might be |
| 213 | interesting... SWIG is now run twice for each module that it is |
| 214 | generating code for. The first time it outputs an XML representaion |
| 215 | of the parse tree, which can be up to 20MB and 300K lines in size! |
| 216 | That XML is then run through a little Python script that creates a |
| 217 | file full of SWIG %rename directives that take the wx off of the |
| 218 | names, and also generates the Python compatibility file described |
| 219 | above that puts the wx back on the names. SWIG is then run a second |
| 220 | time to generate the C++ code to implement the extension module, and |
| 221 | uses the %rename directives that were generated in the first step. |
| 222 | |
| 223 | Not every name is handled correctly (but the bulk of them are) and so |
| 224 | some work has to be done by hand, especially for the reverse-renamers. |
| 225 | So expect a few flaws here and there until everything gets sorted out. |
| 226 | |
| 227 | In summary, the wx package and names without the "wx" prefix are now |
| 228 | the official form of the wxPython classes. For example:: |
| 229 | |
| 230 | import wx |
| 231 | |
| 232 | class MyFrame(wx.Frame): |
| 233 | def __init__(self, parent, title): |
| 234 | wx.Frame.__init__(self, parent, -1, title) |
| 235 | p = wx.Panel(self, -1) |
| 236 | b = wx.Button(p, -1, "Do It", (10,10)) |
| 237 | self.Bind(wx.EVT_BUTTON, self.JustDoIt, b) |
| 238 | |
| 239 | def JustDoIt(self, evt): |
| 240 | print "It's done!" |
| 241 | |
| 242 | app = wx.PySimpleApp() |
| 243 | f = MyFrame(None, "What's up?") |
| 244 | f.Show() |
| 245 | app.MainLoop() |
| 246 | |
| 247 | You shouldn't need to migrate all your modules over to use the new |
| 248 | package and names right away as there are modules in place that try to |
| 249 | provide as much backwards compatibility of the names as possible. If |
| 250 | you rewrote the above sample using "from wxPython.wx import * ", the |
| 251 | old wxNames, and the old style of event binding it will still work |
| 252 | just fine. |
| 253 | |
| 254 | |
| 255 | |
| 256 | |
| 257 | New wx.DC Methods |
| 258 | ----------------- |
| 259 | |
| 260 | **[Changed in 2.5.2.x]** In wxPython 2.5.1.5 there was a new |
| 261 | implementation of the wx.DC Draw and other methods that broke |
| 262 | backwards compatibility in the name of consistency. That change has |
| 263 | been reverted and the wx.DC Draw methods with 2.4 compatible |
| 264 | signatures have been restored. In addition a new set of methods have |
| 265 | been added that take wx.Point and/or wx.Size parameters instead of |
| 266 | separate integer parameters. The Draw and etc. methods now available |
| 267 | in the wx.DC class are:: |
| 268 | |
| 269 | |
| 270 | FloodFill(self, x, y, colour, style = wx.FLOOD_SURFACE) |
| 271 | FoodFillPoint(self, pt, colour, style = wx.FLOOD_SURFACE) |
| 272 | |
| 273 | GetPixel(self, x,y) |
| 274 | GetPixelPoint(self, pt) |
| 275 | |
| 276 | DrawLine(self, x1, y1, x2, y2) |
| 277 | DrawLinePoint(self, pt1, pt2) |
| 278 | |
| 279 | CrossHair(self, x, y) |
| 280 | CrossHairPoint(self, pt) |
| 281 | |
| 282 | DrawArc(self, x1, y1, x2, y2, xc, yc) |
| 283 | DrawArcPoint(self, pt1, pt2, centre) |
| 284 | |
| 285 | DrawCheckMark(self, x, y, width, height) |
| 286 | DrawCheckMarkRect(self, rect) |
| 287 | |
| 288 | DrawEllipticArc(self, x, y, w, h, sa, ea) |
| 289 | DrawEllipticArcPointSize(self, pt, sz, sa, ea) |
| 290 | |
| 291 | DrawPoint(self, x, y) |
| 292 | DrawPointPoint(self, pt) |
| 293 | |
| 294 | DrawRectangle(self, x, y, width, height) |
| 295 | DrawRectangleRect(self, rect) |
| 296 | DrawRectanglePointSize(self, pt, sz) |
| 297 | |
| 298 | DrawRoundedRectangle(self, x, y, width, height, radius) |
| 299 | DrawRoundedRectangleRect(self, r, radius) |
| 300 | DrawRoundedRectanglePointSize(self, pt, sz, radius) |
| 301 | |
| 302 | DrawCircle(self, x, y, radius) |
| 303 | DrawCirclePoint(self, pt, radius) |
| 304 | |
| 305 | DrawEllipse(self, x, y, width, height) |
| 306 | DrawEllipseRect(self, rect) |
| 307 | DrawEllipsePointSize(self, pt, sz) |
| 308 | |
| 309 | DrawIcon(self, icon, x, y) |
| 310 | DrawIconPoint(self, icon, pt) |
| 311 | |
| 312 | DrawBitmap(self, bmp, x, y, useMask = False) |
| 313 | DrawBitmapPoint(self, bmp, pt, useMask = False) |
| 314 | |
| 315 | DrawText(self, text, x, y) |
| 316 | DrawTextPoint(self, text, pt) |
| 317 | |
| 318 | DrawRotatedText(self, text, x, y, angle) |
| 319 | DrawRotatedTextPoint(self, text, pt, angle) |
| 320 | |
| 321 | bool Blit(self, xdest, ydest, width, height, sourceDC, xsrc, ysrc, |
| 322 | rop = wx.COPY, useMask = False, xsrcMask = -1, ysrcMask = -1) |
| 323 | BlitPointSize(self, destPt, sz, sourceDC, srcPt, rop = wx.COPY, |
| 324 | useMask = False, srcPtMask = wxDefaultPosition) |
| 325 | |
| 326 | |
| 327 | SetClippingRegion(self, x, y, width, height) |
| 328 | SetClippingRegionPointSize(self, pt, sz) |
| 329 | SetClippingRegionAsRegion(self, region) |
| 330 | SetClippingRect(self, rect) |
| 331 | |
| 332 | |
| 333 | |
| 334 | |
| 335 | |
| 336 | Building, Extending and Embedding wxPython |
| 337 | ------------------------------------------ |
| 338 | |
| 339 | wxPython's setup.py script now expects to use existing libraries for |
| 340 | the contribs (gizmos, stc, xrc, etc.) rather than building local |
| 341 | copies of them. If you build your own copies of wxPython please be |
| 342 | aware that you now need to also build the ogl, stc, xrc, and gizmos |
| 343 | libraries in addition to the main wx lib. |
| 344 | |
| 345 | The wxPython.h and other header files are now in |
| 346 | .../wxPython/include/wx/wxPython instead of in wxPython/src. You |
| 347 | should include it via the "wx/wxPython/wxPython.h" path and add |
| 348 | .../wxPython/include to your list of include paths. On OSX and |
| 349 | unix-like systems the wxPython headers are installed to the same place |
| 350 | that the wxWidgets headers are installed, so if you are building |
| 351 | wxPython compatible extensions on those platforms then your include |
| 352 | path should already be set properly. |
| 353 | |
| 354 | If you are also using SWIG for your extension then you'll need to |
| 355 | adapt how the wxPython .i files are imported into your .i files. See |
| 356 | the wxPython sources for examples. Your modules will need to at least |
| 357 | ``%import core.i``, and possibly others if you need the definition of |
| 358 | other classes. Since you will need them to build your modules using |
| 359 | SWIG, the main wxPython .i files are also installed with the wxPython |
| 360 | headers in an i_files sibdirectory. It should be enough to pass a |
| 361 | -I/pathname on the command line for SWIG to find the files. |
| 362 | |
| 363 | The bulk of wxPython's setup.py has been moved to another module, |
| 364 | wx/build/config.py. This module will be installed as part of wxPython |
| 365 | so 3rd party modules that wish to use the same setup/configuration |
| 366 | code can do so simply by importing this module from their own setup.py |
| 367 | scripts using ``import wx.build.config``. |
| 368 | |
| 369 | You no longer need to call wxClassInfo::CleanUpClasses() and |
| 370 | wxClassInfo::InitializeClasses() in your extensions or when embedding |
| 371 | wxPython. |
| 372 | |
| 373 | The usage of wxPyBeginAllowThreads and wxPyEndAllowThreads has changed |
| 374 | slightly. wxPyBeginAllowThreads now returns a boolean value that must |
| 375 | be passed to the coresponding wxPyEndAllowThreads function call. This |
| 376 | is to help do the RightThing when calls to these two functions are |
| 377 | nested, or if calls to external code in other extension modules that |
| 378 | are wrapped in the standard Py_(BEGIN|END)_ALLOW_THERADS may result in |
| 379 | wx event handlers being called (such as during the call to |
| 380 | os.startfile.) |
| 381 | |
| 382 | |
| 383 | |
| 384 | Two (or Three!) Phase Create |
| 385 | ---------------------------- |
| 386 | |
| 387 | If you use the Precreate/Create method of instantiating a window, (for |
| 388 | example, to set an extended style flag, or for XRC handlers) then |
| 389 | there is now a new method named PostCreate to help with transplanting |
| 390 | the brain of the prewindow instance into the derived window instance. |
| 391 | For example:: |
| 392 | |
| 393 | class MyDialog(wx.Dialog): |
| 394 | def __init__(self, parent, ID, title, pos, size, style): |
| 395 | pre = wx.PreDialog() |
| 396 | pre.SetExtraStyle(wx.DIALOG_EX_CONTEXTHELP) |
| 397 | pre.Create(parent, ID, title, pos, size, style) |
| 398 | self.PostCreate(pre) |
| 399 | |
| 400 | |
| 401 | |
| 402 | Sizers |
| 403 | ------ |
| 404 | |
| 405 | The hack allowing the old "option" keyword parameter has been removed. |
| 406 | If you use keyword args with w.xSizer Add, Insert, or Prepend methods |
| 407 | then you will need to use the ``proportion`` name instead of |
| 408 | ``option``. (The ``proportion`` keyword was also allowed in 2.4.2.4.) |
| 409 | |
| 410 | When adding a spacer to a sizer you now need to use a wx.Size or a |
| 411 | 2-integer sequence instead of separate width and height parameters. |
| 412 | This was optionally allowed in 2.4, but now it is required. This |
| 413 | allows for more consistency in how you add the various types of items |
| 414 | to a sizer. The first parameter defines the item (instead of the |
| 415 | possibily first two, depending on if you are doing a spacer or not,) |
| 416 | and that item can either be a window, a sizer or a spacer (which can |
| 417 | be a sequence or a wx.Size.) Removing the option for separate width |
| 418 | and height parameters greatly simplified the wrapper code. |
| 419 | |
| 420 | The wx.GridBagSizer class (very similar to the RowColSizer in the |
| 421 | library) has been added to C++ and wrapped for wxPython. It can also |
| 422 | be used from XRC. |
| 423 | |
| 424 | You should not use AddWindow, AddSizer, AddSpacer (and similar for |
| 425 | Insert, Prepend, and etc.) methods any longer. Just use Add and the |
| 426 | wrappers will figure out what to do. **[Changed in 2.5.2.x]** |
| 427 | AddWindow, AddSize, AddSpacer and etc. will now issue a |
| 428 | DeprecationWarning. |
| 429 | |
| 430 | **[Changed in 2.5.2.x]** The Sizers have had some fundamental internal |
| 431 | changes in the 2.5.2.x release intended to make them do more of the |
| 432 | "Right Thing" but also be as backwards compatible as possible. |
| 433 | First a bit about how things used to work: |
| 434 | |
| 435 | * The size that a window had when Add()ed to the sizer was assumed |
| 436 | to be its minimal size, and that size would always be used by |
| 437 | default when calculating layout size and positions, and the |
| 438 | sizer itself would keep track of that minimal size. |
| 439 | |
| 440 | * If the window item was added with the ``wx.ADJUST_MINSIZE`` |
| 441 | flag then when layout was calculated the item's ``GetBestSize`` |
| 442 | would be used to reset the minimal size that the sizer used. |
| 443 | |
| 444 | The main thrust of the new Sizer changes was to make behaviour like |
| 445 | ``wx.ADJUST_MINSIZE`` be the default, and also to push the tracking of |
| 446 | the minimal size to the window itself (since it knows its own needs) |
| 447 | instead of having the sizer take care of it. Consequently these |
| 448 | changes were made: |
| 449 | |
| 450 | * The ``wx.FIXED_MINSIZE`` flag was added to allow for the old |
| 451 | behaviour. When this flag is used the size a window has when |
| 452 | added to the sizer will be treated as its minimal size and it |
| 453 | will not be readjusted on each layout. |
| 454 | |
| 455 | * The min size stored in ``wx.Window`` and settable with |
| 456 | ``SetSizeHints`` or ``SetMinSize`` will by default be used by |
| 457 | the sizer (if it was set) as the minimal size of the sizer item. |
| 458 | If the min size was not set (or was only partially set) then the |
| 459 | window's best size is fetched and it is used instead of (or |
| 460 | blended with) the min size. ``wx.Window.GetBestFittingSize`` |
| 461 | was added to facilitate getting the size to be used by the |
| 462 | sizers. |
| 463 | |
| 464 | * The best size of a window is cached so it doesn't need to |
| 465 | recaculated on every layout. ``wx.Window.InvalidateBestSize`` |
| 466 | was added and should be called (usually just internally in |
| 467 | control methods) whenever something is done that would make the |
| 468 | best size change. |
| 469 | |
| 470 | * All wxControls were changed to set the minsize to what is passed |
| 471 | to the constructor or Create method, and also to set the real |
| 472 | size of the control to the blending of the min size and best |
| 473 | size. ``wx.Window.SetBestFittingSize`` was added to help with |
| 474 | this, although most controls don't need to call it directly |
| 475 | because it is called indirectly via the ``SetInitialSize`` |
| 476 | called in the base classes. |
| 477 | |
| 478 | At this time, the only situation known not to work the same as before |
| 479 | is the following:: |
| 480 | |
| 481 | win = SomeWidget(parent) |
| 482 | win.SetSize(SomeNonDefaultSize) |
| 483 | sizer.Add(win) |
| 484 | |
| 485 | In this case the old code would have used the new size as the minimum, |
| 486 | but now the sizer will use the default size as the minimum rather than |
| 487 | the size set later. It is an easy fix though, just move the |
| 488 | specification of the size to the constructor (assuming that SomeWidget |
| 489 | will set its minsize there like the rest of the controls do) or call |
| 490 | ``SetMinSize`` instead of ``SetSize``. |
| 491 | |
| 492 | In order to fit well with this new scheme of things, all wxControls or |
| 493 | custom controls should do the following things. (Depending on how |
| 494 | they are used you may also want to do the same thing for non-control |
| 495 | custom windows.) |
| 496 | |
| 497 | * Either override or inherit a meaningful ``DoGetBestSize`` method |
| 498 | that calculates whatever size is "best" for the control. Once |
| 499 | that size is calculated then there should normally be a call to |
| 500 | ``CacheBestSize`` to save it for later use, unless for some |
| 501 | reason you want the best size to be recalculated on every |
| 502 | layout. |
| 503 | |
| 504 | Note: In order to successfully override ``DoGetBestSize`` in |
| 505 | Python the class needs to be derived from ``wx.PyWindow``, |
| 506 | ``wx.PyControl``, or etc. If your class instead derives from |
| 507 | one of the standard wx classes then just be sure that the min |
| 508 | size gets explicitly set to what would have been the best size |
| 509 | and things should work properly in almost all situations. |
| 510 | |
| 511 | * Any method that changes the attributes of the control such that |
| 512 | the best size will change should call ``InvalidateBestSize`` so |
| 513 | it will be recalculated the next time it is needed. |
| 514 | |
| 515 | * The control's constructor and/or Create method should ensure |
| 516 | that the minsize is set to the size passed in, and that the |
| 517 | control is sized to a blending of the min size and best size. |
| 518 | This can be done by calling ``SetBestFittingSize``. |
| 519 | |
| 520 | |
| 521 | |
| 522 | PlatformInfo |
| 523 | ------------ |
| 524 | |
| 525 | Added wx.PlatformInfo which is a tuple containing strings that |
| 526 | describe the platform and build options of wxPython. This lets you |
| 527 | know more about the build than just the __WXPORT__ value that |
| 528 | wx.Platform contains, such as if it is a GTK2 build. For example, |
| 529 | instead of:: |
| 530 | |
| 531 | if wx.Platform == "__WXGTK__": |
| 532 | ... |
| 533 | |
| 534 | you should do this:: |
| 535 | |
| 536 | if "__WXGTK__" in wx.PlatformInfo: |
| 537 | ... |
| 538 | |
| 539 | and you can specifically check for a wxGTK2 build by looking for |
| 540 | "gtk2" in wx.PlatformInfo. Unicode builds are also detectable this |
| 541 | way. If there are any other platform/toolkit/build flags that make |
| 542 | sense to add to this tuple please let me know. |
| 543 | |
| 544 | BTW, wx.Platform will probably be deprecated in the future. |
| 545 | |
| 546 | |
| 547 | |
| 548 | ActiveX |
| 549 | ------- |
| 550 | |
| 551 | Lindsay Mathieson's newest wxActiveX_ class has been wrapped into a new |
| 552 | extension module called wx.activex. It is very generic and dynamic |
| 553 | and should allow hosting of arbitray ActiveX controls within your |
| 554 | wxPython apps. So far I've tested it with IE, PDF, and Flash |
| 555 | controls, (and there are new samples in the demo and also library |
| 556 | modules supporting these.) |
| 557 | |
| 558 | .. _wxActiveX: http://members.optusnet.com.au/~blackpaw1/wxactivex.html |
| 559 | |
| 560 | The new wx.activex module contains a bunch of code, but the most |
| 561 | important things to look at are ActiveXWindow and ActiveXEvent. |
| 562 | ActiveXWindow derives from wxWindow and the constructor accepts a |
| 563 | CLSID for the ActiveX Control that should be created. (There is also |
| 564 | a CLSID class that can convert from a progID or a CLSID String.) The |
| 565 | ActiveXWindow class simply adds methods that allow you to query some |
| 566 | of the TypeInfo exposed by the ActiveX object, and also to get/set |
| 567 | properties or call methods by name. The Python implementation |
| 568 | automatically handles converting parameters and return values to/from |
| 569 | the types expected by the ActiveX code as specified by the TypeInfo, |
| 570 | (just bool, integers, floating point, strings and None/Empty so far, |
| 571 | but more can be handled later.) |
| 572 | |
| 573 | That's pretty much all there is to the class, as I mentioned before it |
| 574 | is very generic and dynamic. Very little is hard-coded and everything |
| 575 | that is done with the actual ActiveX control is done at runtime and |
| 576 | referenced by property or method name. Since Python is such a dynamic |
| 577 | language this is a very good match. I thought for a while about doing |
| 578 | some Python black-magic and making the specific methods/properties of |
| 579 | the actual ActiveX control "appear" at runtime, but then decided that |
| 580 | it would be better and more understandable to do it via subclassing. |
| 581 | So there is a utility class in wx.activex that given an existing |
| 582 | ActiveXWindow instance can generate a .py module containing a derived |
| 583 | class with real methods and properties that do the Right Thing to |
| 584 | reflect those calls to the real ActiveX control. There is also a |
| 585 | script/tool module named genaxmodule that given a CLSID or progID and |
| 586 | a class name, will generate the module for you. There are a few |
| 587 | examples of the output of this tool in the wx.lib package, see |
| 588 | iewin.py, pdfwin.py and flashwin.py. |
| 589 | |
| 590 | Currently the genaxmodule tool will tweak some of the names it |
| 591 | generates, but this can be controled if you would like to do it |
| 592 | differently by deriving your own class from GernerateAXModule, |
| 593 | overriding some methods and then using this class from a tool like |
| 594 | genaxmodule. [TODO: make specifying a new class on genaxmodule's |
| 595 | command-line possible.] The current default behavior is that any |
| 596 | event names that start with "On" will have the "On" dropped, property |
| 597 | names are converted to all lower case, and if any name is a Python |
| 598 | keyword it will have an underscore appended to it. GernerateAXModule |
| 599 | does it's best when generating the code in the new module, but it can |
| 600 | only be as good as the TypeInfo data available from the ActiveX |
| 601 | control so sometimes some tweaking will be needed. For example, the |
| 602 | IE web browser control defines the Flags parameter of the Navigate2 |
| 603 | method as required, but MSDN says it is optional. |
| 604 | |
| 605 | It is intended that this new wx.activex module will replace both the |
| 606 | older version of Lindsay's code available in iewin.IEHtmlWindow, and |
| 607 | also the wx.lib.activexwraper module. Probably the biggest |
| 608 | differences you'll ecounter in migrating activexwrapper-based code |
| 609 | (besides events working better without causing deadlocks) is that |
| 610 | events are no longer caught by overriding methods in your derived |
| 611 | class. Instead ActiveXWindow uses the wx event system and you bind |
| 612 | handlers for the ActiveX events exactly the same way you do for any wx |
| 613 | event. There is just one extra step needed and that is creating an |
| 614 | event ID from the ActiveX event name, and if you use the genaxmodule |
| 615 | tool then this extra step will be handled for you there. For example, |
| 616 | for the StatusTextChange event in the IE web browser control, this |
| 617 | code is generated for you:: |
| 618 | |
| 619 | wxEVT_StatusTextChange = wx.activex.RegisterActiveXEvent('StatusTextChange') |
| 620 | EVT_StatusTextChange = wx.PyEventBinder(wxEVT_StatusTextChange, 1) |
| 621 | |
| 622 | and you would use it in your code like this:: |
| 623 | |
| 624 | self.Bind(iewin.EVT_StatusTextChange, self.UpdateStatusText, self.ie) |
| 625 | |
| 626 | When the event happens and your event handler function is called the |
| 627 | event properties from the ActiveX control (if any) are converted to |
| 628 | attributes of the event object passed to the handler. (Can you say |
| 629 | 'event' any more times in a single sentence? ;-) ) For example the |
| 630 | StatusTextChange event will also send the text that should be put into |
| 631 | the status line as an event parameter named "Text" and you can access |
| 632 | it your handlers as an attribute of the event object like this:: |
| 633 | |
| 634 | def UpdateStatusText(self, evt): |
| 635 | self.SetStatusText(evt.Text) |
| 636 | |
| 637 | Usually these event object attributes should be considered read-only, |
| 638 | but some will be defined by the TypeInfo as output parameters. In |
| 639 | those cases if you modify the event object's attribute then that value |
| 640 | will be returned to the ActiveX control. For example, to prevent a |
| 641 | new window from being opened by the IE web browser control you can do |
| 642 | this in the handler for the iewin.EVT_NewWindow2 event:: |
| 643 | |
| 644 | def OnNewWindow2(self, evt): |
| 645 | evt.Cancel = True |
| 646 | |
| 647 | So how do you know what methods, events and properties that an ActiveX |
| 648 | control supports? There is a funciton in wx.activex named GetAXInfo |
| 649 | that returns a printable summary of the TypeInfo from the ActiveX |
| 650 | instance passed in. You can use this as an example of how to browse |
| 651 | the TypeInfo provided, and there is also a copy of this function's |
| 652 | output appended as a comment to the modules produced by the |
| 653 | genaxmodule tool. Beyond that you'll need to consult the docs |
| 654 | provided by the makers of the ActiveX control that you are using. |
| 655 | |
| 656 | |
| 657 | |
| 658 | |
| 659 | PNG Images |
| 660 | ---------- |
| 661 | |
| 662 | Prior to 2.5 the PNG image handler would convert all alpha channel |
| 663 | information to a mask when the image was loaded. Pixels that were |
| 664 | more than halfway transparent would be made fully transparent by the |
| 665 | mask and the rest would be made fully opaque. |
| 666 | |
| 667 | In 2.5 the image handler has been updated to preserve the alpha |
| 668 | channel and will now only create a mask when all the pixels in the |
| 669 | image are either fully transparent or fully opaque. In addition, the |
| 670 | wx.DC.DrawBitmap and wx.DC.Blit methods are able to correctly blend |
| 671 | the pixels in the image with partially transparent alpha values. |
| 672 | (Currently only on MSW and Mac, if anybody knows how to do it for GTK |
| 673 | then please submit a patch!) |
| 674 | |
| 675 | If you are using a PNG with an alpha channel but you need to have a |
| 676 | wx.Mask like you automatically got in 2.4 then you can do one of the |
| 677 | following: |
| 678 | |
| 679 | * Edit the image and make all the partially transparent pixels be |
| 680 | fully transparent. |
| 681 | |
| 682 | * Use a different image type. |
| 683 | |
| 684 | * Set a mask based on colour after you load the image. |
| 685 | |
| 686 | |
| 687 | |
| 688 | OGL is dead! LONG LIVE OGL! |
| 689 | --------------------------- |
| 690 | |
| 691 | **[Changed in 2.5.2.x]** |
| 692 | |
| 693 | The wx.ogl module has been deprecated in favor of the new Python port |
| 694 |