]>
Commit | Line | Data |
---|---|---|
d14a1e28 RD |
1 | ============================ |
2 | wxPython 2.5 Migration Guide | |
3 | ============================ | |
4 | ||
5 | This document will help explain some of the major changes in wxPython | |
f847103a RD |
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. | |
d14a1e28 | 10 | |
33ab916f RD |
11 | .. _CHANGES: CHANGES.html |
12 | ||
d14a1e28 | 13 | |
e8a71fa0 RD |
14 | wxName Change |
15 | ------------- | |
16 | ||
17 | The **wxWindows** project and library is now known as | |
18 | **wxWidgets**. Please see here_ for more details. | |
19 | ||
29bfe46b | 20 | .. _here: http://www.wxwidgets.org/name.htm |
e8a71fa0 RD |
21 | |
22 | This won't really affect wxPython all that much, other than the fact | |
f847103a RD |
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 | |
e8a71fa0 RD |
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 | ||
d14a1e28 RD |
29 | |
30 | Module Initialization | |
31 | --------------------- | |
32 | ||
33 | The import-startup-bootstrap process employed by wxPython was changed | |
e8a71fa0 | 34 | such that wxWidgets and the underlying gui toolkit are **not** |
d14a1e28 RD |
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 | |
61563ef3 | 47 | you have created your wx.App object. If you do then an exception will |
cb2d8b77 | 48 | be raised telling you that the C++ object has not been initialized |
61563ef3 | 49 | yet. |
d14a1e28 RD |
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 | ||
64316568 | 55 | **[Changed in 2.5.2.x]** All the Window and GDI (pen, bitmap, etc.) |
c8169991 RD |
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 | ||
ab1f7d2a | 60 | |
d14a1e28 RD |
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 | |
d7403ad2 RD |
71 | classes." This also allows you to use mixin classes that are |
72 | new-style and to use properties, staticmethod, etc. | |
d14a1e28 RD |
73 | |
74 | Public data members of the C++ classes are wrapped as Python | |
d7403ad2 RD |
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 | |
d14a1e28 RD |
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 | |
d7403ad2 RD |
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 | |
d14a1e28 | 90 | part of the initialization. If you have any code that checks |
d7403ad2 RD |
91 | class type using something like isinstance(obj, wx.FooPtr) you will |
92 | need to change it to isinstance(obj, wx.Foo). | |
d14a1e28 RD |
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 | |
29bfe46b | 102 | flexibility that I expect to take advantave of in the future. |
d14a1e28 RD |
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) | |
c8000995 RD |
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 | |
e8a71fa0 RD |
145 | example, these are all equivallent other than their specific ID |
146 | values:: | |
c8000995 RD |
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) | |
d14a1e28 | 155 | |
c8000995 RD |
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 | ||
d14a1e28 RD |
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 | |
d7403ad2 | 163 | change your EVT_* to be an instance of wx.PyEventBinder instead of a |
29bfe46b | 164 | function. For example, if you used to have something like this:: |
d14a1e28 RD |
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 | ||
6158f936 RD |
173 | myCustomEventType = wx.NewEventType() |
174 | EVT_MY_CUSTOM_EVENT = wx.PyEventBinder(myCustomEventType, 1) | |
d14a1e28 RD |
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 | ||
64316568 | 179 | **[Changed in 2.5.2.x]** There is also an Unbind method added to |
d7403ad2 RD |
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 | """ | |
d14a1e28 RD |
188 | |
189 | ||
c8000995 RD |
190 | |
191 | ||
d14a1e28 RD |
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 | ||
d7403ad2 | 204 | wxWindow = wx._core.Window |
d14a1e28 | 205 | |
d7403ad2 | 206 | Don't let the "_core" in the name bother you. That and some other |
d14a1e28 RD |
207 | modules are implementation details, and everything that was in the |
208 | wxPython.wx module before will still be in the wx package namespace | |
d7403ad2 RD |
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. | |
d14a1e28 RD |
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 | |
82a074ce | 250 | you rewrote the above sample using "from wxPython.wx import * ", the |
d14a1e28 RD |
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 | ||
64316568 | 260 | **[Changed in 2.5.2.x]** In wxPython 2.5.1.5 there was a new |
d7403ad2 RD |
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 | |
51b2943a | 267 | in the wx.DC class are:: |
d14a1e28 | 268 | |
d14a1e28 | 269 | |
51b2943a RD |
270 | FloodFill(self, x, y, colour, style = wx.FLOOD_SURFACE) |
271 | FoodFillPoint(self, pt, colour, style = wx.FLOOD_SURFACE) | |
d14a1e28 | 272 | |
51b2943a RD |
273 | GetPixel(self, x,y) |
274 | GetPixelPoint(self, pt) | |
d7403ad2 | 275 | |
51b2943a RD |
276 | DrawLine(self, x1, y1, x2, y2) |
277 | DrawLinePoint(self, pt1, pt2) | |
d14a1e28 | 278 | |
51b2943a RD |
279 | CrossHair(self, x, y) |
280 | CrossHairPoint(self, pt) | |
d14a1e28 | 281 | |
51b2943a RD |
282 | DrawArc(self, x1, y1, x2, y2, xc, yc) |
283 | DrawArcPoint(self, pt1, pt2, centre) | |
d14a1e28 | 284 | |
51b2943a RD |
285 | DrawCheckMark(self, x, y, width, height) |
286 | DrawCheckMarkRect(self, rect) | |
d14a1e28 | 287 | |
51b2943a RD |
288 | DrawEllipticArc(self, x, y, w, h, sa, ea) |
289 | DrawEllipticArcPointSize(self, pt, sz, sa, ea) | |
d14a1e28 | 290 | |
51b2943a RD |
291 | DrawPoint(self, x, y) |
292 | DrawPointPoint(self, pt) | |
d14a1e28 | 293 | |
51b2943a RD |
294 | DrawRectangle(self, x, y, width, height) |
295 | DrawRectangleRect(self, rect) | |
296 | DrawRectanglePointSize(self, pt, sz) | |
d14a1e28 | 297 | |
51b2943a RD |
298 | DrawRoundedRectangle(self, x, y, width, height, radius) |
299 | DrawRoundedRectangleRect(self, r, radius) | |
300 | DrawRoundedRectanglePointSize(self, pt, sz, radius) | |
d14a1e28 | 301 | |
51b2943a RD |
302 | DrawCircle(self, x, y, radius) |
303 | DrawCirclePoint(self, pt, radius) | |
d14a1e28 | 304 | |
51b2943a RD |
305 | DrawEllipse(self, x, y, width, height) |
306 | DrawEllipseRect(self, rect) | |
307 | DrawEllipsePointSize(self, pt, sz) | |
d14a1e28 | 308 | |
51b2943a RD |
309 | DrawIcon(self, icon, x, y) |
310 | DrawIconPoint(self, icon, pt) | |
d14a1e28 | 311 | |
51b2943a RD |
312 | DrawBitmap(self, bmp, x, y, useMask = False) |
313 | DrawBitmapPoint(self, bmp, pt, useMask = False) | |
d14a1e28 | 314 | |
51b2943a RD |
315 | DrawText(self, text, x, y) |
316 | DrawTextPoint(self, text, pt) | |
d14a1e28 | 317 | |
51b2943a RD |
318 | DrawRotatedText(self, text, x, y, angle) |
319 | DrawRotatedTextPoint(self, text, pt, angle) | |
d14a1e28 | 320 | |
51b2943a | 321 | bool Blit(self, xdest, ydest, width, height, sourceDC, xsrc, ysrc, |
d7403ad2 | 322 | rop = wx.COPY, useMask = False, xsrcMask = -1, ysrcMask = -1) |
51b2943a | 323 | BlitPointSize(self, destPt, sz, sourceDC, srcPt, rop = wx.COPY, |
d7403ad2 | 324 | useMask = False, srcPtMask = wxDefaultPosition) |
4da6d35e | 325 | |
d14a1e28 | 326 | |
51b2943a RD |
327 | SetClippingRegion(self, x, y, width, height) |
328 | SetClippingRegionPointSize(self, pt, sz) | |
329 | SetClippingRegionAsRegion(self, region) | |
330 | SetClippingRect(self, rect) | |
d14a1e28 | 331 | |
d14a1e28 RD |
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 | |
29bfe46b | 343 | libraries in addition to the main wx lib. |
d14a1e28 RD |
344 | |
345 | The wxPython.h and other header files are now in | |
9ec83f8d RD |
346 | .../wxPython/include/wx/wxPython instead of in wxPython/src. You |
347 | should include it via the "wx/wxPython/wxPython.h" path and add | |
29bfe46b RD |
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 | |
9ec83f8d RD |
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. | |
29bfe46b RD |
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 | |
9ec83f8d RD |
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. | |
29bfe46b RD |
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``. | |
d14a1e28 RD |
368 | |
369 | You no longer need to call wxClassInfo::CleanUpClasses() and | |
370 | wxClassInfo::InitializeClasses() in your extensions or when embedding | |
371 | wxPython. | |
372 | ||
29bfe46b RD |
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.) | |
d14a1e28 RD |
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 | ||
e6a5dac6 | 405 | The hack allowing the old "option" keyword parameter has been removed. |
9ec83f8d | 406 | If you use keyword args with w.xSizer Add, Insert, or Prepend methods |
d7403ad2 RD |
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.) | |
d14a1e28 | 409 | |
29bfe46b | 410 | When adding a spacer to a sizer you now need to use a wx.Size or a |
d14a1e28 | 411 | 2-integer sequence instead of separate width and height parameters. |
d7403ad2 RD |
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. | |
d14a1e28 | 419 | |
29bfe46b | 420 | The wx.GridBagSizer class (very similar to the RowColSizer in the |
d14a1e28 RD |
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 | |
64316568 | 426 | wrappers will figure out what to do. **[Changed in 2.5.2.x]** |
d7403ad2 RD |
427 | AddWindow, AddSize, AddSpacer and etc. will now issue a |
428 | DeprecationWarning. | |
d14a1e28 | 429 | |
64316568 | 430 | **[Changed in 2.5.2.x]** wx.ADJUST_MINSIZE is now the default |
95fed4d8 | 431 | behaviour for window items in sizers. This means that the item's |
ffcb969e | 432 | GetMinSize and/or GetBestSize will be called when calculating layout |
cb8f28ba RD |
433 | and the return value from that will be used for the minimum size used |
434 | by the sizer. The wx.FIXED_MINSIZE flag was added that will cause the | |
435 | sizer to use the old behaviour in that it will *not* call the window's | |
436 | methods to determine the new best size, instead the minsize that the | |
437 | window had when added to the sizer (or the size the window was created | |
438 | with) will always be used. | |
439 | ||
440 | Related to the above, when controls and some other window types are | |
441 | created either the size passed to the constructor, or their "best | |
442 | size" if an explicit size was not passed in, is set as the window's | |
443 | minimal size. For non top-level windows that hasn't meant much in the | |
444 | past, but now the sizers are sensitive to the window's minimal size. | |
445 | The key point to understand here is that it is no longer the window's | |
446 | size it has when added to the sizer that matters, but its minimal | |
447 | size. So you might have some issues to iron out if you create a | |
448 | control without a size and then set its size to something before | |
449 | adding it to the sizer. Since it's minimal size is probably not the | |
450 | size you set then the sizer will appear to be misbehaving. The fix is | |
451 | to either set the size when calling the window's constructor, or to | |
452 | reset the min size by calling SetSizeHints. You can call SetSizeHints | |
453 | at anytime to change the minsize of a window, just call the sizer's | |
454 | Layout method to redistribute the controls as needed. | |
d7403ad2 | 455 | |
95fed4d8 | 456 | |
d14a1e28 | 457 | |
dd346b94 RD |
458 | PlatformInfo |
459 | ------------ | |
460 | ||
461 | Added wx.PlatformInfo which is a tuple containing strings that | |
462 | describe the platform and build options of wxPython. This lets you | |
463 | know more about the build than just the __WXPORT__ value that | |
464 | wx.Platform contains, such as if it is a GTK2 build. For example, | |
465 | instead of:: | |
466 | ||
467 | if wx.Platform == "__WXGTK__": | |
468 | ... | |
469 | ||
470 | you should do this:: | |
471 | ||
472 | if "__WXGTK__" in wx.PlatformInfo: | |
473 | ... | |
474 | ||
475 | and you can specifically check for a wxGTK2 build by looking for | |
476 | "gtk2" in wx.PlatformInfo. Unicode builds are also detectable this | |
477 | way. If there are any other platform/toolkit/build flags that make | |
478 | sense to add to this tuple please let me know. | |
479 | ||
480 | BTW, wx.Platform will probably be deprecated in the future. | |
481 | ||
482 | ||
d14a1e28 | 483 | |
b7c75283 RD |
484 | ActiveX |
485 | ------- | |
486 | ||
487 | Lindsay Mathieson's newest wxActiveX_ class has been wrapped into a new | |
488 | extension module called wx.activex. It is very generic and dynamic | |
489 | and should allow hosting of arbitray ActiveX controls within your | |
490 | wxPython apps. So far I've tested it with IE, PDF, and Flash | |
491 | controls, (and there are new samples in the demo and also library | |
492 | modules supporting these.) | |
493 | ||
494 | .. _wxActiveX: http://members.optusnet.com.au/~blackpaw1/wxactivex.html | |
495 | ||
496 | The new wx.activex module contains a bunch of code, but the most | |
497 | important things to look at are ActiveXWindow and ActiveXEvent. | |
498 | ActiveXWindow derives from wxWindow and the constructor accepts a | |
499 | CLSID for the ActiveX Control that should be created. (There is also | |
500 | a CLSID class that can convert from a progID or a CLSID String.) The | |
501 | ActiveXWindow class simply adds methods that allow you to query some | |
502 | of the TypeInfo exposed by the ActiveX object, and also to get/set | |
503 | properties or call methods by name. The Python implementation | |
504 | automatically handles converting parameters and return values to/from | |
505 | the types expected by the ActiveX code as specified by the TypeInfo, | |
506 | (just bool, integers, floating point, strings and None/Empty so far, | |
507 | but more can be handled later.) | |
508 | ||
509 | That's pretty much all there is to the class, as I mentioned before it | |
510 | is very generic and dynamic. Very little is hard-coded and everything | |
511 | that is done with the actual ActiveX control is done at runtime and | |
512 | referenced by property or method name. Since Python is such a dynamic | |
513 | language this is a very good match. I thought for a while about doing | |
514 | some Python black-magic and making the specific methods/properties of | |
515 | the actual ActiveX control "appear" at runtime, but then decided that | |
516 | it would be better and more understandable to do it via subclassing. | |
517 | So there is a utility class in wx.activex that given an existing | |
518 | ActiveXWindow instance can generate a .py module containing a derived | |
519 | class with real methods and properties that do the Right Thing to | |
520 | reflect those calls to the real ActiveX control. There is also a | |
521 | script/tool module named genaxmodule that given a CLSID or progID and | |
522 | a class name, will generate the module for you. There are a few | |
b098694c | 523 | examples of the output of this tool in the wx.lib package, see |
b7c75283 RD |
524 | iewin.py, pdfwin.py and flashwin.py. |
525 | ||
526 | Currently the genaxmodule tool will tweak some of the names it | |
527 | generates, but this can be controled if you would like to do it | |
528 | differently by deriving your own class from GernerateAXModule, | |
529 | overriding some methods and then using this class from a tool like | |
530 | genaxmodule. [TODO: make specifying a new class on genaxmodule's | |
531 | command-line possible.] The current default behavior is that any | |
532 | event names that start with "On" will have the "On" dropped, property | |
533 | names are converted to all lower case, and if any name is a Python | |
534 | keyword it will have an underscore appended to it. GernerateAXModule | |
535 | does it's best when generating the code in the new module, but it can | |
536 | only be as good as the TypeInfo data available from the ActiveX | |
537 | control so sometimes some tweaking will be needed. For example, the | |
538 | IE web browser control defines the Flags parameter of the Navigate2 | |
539 | method as required, but MSDN says it is optional. | |
540 | ||
541 | It is intended that this new wx.activex module will replace both the | |
542 | older version of Lindsay's code available in iewin.IEHtmlWindow, and | |
543 | also the wx.lib.activexwraper module. Probably the biggest | |
b098694c | 544 | differences you'll ecounter in migrating activexwrapper-based code |
b7c75283 RD |
545 | (besides events working better without causing deadlocks) is that |
546 | events are no longer caught by overriding methods in your derived | |
547 | class. Instead ActiveXWindow uses the wx event system and you bind | |
548 | handlers for the ActiveX events exactly the same way you do for any wx | |
549 | event. There is just one extra step needed and that is creating an | |
550 | event ID from the ActiveX event name, and if you use the genaxmodule | |
551 | tool then this extra step will be handled for you there. For example, | |
552 | for the StatusTextChange event in the IE web browser control, this | |
553 | code is generated for you:: | |
554 | ||
555 | wxEVT_StatusTextChange = wx.activex.RegisterActiveXEvent('StatusTextChange') | |
556 | EVT_StatusTextChange = wx.PyEventBinder(wxEVT_StatusTextChange, 1) | |
557 | ||
558 | and you would use it in your code like this:: | |
559 | ||
560 | self.Bind(iewin.EVT_StatusTextChange, self.UpdateStatusText, self.ie) | |
561 | ||
562 | When the event happens and your event handler function is called the | |
563 | event properties from the ActiveX control (if any) are converted to | |
564 | attributes of the event object passed to the handler. (Can you say | |
565 | 'event' any more times in a single sentence? ;-) ) For example the | |
566 | StatusTextChange event will also send the text that should be put into | |
567 | the status line as an event parameter named "Text" and you can access | |
b098694c | 568 | it your handlers as an attribute of the event object like this:: |
b7c75283 RD |
569 | |
570 | def UpdateStatusText(self, evt): | |
571 | self.SetStatusText(evt.Text) | |
572 | ||
b098694c RD |
573 | Usually these event object attributes should be considered read-only, |
574 | but some will be defined by the TypeInfo as output parameters. In | |
575 | those cases if you modify the event object's attribute then that value | |
576 | will be returned to the ActiveX control. For example, to prevent a | |
577 | new window from being opened by the IE web browser control you can do | |
578 | this in the handler for the iewin.EVT_NewWindow2 event:: | |
579 | ||
580 | def OnNewWindow2(self, evt): | |
581 | evt.Cancel = True | |
b7c75283 | 582 | |
29bfe46b | 583 | So how do you know what methods, events and properties that an ActiveX |
b7c75283 RD |
584 | control supports? There is a funciton in wx.activex named GetAXInfo |
585 | that returns a printable summary of the TypeInfo from the ActiveX | |
586 | instance passed in. You can use this as an example of how to browse | |
587 | the TypeInfo provided, and there is also a copy of this function's | |
588 | output appended as a comment to the modules produced by the | |
589 | genaxmodule tool. Beyond that you'll need to consult the docs | |
590 | provided by the makers of the ActiveX control that you are using. | |
591 | ||
592 | ||
593 | ||
dcbafcc2 RD |
594 | |
595 | PNG Images | |
596 | ---------- | |
597 | ||
598 | Prior to 2.5 the PNG image handler would convert all alpha channel | |
599 | information to a mask when the image was loaded. Pixels that were | |
600 | more than halfway transparent would be made fully transparent by the | |
601 | mask and the rest would be made fully opaque. | |
602 | ||
603 | In 2.5 the image handler has been updated to preserve the alpha | |
604 | channel and will now only create a mask when all the pixels in the | |
605 | image are either fully transparent or fully opaque. In addition, the | |
606 | wx.DC.DrawBitmap and wx.DC.Blit methods are able to correctly blend | |
607 | the pixels in the image with partially transparent alpha values. | |
608 | (Currently only on MSW and Mac, if anybody knows how to do it for GTK | |
609 | then please submit a patch!) | |
610 | ||
611 | If you are using a PNG with an alpha channel but you need to have a | |
612 | wx.Mask like you automatically got in 2.4 then you can do one of the | |
613 | following: | |
614 | ||
615 | * Edit the image and make all the partially transparent pixels be | |
616 | fully transparent. | |
617 | ||
618 | * Use a different image type. | |
619 | ||
620 | * Set a mask based on colour after you load the image. | |
621 | ||
622 | ||
623 | ||
f847103a RD |
624 | OGL is dead! LONG LIVE OGL! |
625 | --------------------------- | |
626 | ||
64316568 | 627 | **[Changed in 2.5.2.x]** |
ea06848c | 628 | |
f847103a RD |
629 | The wx.ogl module has been deprecated in favor of the new Python port |
630 | Content-type: text/html ]>