]>
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 | |
6 | 2.5 and let you know what you need to do to adapt your programs to | |
33ab916f | 7 | those changes. Be sure to also check in the CHANGES_ file like |
d14a1e28 RD |
8 | usual to see info about the not so major changes and other things that |
9 | have been added to wxPython. | |
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 | |
23 | that the wxwindows.org domain name will be changing to wxwidgets.org, | |
24 | so mail list, CVS, and etc. addresses will be changing. 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 | ||
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 | ||
55 | ||
56 | ||
57 | SWIG 1.3 | |
58 | -------- | |
59 | ||
60 | wxPython is now using SWIG 1.3.x from CVS (with several of my own | |
61 | customizations added that I hope to get folded back into the main SWIG | |
62 | distribution.) This has some far reaching ramifications: | |
63 | ||
64 | All classes derive from object and so all are now "new-style | |
65 | classes" | |
66 | ||
67 | Public data members of the C++ classes are wrapped as Python | |
68 | properties using property() instead of using __getattr__/__setattr__ | |
69 | like before. Normally you shouldn't notice any difference, but if | |
70 | you were previously doing something with __getattr__/__setattr__ | |
71 | in derived classes then you may have to adjust things. | |
72 | ||
73 | Static C++ methods are wrapped using the staticmethod() | |
74 | feature of Python and so are accessible as ClassName.MethodName | |
75 | as expected. They are still available as top level functions | |
76 | ClassName_MethodName as before. | |
77 | ||
78 | The relationship between the wxFoo and wxFooPtr classes have | |
79 | changed for the better. Specifically, all instances that you see | |
80 | will be wxFoo even if they are created internally using wxFooPtr, | |
81 | because wxFooPtr.__init__ will change the instance's __class__ as | |
82 | part of the initialization. If you have any code that checks | |
83 | class type using something like isinstance(obj, wxFooPtr) you will | |
84 | need to change it to isinstance(obj, wxFoo). | |
85 | ||
86 | ||
87 | ||
88 | Binding Events | |
89 | -------------- | |
90 | ||
91 | All of the EVT_* functions are now instances of the wx.PyEventBinder | |
92 | class. They have a __call__ method so they can still be used as | |
93 | functions like before, but making them instances adds some | |
29bfe46b | 94 | flexibility that I expect to take advantave of in the future. |
d14a1e28 RD |
95 | |
96 | wx.EvtHandler (the base class for wx.Window) now has a Bind method that | |
97 | makes binding events to windows a little easier. Here is its | |
98 | definition and docstring:: | |
99 | ||
100 | def Bind(self, event, handler, source=None, id=wxID_ANY, id2=wxID_ANY): | |
101 | """ | |
102 | Bind an event to an event handler. | |
103 | ||
104 | event One of the EVT_* objects that specifies the | |
105 | type of event to bind. | |
106 | ||
107 | handler A callable object to be invoked when the event | |
108 | is delivered to self. Pass None to disconnect an | |
109 | event handler. | |
110 | ||
111 | source Sometimes the event originates from a different window | |
112 | than self, but you still want to catch it in self. (For | |
113 | example, a button event delivered to a frame.) By | |
114 | passing the source of the event, the event handling | |
115 | system is able to differentiate between the same event | |
116 | type from different controls. | |
117 | ||
118 | id,id2 Used for menu IDs or for event types that require a | |
119 | range of IDs | |
120 | ||
121 | """ | |
122 | ||
123 | Some examples of its use:: | |
124 | ||
125 | self.Bind(wx.EVT_SIZE, self.OnSize) | |
126 | self.Bind(wx.EVT_BUTTON, self.OnButtonClick, theButton) | |
c8000995 RD |
127 | self.Bind(wx.EVT_MENU, self.OnExit, id=wx.ID_EXIT) |
128 | ||
129 | ||
130 | The wx.Menu methods that add items to a wx.Menu have been modified | |
131 | such that they return a reference to the wx.MenuItem that was created. | |
132 | Additionally menu items and toolbar items have been modified to | |
133 | automatically generate a new ID if -1 is given, similar to using -1 | |
134 | with window classess. This means that you can create menu or toolbar | |
135 | items and event bindings without having to predefine a unique menu ID, | |
136 | although you still can use IDs just like before if you want. For | |
e8a71fa0 RD |
137 | example, these are all equivallent other than their specific ID |
138 | values:: | |
c8000995 RD |
139 | |
140 | 1. | |
141 | item = menu.Append(-1, "E&xit", "Terminate the App") | |
142 | self.Bind(wx.EVT_MENU, self.OnExit, item) | |
143 | ||
144 | 2. | |
145 | item = menu.Append(wx.ID_EXIT, "E&xit", "Terminate the App") | |
146 | self.Bind(wx.EVT_MENU, self.OnExit, item) | |
d14a1e28 | 147 | |
c8000995 RD |
148 | 3. |
149 | menu.Append(wx.ID_EXIT, "E&xit", "Terminate the App") | |
150 | self.Bind(wx.EVT_MENU, self.OnExit, id=wx.ID_EXIT) | |
151 | ||
152 | ||
d14a1e28 RD |
153 | If you create your own custom event types and EVT_* functions, and you |
154 | want to be able to use them with the Bind method above then you should | |
155 | change your EVT_* to be an instance of wxPyEventBinder instead of a | |
29bfe46b | 156 | function. For example, if you used to have something like this:: |
d14a1e28 RD |
157 | |
158 | myCustomEventType = wxNewEventType() | |
159 | def EVT_MY_CUSTOM_EVENT(win, id, func): | |
160 | win.Connect(id, -1, myCustomEventType, func) | |
161 | ||
162 | ||
163 | Change it like so:: | |
164 | ||
6158f936 RD |
165 | myCustomEventType = wx.NewEventType() |
166 | EVT_MY_CUSTOM_EVENT = wx.PyEventBinder(myCustomEventType, 1) | |
d14a1e28 RD |
167 | |
168 | The second parameter is an integer in [0, 1, 2] that specifies the | |
169 | number of IDs that are needed to be passed to Connect. | |
170 | ||
171 | ||
172 | ||
c8000995 RD |
173 | |
174 | ||
d14a1e28 RD |
175 | The wx Namespace |
176 | ---------------- | |
177 | ||
178 | The second phase of the wx Namespace Transition has begun. That means | |
179 | that the real names of the classes and other symbols do not have the | |
180 | 'wx' prefix and the modules are located in a Python package named | |
181 | wx. There is still a Python package named wxPython with modules | |
182 | that have the names with the wx prefix for backwards compatibility. | |
183 | Instead of dynamically changing the names at module load time like in | |
184 | 2.4, the compatibility modules are generated at build time and contain | |
185 | assignment statements like this:: | |
186 | ||
187 | wxWindow = wx.core.Window | |
188 | ||
189 | Don't let the "core" in the name bother you. That and some other | |
190 | modules are implementation details, and everything that was in the | |
191 | wxPython.wx module before will still be in the wx package namespace | |
192 | after this change. So from your code you would use it as wx.Window. | |
193 | ||
194 | A few notes about how all of this was accomplished might be | |
195 | interesting... SWIG is now run twice for each module that it is | |
196 | generating code for. The first time it outputs an XML representaion | |
197 | of the parse tree, which can be up to 20MB and 300K lines in size! | |
198 | That XML is then run through a little Python script that creates a | |
199 | file full of SWIG %rename directives that take the wx off of the | |
200 | names, and also generates the Python compatibility file described | |
201 | above that puts the wx back on the names. SWIG is then run a second | |
202 | time to generate the C++ code to implement the extension module, and | |
203 | uses the %rename directives that were generated in the first step. | |
204 | ||
205 | Not every name is handled correctly (but the bulk of them are) and so | |
206 | some work has to be done by hand, especially for the reverse-renamers. | |
207 | So expect a few flaws here and there until everything gets sorted out. | |
208 | ||
209 | In summary, the wx package and names without the "wx" prefix are now | |
210 | the official form of the wxPython classes. For example:: | |
211 | ||
212 | import wx | |
213 | ||
214 | class MyFrame(wx.Frame): | |
215 | def __init__(self, parent, title): | |
216 | wx.Frame.__init__(self, parent, -1, title) | |
217 | p = wx.Panel(self, -1) | |
218 | b = wx.Button(p, -1, "Do It", (10,10)) | |
219 | self.Bind(wx.EVT_BUTTON, self.JustDoIt, b) | |
220 | ||
221 | def JustDoIt(self, evt): | |
222 | print "It's done!" | |
223 | ||
224 | app = wx.PySimpleApp() | |
225 | f = MyFrame(None, "What's up?") | |
226 | f.Show() | |
227 | app.MainLoop() | |
228 | ||
229 | You shouldn't need to migrate all your modules over to use the new | |
230 | package and names right away as there are modules in place that try to | |
231 | provide as much backwards compatibility of the names as possible. If | |
82a074ce | 232 | you rewrote the above sample using "from wxPython.wx import * ", the |
d14a1e28 RD |
233 | old wxNames, and the old style of event binding it will still work |
234 | just fine. | |
235 | ||
236 | ||
237 | ||
238 | ||
239 | New wx.DC Methods | |
240 | ----------------- | |
241 | ||
242 | Many of the Draw methods of wx.DC have alternate forms in C++ that take | |
243 | wxPoint or wxSize parameters (let's call these *Type A*) instead of | |
244 | the individual x, y, width, height, etc. parameters (and we'll call | |
245 | these *Type B*). In the rest of the library I normally made the *Type | |
246 | A* forms of the methods be the default method with the "normal" name, | |
247 | and had renamed the *Type B* forms of the methods to some similar | |
248 | name. For example in wx.Window we have these Python methods:: | |
249 | ||
250 | SetSize(size) # Type A | |
251 | SetSizeWH(width, height) # Type B | |
252 | ||
253 | ||
254 | For various reasons the new *Type A* methods in wx.DC were never added | |
255 | and the existing *Type B* methods were never renamed. Now that lots | |
256 | of other things are also changing in wxPython it has been decided that | |
257 | it is a good time to also do the method renaming in wx.DC too in order | |
258 | to be consistent with the rest of the library. The methods in wx.DC | |
259 | that are affected are listed here:: | |
260 | ||
261 | FloodFillXY(x, y, colour, style = wx.FLOOD_SURFACE) | |
262 | FloodFill(point, colour, style = wx.FLOOD_SURFACE) | |
263 | ||
264 | GetPixelXY(x, y) | |
265 | GetPixel(point) | |
266 | ||
267 | DrawLineXY(x1, y1, x2, y2) | |
268 | DrawLine(point1, point2) | |
269 | ||
270 | CrossHairXY(x, y) | |
271 | CrossHair(point) | |
272 | ||
273 | DrawArcXY(x1, y1, x2, y2, xc, yc) | |
274 | DrawArc(point1, point2, center) | |
275 | ||
276 | DrawCheckMarkXY(x, y, width, height) | |
277 | DrawCheckMark(rect) | |
278 | ||
279 | DrawEllipticArcXY(x, y, w, h, start_angle, end_angle) | |
280 | DrawEllipticArc(point, size, start_angle, end_angle) | |
281 | ||
282 | DrawPointXY(x, y) | |
283 | DrawPoint(point) | |
284 | ||
285 | DrawRectangleXY(x, y, width, height) | |
286 | DrawRectangle(point, size) | |
287 | DrawRectangleRect(rect) | |
288 | ||
289 | DrawRoundedRectangleXY(x, y, width, height, radius) | |
290 | DrawRoundedRectangle(point, size, radius) | |
291 | DrawRoundedRectangleRect(rect, radius) | |
292 | ||
293 | DrawCircleXY(x, y, radius) | |
294 | DrawCircle(point, radius) | |
295 | ||
296 | DrawEllipseXY(x, y, width, height) | |
297 | DrawEllipse(point, size) | |
298 | DrawEllipseRect(rect) | |
299 | ||
300 | DrawIconXY(icon, x, y) | |
301 | DrawIcon(icon, point) | |
302 | ||
303 | DrawBitmapXY(bmp, x, y, useMask = FALSE) | |
304 | DrawBitmap(bmp, point, useMask = FALSE) | |
305 | ||
306 | DrawTextXY(text, x, y) | |
307 | DrawText(text, point) | |
308 | ||
309 | DrawRotatedTextXY(text, x, y, angle) | |
310 | DrawRotatedText(text, point, angle) | |
311 | ||
312 | ||
313 | BlitXY(xdest, ydest, width, height, sourceDC, xsrc, ysrc, | |
314 | rop = wxCOPY, useMask = FALSE, xsrcMask = -1, ysrcMask = -1) | |
315 | Blit(destPt, size, sourceDC, srcPt, | |
316 | rop = wxCOPY, useMask = FALSE, srcPtMask = wx.DefaultPosition) | |
317 | ||
82a074ce | 318 | SetClippingRegionXY(x, y, width, height) |
4da6d35e RD |
319 | SetClippingRegion(point, size) |
320 | SetClippingRect(rect) | |
321 | SetClippingRegionAsRegion(region); | |
322 | ||
d14a1e28 | 323 | |
4942342c RD |
324 | If you have code that draws on a DC and you are using the new wx |
325 | namespace then you **will** get errors because of these changes, but | |
326 | it should be easy to fix the code. You can either change the name of | |
327 | the *Type B* method called to the names shown above, or just add | |
328 | parentheses around the parameters as needed to turn them into tuples | |
329 | and let the SWIG typemaps turn them into the wx.Point or wx.Size | |
330 | object that is expected. Then you will be calling the new *Type A* | |
331 | method. For example, if you had this code before:: | |
d14a1e28 RD |
332 | |
333 | dc.DrawRectangle(x, y, width, height) | |
334 | ||
9ec83f8d RD |
335 | You could either continue to use the *Type B* method by changing the |
336 | name to DrawRectangleXY, or just change it to the new *Type A* by | |
d14a1e28 RD |
337 | adding some parentheses like this:: |
338 | ||
339 | dc.DrawRectangle((x, y), (width, height)) | |
340 | ||
9ec83f8d | 341 | Or if you were already using a point and size like this:: |
d14a1e28 RD |
342 | |
343 | dc.DrawRectangle(p.x, p.y, s.width, s.height) | |
344 | ||
345 | Then you can just simplify it like this:: | |
346 | ||
347 | dc.DrawRectangle(p, s) | |
348 | ||
4942342c | 349 | Now before you start yelling and screaming at me for breaking all your |
95fed4d8 RD |
350 | code, take note that up above I said, "...using the new wx |
351 | namespace..." That's because if you are still importing from | |
352 | wxPython.wx then there are some classes defined there with Draw and | |
353 | etc. methods that have 2.4 compatible signatures. Unfortunately there | |
354 | is one exception to this behaviour. If a DC is returned from a | |
355 | function or method then an instance of the new class (with the new | |
356 | methods described above) will be returned instead of the compatibility | |
357 | class. If/When the old wxPython.wx namespace is removed then these | |
358 | compatibility classes will be removed too so you should plan on | |
359 | migrating to the new namespace and new DC Draw methods before that | |
360 | time. | |
d14a1e28 RD |
361 | |
362 | ||
363 | ||
364 | Building, Extending and Embedding wxPython | |
365 | ------------------------------------------ | |
366 | ||
367 | wxPython's setup.py script now expects to use existing libraries for | |
368 | the contribs (gizmos, stc, xrc, etc.) rather than building local | |
369 | copies of them. If you build your own copies of wxPython please be | |
370 | aware that you now need to also build the ogl, stc, xrc, and gizmos | |
29bfe46b | 371 | libraries in addition to the main wx lib. |
d14a1e28 RD |
372 | |
373 | The wxPython.h and other header files are now in | |
9ec83f8d RD |
374 | .../wxPython/include/wx/wxPython instead of in wxPython/src. You |
375 | should include it via the "wx/wxPython/wxPython.h" path and add | |
29bfe46b RD |
376 | .../wxPython/include to your list of include paths. On OSX and |
377 | unix-like systems the wxPython headers are installed to the same place | |
9ec83f8d RD |
378 | that the wxWidgets headers are installed, so if you are building |
379 | wxPython compatible extensions on those platforms then your include | |
380 | path should already be set properly. | |
29bfe46b RD |
381 | |
382 | If you are also using SWIG for your extension then you'll need to | |
383 | adapt how the wxPython .i files are imported into your .i files. See | |
384 | the wxPython sources for examples. Your modules will need to at least | |
385 | ``%import core.i``, and possibly others if you need the definition of | |
9ec83f8d RD |
386 | other classes. Since you will need them to build your modules using |
387 | SWIG, the main wxPython .i files are also installed with the wxPython | |
388 | headers in an i_files sibdirectory. It should be enough to pass a | |
389 | -I/pathname on the command line for SWIG to find the files. | |
29bfe46b RD |
390 | |
391 | The bulk of wxPython's setup.py has been moved to another module, | |
392 | wx/build/config.py. This module will be installed as part of wxPython | |
393 | so 3rd party modules that wish to use the same setup/configuration | |
394 | code can do so simply by importing this module from their own setup.py | |
395 | scripts using ``import wx.build.config``. | |
d14a1e28 RD |
396 | |
397 | You no longer need to call wxClassInfo::CleanUpClasses() and | |
398 | wxClassInfo::InitializeClasses() in your extensions or when embedding | |
399 | wxPython. | |
400 | ||
29bfe46b RD |
401 | The usage of wxPyBeginAllowThreads and wxPyEndAllowThreads has changed |
402 | slightly. wxPyBeginAllowThreads now returns a boolean value that must | |
403 | be passed to the coresponding wxPyEndAllowThreads function call. This | |
404 | is to help do the RightThing when calls to these two functions are | |
405 | nested, or if calls to external code in other extension modules that | |
406 | are wrapped in the standard Py_(BEGIN|END)_ALLOW_THERADS may result in | |
407 | wx event handlers being called (such as during the call to | |
408 | os.startfile.) | |
d14a1e28 RD |
409 | |
410 | ||
411 | ||
412 | Two (or Three!) Phase Create | |
413 | ---------------------------- | |
414 | ||
415 | If you use the Precreate/Create method of instantiating a window, (for | |
416 | example, to set an extended style flag, or for XRC handlers) then | |
417 | there is now a new method named PostCreate to help with transplanting | |
418 | the brain of the prewindow instance into the derived window instance. | |
419 | For example:: | |
420 | ||
421 | class MyDialog(wx.Dialog): | |
422 | def __init__(self, parent, ID, title, pos, size, style): | |
423 | pre = wx.PreDialog() | |
424 | pre.SetExtraStyle(wx.DIALOG_EX_CONTEXTHELP) | |
425 | pre.Create(parent, ID, title, pos, size, style) | |
426 | self.PostCreate(pre) | |
427 | ||
428 | ||
429 | ||
430 | Sizers | |
431 | ------ | |
432 | ||
e6a5dac6 | 433 | The hack allowing the old "option" keyword parameter has been removed. |
9ec83f8d | 434 | If you use keyword args with w.xSizer Add, Insert, or Prepend methods |
29bfe46b | 435 | then you will need to use the ``proportion`` name instead of ``option``. |
d14a1e28 | 436 | |
29bfe46b | 437 | When adding a spacer to a sizer you now need to use a wx.Size or a |
d14a1e28 | 438 | 2-integer sequence instead of separate width and height parameters. |
95fed4d8 RD |
439 | This allows for more consistency in how you add the various types of |
440 | items to a sizer. The first parameter defines the item (instead of | |
441 | the possibily first two, depending on if you are doing a spacer or | |
442 | not,) and that item can either be a window, a sizer or a spacer (which | |
443 | can be a sequence or a wx.Size.) | |
d14a1e28 | 444 | |
29bfe46b | 445 | The wx.GridBagSizer class (very similar to the RowColSizer in the |
d14a1e28 RD |
446 | library) has been added to C++ and wrapped for wxPython. It can also |
447 | be used from XRC. | |
448 | ||
449 | You should not use AddWindow, AddSizer, AddSpacer (and similar for | |
450 | Insert, Prepend, and etc.) methods any longer. Just use Add and the | |
451 | wrappers will figure out what to do. | |
452 | ||
95fed4d8 RD |
453 | **[Changed in 2.5.1.6]** wx.ADJUST_MINSIZE is now the default |
454 | behaviour for window items in sizers. This means that the item's | |
455 | GetAdjustedBestSize will be called when calculating layout and the | |
456 | return value from that will be used for the minimum size. Added | |
761b244f | 457 | wx.FIXED_MINSIZE flag for when you would like the old behavior but you |
95fed4d8 | 458 | should only need it when your desired size is smaller than the item's |
1980f3fa RD |
459 | GetBestSize. When a window is added to a sizer it's initial size, if |
460 | any, is set as the window's minimal size using SetSizeHints if there | |
461 | isn't already a minimal size. | |
95fed4d8 | 462 | |
d14a1e28 | 463 | |
dd346b94 RD |
464 | PlatformInfo |
465 | ------------ | |
466 | ||
467 | Added wx.PlatformInfo which is a tuple containing strings that | |
468 | describe the platform and build options of wxPython. This lets you | |
469 | know more about the build than just the __WXPORT__ value that | |
470 | wx.Platform contains, such as if it is a GTK2 build. For example, | |
471 | instead of:: | |
472 | ||
473 | if wx.Platform == "__WXGTK__": | |
474 | ... | |
475 | ||
476 | you should do this:: | |
477 | ||
478 | if "__WXGTK__" in wx.PlatformInfo: | |
479 | ... | |
480 | ||
481 | and you can specifically check for a wxGTK2 build by looking for | |
482 | "gtk2" in wx.PlatformInfo. Unicode builds are also detectable this | |
483 | way. If there are any other platform/toolkit/build flags that make | |
484 | sense to add to this tuple please let me know. | |
485 | ||
486 | BTW, wx.Platform will probably be deprecated in the future. | |
487 | ||
488 | ||
d14a1e28 | 489 | |
b7c75283 RD |
490 | ActiveX |
491 | ------- | |
492 | ||
493 | Lindsay Mathieson's newest wxActiveX_ class has been wrapped into a new | |
494 | extension module called wx.activex. It is very generic and dynamic | |
495 | and should allow hosting of arbitray ActiveX controls within your | |
496 | wxPython apps. So far I've tested it with IE, PDF, and Flash | |
497 | controls, (and there are new samples in the demo and also library | |
498 | modules supporting these.) | |
499 | ||
500 | .. _wxActiveX: http://members.optusnet.com.au/~blackpaw1/wxactivex.html | |
501 | ||
502 | The new wx.activex module contains a bunch of code, but the most | |
503 | important things to look at are ActiveXWindow and ActiveXEvent. | |
504 | ActiveXWindow derives from wxWindow and the constructor accepts a | |
505 | CLSID for the ActiveX Control that should be created. (There is also | |
506 | a CLSID class that can convert from a progID or a CLSID String.) The | |
507 | ActiveXWindow class simply adds methods that allow you to query some | |
508 | of the TypeInfo exposed by the ActiveX object, and also to get/set | |
509 | properties or call methods by name. The Python implementation | |
510 | automatically handles converting parameters and return values to/from | |
511 | the types expected by the ActiveX code as specified by the TypeInfo, | |
512 | (just bool, integers, floating point, strings and None/Empty so far, | |
513 | but more can be handled later.) | |
514 | ||
515 | That's pretty much all there is to the class, as I mentioned before it | |
516 | is very generic and dynamic. Very little is hard-coded and everything | |
517 | that is done with the actual ActiveX control is done at runtime and | |
518 | referenced by property or method name. Since Python is such a dynamic | |
519 | language this is a very good match. I thought for a while about doing | |
520 | some Python black-magic and making the specific methods/properties of | |
521 | the actual ActiveX control "appear" at runtime, but then decided that | |
522 | it would be better and more understandable to do it via subclassing. | |
523 | So there is a utility class in wx.activex that given an existing | |
524 | ActiveXWindow instance can generate a .py module containing a derived | |
525 | class with real methods and properties that do the Right Thing to | |
526 | reflect those calls to the real ActiveX control. There is also a | |
527 | script/tool module named genaxmodule that given a CLSID or progID and | |
528 | a class name, will generate the module for you. There are a few | |
b098694c | 529 | examples of the output of this tool in the wx.lib package, see |
b7c75283 RD |
530 | iewin.py, pdfwin.py and flashwin.py. |
531 | ||
532 | Currently the genaxmodule tool will tweak some of the names it | |
533 | generates, but this can be controled if you would like to do it | |
534 | differently by deriving your own class from GernerateAXModule, | |
535 | overriding some methods and then using this class from a tool like | |
536 | genaxmodule. [TODO: make specifying a new class on genaxmodule's | |
537 | command-line possible.] The current default behavior is that any | |
538 | event names that start with "On" will have the "On" dropped, property | |
539 | names are converted to all lower case, and if any name is a Python | |
540 | keyword it will have an underscore appended to it. GernerateAXModule | |
541 | does it's best when generating the code in the new module, but it can | |
542 | only be as good as the TypeInfo data available from the ActiveX | |
543 | control so sometimes some tweaking will be needed. For example, the | |
544 | IE web browser control defines the Flags parameter of the Navigate2 | |
545 | method as required, but MSDN says it is optional. | |
546 | ||
547 | It is intended that this new wx.activex module will replace both the | |
548 | older version of Lindsay's code available in iewin.IEHtmlWindow, and | |
549 | also the wx.lib.activexwraper module. Probably the biggest | |
b098694c | 550 | differences you'll ecounter in migrating activexwrapper-based code |
b7c75283 RD |
551 | (besides events working better without causing deadlocks) is that |
552 | events are no longer caught by overriding methods in your derived | |
553 | class. Instead ActiveXWindow uses the wx event system and you bind | |
554 | handlers for the ActiveX events exactly the same way you do for any wx | |
555 | event. There is just one extra step needed and that is creating an | |
556 | event ID from the ActiveX event name, and if you use the genaxmodule | |
557 | tool then this extra step will be handled for you there. For example, | |
558 | for the StatusTextChange event in the IE web browser control, this | |
559 | code is generated for you:: | |
560 | ||
561 | wxEVT_StatusTextChange = wx.activex.RegisterActiveXEvent('StatusTextChange') | |
562 | EVT_StatusTextChange = wx.PyEventBinder(wxEVT_StatusTextChange, 1) | |
563 | ||
564 | and you would use it in your code like this:: | |
565 | ||
566 | self.Bind(iewin.EVT_StatusTextChange, self.UpdateStatusText, self.ie) | |
567 | ||
568 | When the event happens and your event handler function is called the | |
569 | event properties from the ActiveX control (if any) are converted to | |
570 | attributes of the event object passed to the handler. (Can you say | |
571 | 'event' any more times in a single sentence? ;-) ) For example the | |
572 | StatusTextChange event will also send the text that should be put into | |
573 | the status line as an event parameter named "Text" and you can access | |
b098694c | 574 | it your handlers as an attribute of the event object like this:: |
b7c75283 RD |
575 | |
576 | def UpdateStatusText(self, evt): | |
577 | self.SetStatusText(evt.Text) | |
578 | ||
b098694c RD |
579 | Usually these event object attributes should be considered read-only, |
580 | but some will be defined by the TypeInfo as output parameters. In | |
581 | those cases if you modify the event object's attribute then that value | |
582 | will be returned to the ActiveX control. For example, to prevent a | |
583 | new window from being opened by the IE web browser control you can do | |
584 | this in the handler for the iewin.EVT_NewWindow2 event:: | |
585 | ||
586 | def OnNewWindow2(self, evt): | |
587 | evt.Cancel = True | |
b7c75283 | 588 | |
29bfe46b | 589 | So how do you know what methods, events and properties that an ActiveX |
b7c75283 RD |
590 | control supports? There is a funciton in wx.activex named GetAXInfo |
591 | that returns a printable summary of the TypeInfo from the ActiveX | |
592 | instance passed in. You can use this as an example of how to browse | |
593 | the TypeInfo provided, and there is also a copy of this function's | |
594 | output appended as a comment to the modules produced by the | |
595 | genaxmodule tool. Beyond that you'll need to consult the docs | |
596 | provided by the makers of the ActiveX control that you are using. | |
597 | ||
598 | ||
599 | ||
d14a1e28 RD |
600 | Other Stuff |
601 | ----------- | |
602 | ||
603 | Instead of over a dozen separate extension modules linked together | |
604 | into a single extension module, the "core" module is now just a few | |
605 | extensions that are linked independently, and then merged together | |
606 | later into the main namespace via Python code. | |
607 | ||
e6a5dac6 RD |
608 | Because of the above and also because of the way the new SWIG works, |
609 | the "internal" module names have changed, but you shouldn't have been | |
610 | using them anyway so it shouldn't bother you. ;-) | |
d14a1e28 | 611 | |
e6a5dac6 RD |
612 | The help module no longer exists and the classes therein are now part |
613 | of the core module imported with wxPython.wx or the wx package. | |
d14a1e28 RD |
614 | |
615 | wxPyDefaultPosition and wxPyDefaultSize are gone. Use the | |
616 | wxDefaultPosition and wxDefaultSize objects instead. | |
617 | ||
618 | Similarly, the wxSystemSettings backwards compatibiility aliases for | |
619 | GetSystemColour, GetSystemFont and GetSystemMetric have also gone into | |
620 | the bit-bucket. Use GetColour, GetFont and GetMetric instead. | |
621 | ||
622 | ||
ed8e1ecb RD |
623 | The wx.NO_FULL_REPAINT_ON_RESIZE style is now the default style for |
624 | all windows. The name still exists for compatibility, but it is set | |
625 | to zero. If you want to disable the setting (so it matches the old | |
626 | default) then you need to use the new wx.FULL_REPAINT_ON_RESIZE style | |
627 | flag otherwise only the freshly exposed areas of the window will be | |
628 | refreshed. | |
d14a1e28 | 629 | |
1f9b31fc RD |
630 | wxPyTypeCast has been removed. Since we've had the OOR (Original |
631 | Object Return) for a couple years now there should be no need to use | |
632 | wxPyTypeCast at all. | |
d14a1e28 | 633 | |
e6a5dac6 RD |
634 | If you use the old wxPython package and wxPython.wx namespace then |
635 | there are compatibility aliases for much of the above items. | |
78862f24 RD |
636 | |
637 | The wxWave class has been renamed to wxSound, and now has a slightly | |
638 | different API. | |
ce32c85b | 639 | |
45d67f33 RD |
640 | wx.TaskbarIcon works on wxGTK-based platforms now, however you have to |
641 | manage it a little bit more than you did before. Basically, the app | |
642 | will treat it like a top-level frame in that if the wx.TaskBarIcon | |
643 | still exists when all the frames are closed then the app will still | |
644 | not exit. You need to ensure that the wx.TaskBarIcon is destroyed | |
645 | when your last Frame is closed. For wxPython apps it is usually | |
646 | enough if your main frame object holds the only reference to the | |
647 | wx.TaskBarIcon, then when the frame is closed Python reference | |
648 | counting takes care of the rest. | |
649 | ||
33ab916f RD |
650 | Before Python 2.3 it was possible to pass a floating point object as a |
651 | parameter to a function that expected an integer, and the | |
652 | PyArg_ParseTuple family of functions would automatically convert to | |
653 | integer by truncating the fractional portion of the number. With | |
654 | Python 2.3 that behavior was deprecated and a deprecation warning is | |
655 | raised when you pass a floating point value, (for example, calling | |
656 | wx.DC.DrawLineXY with floats for the position and size,) and lots of | |
657 | developers using wxPython had to scramble to change their code to call | |
658 | int() before calling wxPython methods. Recent changes in SWIG have | |
659 | moved the conversion out of PyArg_ParseTuple to custom code that SWIG | |
660 | generates. Since the default conversion fragment was a little too | |
661 | strict and didn't generate a very meaningful exception when it failed, | |
662 | I decided to use a custom fragment instead, and it turned out that | |
663 | it's very easy to allow floats to be converted again just like they | |
664 | used to be. So, in a nutshell, any numeric type that can be | |
665 | converted to an integer is now legal to be passed to SWIG wrapped | |
666 | functions in wxPython for parameters that are expecting an integer. | |
667 | If the object is not already an integer then it will be asked to | |
668 | convert itself to one. A similar conversion fragment is in place for | |
669 | parameters that expect floating point values. |