]>
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 | |
7 | those changes. Be sure to also check in the CHANGES.txt file like | |
8 | usual to see info about the not so major changes and other things that | |
9 | have been added to wxPython. | |
10 | ||
11 | ||
12 | ||
13 | Module Initialization | |
14 | --------------------- | |
15 | ||
16 | The import-startup-bootstrap process employed by wxPython was changed | |
17 | such that wxWindows and the underlying gui toolkit are **not** | |
18 | initialized until the wx.App object is created (but before wx.App.OnInit | |
19 | is called.) This was required because of some changes that were made | |
20 | to the C++ wxApp class. | |
21 | ||
22 | There are both benefits and potential problems with this change. The | |
23 | benefits are that you can import wxPython without requiring access to | |
24 | a GUI (for checking version numbers, etc.) and that in a | |
25 | multi-threaded environment the thread that creates the app object will | |
26 | now be the GUI thread instead of the one that imports wxPython. Some | |
27 | potential problems are that the C++ side of the "stock-objects" | |
28 | (wx.BLUE_PEN, wx.TheColourDatabase, etc.) are not initialized until | |
29 | the wx.App object is created, so you should not use them until after | |
30 | you have created your wx.App object. (In fact, until I find a better | |
31 | solution trying to use one of the stock objects before the app is | |
32 | created will probably result in a crash.) | |
33 | ||
34 | Also, you will probably not be able to do any kind of GUI or bitmap | |
35 | operation unless you first have created an app object, (even on | |
36 | Windows where most anything was possible before.) | |
37 | ||
38 | ||
39 | ||
40 | SWIG 1.3 | |
41 | -------- | |
42 | ||
43 | wxPython is now using SWIG 1.3.x from CVS (with several of my own | |
44 | customizations added that I hope to get folded back into the main SWIG | |
45 | distribution.) This has some far reaching ramifications: | |
46 | ||
47 | All classes derive from object and so all are now "new-style | |
48 | classes" | |
49 | ||
50 | Public data members of the C++ classes are wrapped as Python | |
51 | properties using property() instead of using __getattr__/__setattr__ | |
52 | like before. Normally you shouldn't notice any difference, but if | |
53 | you were previously doing something with __getattr__/__setattr__ | |
54 | in derived classes then you may have to adjust things. | |
55 | ||
56 | Static C++ methods are wrapped using the staticmethod() | |
57 | feature of Python and so are accessible as ClassName.MethodName | |
58 | as expected. They are still available as top level functions | |
59 | ClassName_MethodName as before. | |
60 | ||
61 | The relationship between the wxFoo and wxFooPtr classes have | |
62 | changed for the better. Specifically, all instances that you see | |
63 | will be wxFoo even if they are created internally using wxFooPtr, | |
64 | because wxFooPtr.__init__ will change the instance's __class__ as | |
65 | part of the initialization. If you have any code that checks | |
66 | class type using something like isinstance(obj, wxFooPtr) you will | |
67 | need to change it to isinstance(obj, wxFoo). | |
68 | ||
69 | ||
70 | ||
71 | Binding Events | |
72 | -------------- | |
73 | ||
74 | All of the EVT_* functions are now instances of the wx.PyEventBinder | |
75 | class. They have a __call__ method so they can still be used as | |
76 | functions like before, but making them instances adds some | |
77 | flexibility. | |
78 | ||
79 | wx.EvtHandler (the base class for wx.Window) now has a Bind method that | |
80 | makes binding events to windows a little easier. Here is its | |
81 | definition and docstring:: | |
82 | ||
83 | def Bind(self, event, handler, source=None, id=wxID_ANY, id2=wxID_ANY): | |
84 | """ | |
85 | Bind an event to an event handler. | |
86 | ||
87 | event One of the EVT_* objects that specifies the | |
88 | type of event to bind. | |
89 | ||
90 | handler A callable object to be invoked when the event | |
91 | is delivered to self. Pass None to disconnect an | |
92 | event handler. | |
93 | ||
94 | source Sometimes the event originates from a different window | |
95 | than self, but you still want to catch it in self. (For | |
96 | example, a button event delivered to a frame.) By | |
97 | passing the source of the event, the event handling | |
98 | system is able to differentiate between the same event | |
99 | type from different controls. | |
100 | ||
101 | id,id2 Used for menu IDs or for event types that require a | |
102 | range of IDs | |
103 | ||
104 | """ | |
105 | ||
106 | Some examples of its use:: | |
107 | ||
108 | self.Bind(wx.EVT_SIZE, self.OnSize) | |
109 | self.Bind(wx.EVT_BUTTON, self.OnButtonClick, theButton) | |
110 | self.Bind(wx.EVT_MENU, self.OnExit, id=ID_EXIT) | |
111 | ||
112 | I hope to be able to remove the need for using IDs even for menu | |
113 | events too... | |
114 | ||
115 | If you create your own custom event types and EVT_* functions, and you | |
116 | want to be able to use them with the Bind method above then you should | |
117 | change your EVT_* to be an instance of wxPyEventBinder instead of a | |
118 | function. If you used to have something like this:: | |
119 | ||
120 | myCustomEventType = wxNewEventType() | |
121 | def EVT_MY_CUSTOM_EVENT(win, id, func): | |
122 | win.Connect(id, -1, myCustomEventType, func) | |
123 | ||
124 | ||
125 | Change it like so:: | |
126 | ||
127 | myCustomEventType = wxNewEventType() | |
128 | EVT_MY_CUSTOM_EVENT = wxPyEventBinder(myCustomEventType, 1) | |
129 | ||
130 | The second parameter is an integer in [0, 1, 2] that specifies the | |
131 | number of IDs that are needed to be passed to Connect. | |
132 | ||
133 | ||
134 | ||
135 | The wx Namespace | |
136 | ---------------- | |
137 | ||
138 | The second phase of the wx Namespace Transition has begun. That means | |
139 | that the real names of the classes and other symbols do not have the | |
140 | 'wx' prefix and the modules are located in a Python package named | |
141 | wx. There is still a Python package named wxPython with modules | |
142 | that have the names with the wx prefix for backwards compatibility. | |
143 | Instead of dynamically changing the names at module load time like in | |
144 | 2.4, the compatibility modules are generated at build time and contain | |
145 | assignment statements like this:: | |
146 | ||
147 | wxWindow = wx.core.Window | |
148 | ||
149 | Don't let the "core" in the name bother you. That and some other | |
150 | modules are implementation details, and everything that was in the | |
151 | wxPython.wx module before will still be in the wx package namespace | |
152 | after this change. So from your code you would use it as wx.Window. | |
153 | ||
154 | A few notes about how all of this was accomplished might be | |
155 | interesting... SWIG is now run twice for each module that it is | |
156 | generating code for. The first time it outputs an XML representaion | |
157 | of the parse tree, which can be up to 20MB and 300K lines in size! | |
158 | That XML is then run through a little Python script that creates a | |
159 | file full of SWIG %rename directives that take the wx off of the | |
160 | names, and also generates the Python compatibility file described | |
161 | above that puts the wx back on the names. SWIG is then run a second | |
162 | time to generate the C++ code to implement the extension module, and | |
163 | uses the %rename directives that were generated in the first step. | |
164 | ||
165 | Not every name is handled correctly (but the bulk of them are) and so | |
166 | some work has to be done by hand, especially for the reverse-renamers. | |
167 | So expect a few flaws here and there until everything gets sorted out. | |
168 | ||
169 | In summary, the wx package and names without the "wx" prefix are now | |
170 | the official form of the wxPython classes. For example:: | |
171 | ||
172 | import wx | |
173 | ||
174 | class MyFrame(wx.Frame): | |
175 | def __init__(self, parent, title): | |
176 | wx.Frame.__init__(self, parent, -1, title) | |
177 | p = wx.Panel(self, -1) | |
178 | b = wx.Button(p, -1, "Do It", (10,10)) | |
179 | self.Bind(wx.EVT_BUTTON, self.JustDoIt, b) | |
180 | ||
181 | def JustDoIt(self, evt): | |
182 | print "It's done!" | |
183 | ||
184 | app = wx.PySimpleApp() | |
185 | f = MyFrame(None, "What's up?") | |
186 | f.Show() | |
187 | app.MainLoop() | |
188 | ||
189 | You shouldn't need to migrate all your modules over to use the new | |
190 | package and names right away as there are modules in place that try to | |
191 | provide as much backwards compatibility of the names as possible. If | |
192 | you rewrote the above sample using "from wxPython.wx import *", the | |
193 | old wxNames, and the old style of event binding it will still work | |
194 | just fine. | |
195 | ||
196 | ||
197 | ||
198 | ||
199 | New wx.DC Methods | |
200 | ----------------- | |
201 | ||
202 | Many of the Draw methods of wx.DC have alternate forms in C++ that take | |
203 | wxPoint or wxSize parameters (let's call these *Type A*) instead of | |
204 | the individual x, y, width, height, etc. parameters (and we'll call | |
205 | these *Type B*). In the rest of the library I normally made the *Type | |
206 | A* forms of the methods be the default method with the "normal" name, | |
207 | and had renamed the *Type B* forms of the methods to some similar | |
208 | name. For example in wx.Window we have these Python methods:: | |
209 | ||
210 | SetSize(size) # Type A | |
211 | SetSizeWH(width, height) # Type B | |
212 | ||
213 | ||
214 | For various reasons the new *Type A* methods in wx.DC were never added | |
215 | and the existing *Type B* methods were never renamed. Now that lots | |
216 | of other things are also changing in wxPython it has been decided that | |
217 | it is a good time to also do the method renaming in wx.DC too in order | |
218 | to be consistent with the rest of the library. The methods in wx.DC | |
219 | that are affected are listed here:: | |
220 | ||
221 | FloodFillXY(x, y, colour, style = wx.FLOOD_SURFACE) | |
222 | FloodFill(point, colour, style = wx.FLOOD_SURFACE) | |
223 | ||
224 | GetPixelXY(x, y) | |
225 | GetPixel(point) | |
226 | ||
227 | DrawLineXY(x1, y1, x2, y2) | |
228 | DrawLine(point1, point2) | |
229 | ||
230 | CrossHairXY(x, y) | |
231 | CrossHair(point) | |
232 | ||
233 | DrawArcXY(x1, y1, x2, y2, xc, yc) | |
234 | DrawArc(point1, point2, center) | |
235 | ||
236 | DrawCheckMarkXY(x, y, width, height) | |
237 | DrawCheckMark(rect) | |
238 | ||
239 | DrawEllipticArcXY(x, y, w, h, start_angle, end_angle) | |
240 | DrawEllipticArc(point, size, start_angle, end_angle) | |
241 | ||
242 | DrawPointXY(x, y) | |
243 | DrawPoint(point) | |
244 | ||
245 | DrawRectangleXY(x, y, width, height) | |
246 | DrawRectangle(point, size) | |
247 | DrawRectangleRect(rect) | |
248 | ||
249 | DrawRoundedRectangleXY(x, y, width, height, radius) | |
250 | DrawRoundedRectangle(point, size, radius) | |
251 | DrawRoundedRectangleRect(rect, radius) | |
252 | ||
253 | DrawCircleXY(x, y, radius) | |
254 | DrawCircle(point, radius) | |
255 | ||
256 | DrawEllipseXY(x, y, width, height) | |
257 | DrawEllipse(point, size) | |
258 | DrawEllipseRect(rect) | |
259 | ||
260 | DrawIconXY(icon, x, y) | |
261 | DrawIcon(icon, point) | |
262 | ||
263 | DrawBitmapXY(bmp, x, y, useMask = FALSE) | |
264 | DrawBitmap(bmp, point, useMask = FALSE) | |
265 | ||
266 | DrawTextXY(text, x, y) | |
267 | DrawText(text, point) | |
268 | ||
269 | DrawRotatedTextXY(text, x, y, angle) | |
270 | DrawRotatedText(text, point, angle) | |
271 | ||
272 | ||
273 | BlitXY(xdest, ydest, width, height, sourceDC, xsrc, ysrc, | |
274 | rop = wxCOPY, useMask = FALSE, xsrcMask = -1, ysrcMask = -1) | |
275 | Blit(destPt, size, sourceDC, srcPt, | |
276 | rop = wxCOPY, useMask = FALSE, srcPtMask = wx.DefaultPosition) | |
277 | ||
4da6d35e RD |
278 | SetClippingRegionXY SetClippingRegion(x, y, width, height) |
279 | SetClippingRegion(point, size) | |
280 | SetClippingRect(rect) | |
281 | SetClippingRegionAsRegion(region); | |
282 | ||
d14a1e28 RD |
283 | |
284 | If you have code that draws on a DC you **will** get errors because of | |
285 | these changes, but it should be easy to fix the code. You can either | |
286 | change the name of the *Type B* method called to the names shown | |
287 | above, or just add parentheses around the parameters as needed to turn | |
288 | them into tuples and let the SWIG typemaps turn them into the wx.Point | |
289 | or wx.Size object that is expected. Then you will be calling the new | |
290 | *Type A* method. For example, if you had this code before:: | |
291 | ||
292 | dc.DrawRectangle(x, y, width, height) | |
293 | ||
294 | You could either continue to use the *Type B* method bu changing the | |
295 | name to DrawRectabgleXY, or just change it to the new *Type A* by | |
296 | adding some parentheses like this:: | |
297 | ||
298 | dc.DrawRectangle((x, y), (width, height)) | |
299 | ||
300 | Or if you were already using a point and size:: | |
301 | ||
302 | dc.DrawRectangle(p.x, p.y, s.width, s.height) | |
303 | ||
304 | Then you can just simplify it like this:: | |
305 | ||
306 | dc.DrawRectangle(p, s) | |
307 | ||
308 | ||
309 | ||
310 | ||
311 | Building, Extending and Embedding wxPython | |
312 | ------------------------------------------ | |
313 | ||
314 | wxPython's setup.py script now expects to use existing libraries for | |
315 | the contribs (gizmos, stc, xrc, etc.) rather than building local | |
316 | copies of them. If you build your own copies of wxPython please be | |
317 | aware that you now need to also build the ogl, stc, xrc, and gizmos | |
318 | libraries in addition to the main wx lib. [[TODO: update the | |
319 | BUILD.*.txt files too!]] | |
320 | ||
321 | The wxPython.h and other header files are now in | |
322 | .../wxPython/include/wx/wxPython instead of in wxPython/src. You should | |
323 | include it via the "wx/wxPython/wxPython.h" path and add | |
324 | .../wxPython/include to your list of include paths. [[TODO: Install | |
325 | these headers on Linux...]] | |
326 | ||
327 | You no longer need to call wxClassInfo::CleanUpClasses() and | |
328 | wxClassInfo::InitializeClasses() in your extensions or when embedding | |
329 | wxPython. | |
330 | ||
331 | ||
332 | ||
333 | ||
334 | Two (or Three!) Phase Create | |
335 | ---------------------------- | |
336 | ||
337 | If you use the Precreate/Create method of instantiating a window, (for | |
338 | example, to set an extended style flag, or for XRC handlers) then | |
339 | there is now a new method named PostCreate to help with transplanting | |
340 | the brain of the prewindow instance into the derived window instance. | |
341 | For example:: | |
342 | ||
343 | class MyDialog(wx.Dialog): | |
344 | def __init__(self, parent, ID, title, pos, size, style): | |
345 | pre = wx.PreDialog() | |
346 | pre.SetExtraStyle(wx.DIALOG_EX_CONTEXTHELP) | |
347 | pre.Create(parent, ID, title, pos, size, style) | |
348 | self.PostCreate(pre) | |
349 | ||
350 | ||
351 | ||
352 | Sizers | |
353 | ------ | |
354 | ||
355 | The hack allowing the old "option" keyword parameter has been | |
356 | removed. If you use keyworkd args with wxSizer Add, Insert, or | |
357 | Prepend then you will need to use the "proportion" name instead of | |
358 | "option". | |
359 | ||
360 | When adding a spacer to a sizer you now need to use a wxSize or a | |
361 | 2-integer sequence instead of separate width and height parameters. | |
362 | ||
363 | The wxGridBagSizer class (very similar to the RowColSizer in the | |
364 | library) has been added to C++ and wrapped for wxPython. It can also | |
365 | be used from XRC. | |
366 | ||
367 | You should not use AddWindow, AddSizer, AddSpacer (and similar for | |
368 | Insert, Prepend, and etc.) methods any longer. Just use Add and the | |
369 | wrappers will figure out what to do. | |
370 | ||
371 | ||
372 | ||
373 | Other Stuff | |
374 | ----------- | |
375 | ||
376 | Instead of over a dozen separate extension modules linked together | |
377 | into a single extension module, the "core" module is now just a few | |
378 | extensions that are linked independently, and then merged together | |
379 | later into the main namespace via Python code. | |
380 | ||
381 | Because of the above, the "internal" module names have changed, but | |
382 | you shouldn't have been using them anyway so it shouldn't bother | |
383 | you. ;-) | |
384 | ||
385 | The wxPython.help module no longer exists and the classes therein are | |
386 | now part of the core module imported with wxPython.wx or the wx | |
387 | package. | |
388 | ||
389 | wxPyDefaultPosition and wxPyDefaultSize are gone. Use the | |
390 | wxDefaultPosition and wxDefaultSize objects instead. | |
391 | ||
392 | Similarly, the wxSystemSettings backwards compatibiility aliases for | |
393 | GetSystemColour, GetSystemFont and GetSystemMetric have also gone into | |
394 | the bit-bucket. Use GetColour, GetFont and GetMetric instead. | |
395 | ||
396 | ||
ed8e1ecb RD |
397 | The wx.NO_FULL_REPAINT_ON_RESIZE style is now the default style for |
398 | all windows. The name still exists for compatibility, but it is set | |
399 | to zero. If you want to disable the setting (so it matches the old | |
400 | default) then you need to use the new wx.FULL_REPAINT_ON_RESIZE style | |
401 | flag otherwise only the freshly exposed areas of the window will be | |
402 | refreshed. | |
d14a1e28 | 403 | |
1f9b31fc RD |
404 | wxPyTypeCast has been removed. Since we've had the OOR (Original |
405 | Object Return) for a couple years now there should be no need to use | |
406 | wxPyTypeCast at all. | |
d14a1e28 | 407 |