Files
Phoenix/docs/MigrationGuide.txt
Robin Dunn 443c6590d2 Fix typo
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@73874 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2013-04-28 05:07:51 +00:00

447 lines
19 KiB
Plaintext

========================================
wxPython Project Phoenix Migration Guide
========================================
wxPython's Project Phoenix is a new incarnation of the wxPython
toolkit in which everything that existed before will be cast into the
flames in the hopes that that which emerges from the ashes will be
better, brighter, stronger and faster than before. For more details
about why and how, please see the ProjectPhoenix_ pages in the
wiki.
.. _ProjectPhoenix: http://wiki.wxpython.org/ProjectPhoenix
This document will describe some of the incompatibilities that
programmers will run into when migrating code from Classic wxPython to
the Phoenix. For some types of changes there won't be any attempt to
document the nitty gritty details of the differences, but rather the
general patterns of the changes will be documented. Most proggrammers
should then be able to work out the details for themselves.
Overloaded Functions
--------------------
In order to support more than one of the versions of an overloaded C++
function or class method in Classic wxPython, we had to rename all but
one of them. For example, for the wxWindow::SetSize method we have
SetSize, SetDimensions, SetRect and SetSizeWH. One of the features of
the new tools used for Project Pheonix is that we no longer need to do
that and instead we can have just one function or method in the Python
API and the propper version of the C++ function or method is chosen at
runtime based on the types of parameters passed to the function. So
in most cases the renamed versions of the overloaded functions have
been removed and you can call the function with the same name as the
C++ API.
This also includes the default constructor for all widget classes,
used for the 2-phase create. Previously they were renamed to to be the
class name with "Pre" prepended to it. For example, wx.PreWindow(),
wx.PreFrame(), etc. Now in the Phoenix build of wxPython that is no
longer neccessary and you can just call the class with no parameters
like normal.
For those renamed items that are more commonly used in the old
wxPython I'll add some alias that will issue a DeprecationWarning for
the first release or two after we switch over to the Phoenix version
of the code, and then remove them in a later release.
For a (relatively comprehensive) list of classes, functions and methods
which need modification while porting your code from Classic to Phoenix,
please see the :ref:`Classic vs. Phoenix <classic vs phoenix>` document.
Static Methods
--------------
In the distant past when SWIG was generating wrapper code for C++ static
methods it would create a standalone function named ClassName_MethodName for
it. When Python added support for static methods then SWIG was able to use
that to make a real static method named ClassName.MethodName, but it still
generated the standalone function named with the underscore, for
compatibility. That underscore version of the static methods is now gone, and
you will get an AttributeError in existing code that is using them. To fix
the problem simply change the underscore to a dot, for example you should
change this::
c = wx.SystemSettings_GetColour(wx.SYS_COLOUR_MENUTEXT)
to this::
c = wx.SystemSettings.GetColour(wx.SYS_COLOUR_MENUTEXT)
You can also make this change in your existing code that is using pre-Phoenix
versions of wxPython, in order to help you prepare for the transition.
Unicode and Auto-Converting Strings
-----------------------------------
Starting with the wxPython 2.9 release series, there are no longer
separate ansi/Unicode builds of wxPython. All wxPython builds are now
essentially the same as the old Unicode builds. This means that all
string objects passed to wx API functions or methods are converted to
Unicode before calling the C++ function or method. By default CLassic
wxPython would use the encoding specified by the locale that was
current at the time of the import of the wx module.
However using the default locale could sometimes cause issues because
it meant that slightly different encodings could be used on different
platforms, even in the same locale, or the program could end up using
an encoding in a different locale that the developer has not tested
their code with.
Project Phoenix takes this Unicode simplification one step further by
stipulating that only the utf-8 encoding will be used for
auto-converting string objects to the Unicode objects that will be
passed on to the wx APIs. If you need to deal with text using a
different encoding then you will need to convert it to Unicode
yourself before passing the text to the wx API. For the most part this
should not be much of a problem for well written programs that support
Unicode because they will typically only convert to/from Unicode when
reading/writing text to a file or database, and will use Unicode objects
throughout the rest of the code. The common exception to this is that
string-literals are often used in the code for specifying labels,
etc. for UI elements. If your text for the string literals in your
code are all ascii or utf-8 then you should not need to make any
changes at all. If you have literals with some other encoding then
you'll need to deal with them one way or another, either change the
encoding of your source file to utf-8, or convert the literals from
your encoding to Unicode before passing the text to the wx API.
Font, Pen, and Brush Styles
---------------------------
The following aliases are currently added for backwards compatiblity,
but will be removed in a future release. You should migrate any code
that is using the old names to use the new ones instead::
wx.DEFAULT = wx.FONTFAMILY_DEFAULT
wx.DECORATIVE = wx.FONTFAMILY_DECORATIVE
wx.ROMAN = wx.FONTFAMILY_ROMAN
wx.SCRIPT = wx.FONTFAMILY_SCRIPT
wx.SWISS = wx.FONTFAMILY_SWISS
wx.MODERN = wx.FONTFAMILY_MODERN
wx.TELETYPE = wx.FONTFAMILY_TELETYPE
wx.NORMAL = wx.FONTWEIGHT_NORMAL
wx.LIGHT = wx.FONTWEIGHT_LIGHT
wx.BOLD = wx.FONTWEIGHT_BOLD
wx.NORMAL = wx.FONTSTYLE_NORMAL
wx.ITALIC = wx.FONTSTYLE_ITALIC
wx.SLANT = wx.FONTSTYLE_SLANT
wx.SOLID = wx.PENSTYLE_SOLID
wx.DOT = wx.PENSTYLE_DOT
wx.LONG_DASH = wx.PENSTYLE_LONG_DASH
wx.SHORT_DASH = wx.PENSTYLE_SHORT_DASH
wx.DOT_DASH = wx.PENSTYLE_DOT_DASH
wx.USER_DASH = wx.PENSTYLE_USER_DASH
wx.TRANSPARENT = wx.PENSTYLE_TRANSPARENT
wx.STIPPLE_MASK_OPAQUE = wx.BRUSHSTYLE_STIPPLE_MASK_OPAQUE
wx.STIPPLE_MASK = wx.BRUSHSTYLE_STIPPLE_MASK
wx.STIPPLE = wx.BRUSHSTYLE_STIPPLE
wx.BDIAGONAL_HATCH = wx.BRUSHSTYLE_BDIAGONAL_HATCH
wx.CROSSDIAG_HATCH = wx.BRUSHSTYLE_CROSSDIAG_HATCH
wx.FDIAGONAL_HATCH = wx.BRUSHSTYLE_FDIAGONAL_HATCH
wx.CROSS_HATCH = wx.BRUSHSTYLE_CROSS_HATCH
wx.HORIZONTAL_HATCH = wx.BRUSHSTYLE_HORIZONTAL_HATCH
wx.VERTICAL_HATCH = wx.BRUSHSTYLE_VERTICAL_HATCH
wx.PyDeadObjectError --> RuntimeError
-------------------------------------
Classic wxPython tracks when the C++ part of some types of objects (pretty
much just window types) is destroyed and then replaces the proxy object's
class with one that raises a wx.PyDeadObjectError exception. SIP takes care of
that for us now in a much better way, so that custom hack is no longer
present in Phoenix, however a RuntimeError is the exception that is raised
now. The wx.Window class has a __nonzero__ method that tests if the C++
object has been deleted, so you can still test the window with an if or other
conditional statement to see if it is safe to use, like this::
if someWindow:
someWindow.doSomething()
wx.PyAssertionError --> wx.wxAssertionError
-------------------------------------------
This is the exception raised when one of the wxASSERT (or similar) statements
in the wx C++ code fails. Since it is a wxWidgets assertion and not a
wxPython assertion the name was changed to make that a little more clear. A
compatibility alias exists so using wx.PyAssertionError will still work, but
you should migrate those uses to wx.wxAssertionError if possible.
The 'wx' namespace and submodules reorganized
---------------------------------------------
Some reorganization of what classes and functions goes in which internal wx
extension module has been done. In Classic the organization of the extension
modules was somewhat haphazard and chaotic. For example there were 5 separate
modules whose contents were loaded into the main "wx" package namespace and
several others that needed to be imported separately. However since there was
not much organization of the core the C++ wxadv and wxhtml DLLs would need to
be distributed with any applications built with a bundling tool even if the
application did not use any of those classes.
For Phoenix the location of the wrapper code for the classes and functions
will attempt to follow the same organization that wxWidgets uses for putting
those same classes and functions into DLLs or shared libraries. This means
that some things that were formerly in the core wx package namespace are no
longer there. They will have to be used by importing a wx submodule. Most of
them will be in the wx.adv module. One nice advantage of doing this is that
if your application is not using any of these lesser used classes then you
will not have to bundle the new modules (nor the associated wx DLLs) with
your application when you use py2exe or other executable builder.
wx.ListCtrl
-----------
* In wx.ListItem and wx.ListEvent the ``"m_"`` properties are no longer
public. Instead use the associated getter/setter methods or the
auto-generated properties that are using them.
wx.TreeCtrl
-----------
* The GetItemData and SetItemData now behave just like GetItemPyData
and SetItemPyData did in Classic wxPython. In other words, instead
of needing to create and use instances of wx.TreeItemData to
associate Python data objects with tree items, you just use the
Python objects directly. It will also work when passing the data
objects directly to the AppendItem, InsertItem, etc. methods. (If
anybody was actually using the wx.TreeItemData objects directly
before and are unable to adapt then please let Robin know.) The
[G|S]etItemPyData members still exist, but are now deprecated
aliases for [G|S]etItemData.
wx.DragImage
------------
Phoenix is providing both wx.DragImage and wx.GenericDragImage classes.
Classic wxPython only provided wx.DragImage, but it was actually using
wx.GenericDragImage internally for all platforms. wx.DragImage will now be a
native implementation on Windows, and will still be the generic version
elsewhere. If you would rather use the generic implementation on Windows too
then switch to using the wx.GenericDragImage class name.
2-Phase Create
--------------
In Classic wxPython we had to do some fancy footwork to make use of
wxWidget's 2-Phase Create scheme for creating instances of a C++ widget
class, but delaying the creation of the UI object until later. (This is
needed for things like setting extended style flags that can not be set after
creation, or with class factories like XRC.) The old trickery should no
longer be needed, and instead you can write code that is much more sane. For
example, instead of Classic code like this::
class MyDialog(wx.Dialog):
def __init__(self, parent, ID, title):
pre = wx.PreDialog()
pre.SetExtraStyle(wx.FRAME_EX_CONTEXTHELP)
pre.Create(parent, ID, title)
self.PostCreate(pre) # 4
In Phoenix that should now be done like this::
class MyDialog(wx.Dialog):
def __init__(self, parent, ID, title):
wx.Dialog.__init__(self) # 1
self.SetExtraStyle(wx.FRAME_EX_CONTEXTHELP) # 2
self.Create(parent, ID, title) # 3
Notice that we are (#1) calling the base class __init__ like usual,
but passing no parameters so the default C++ constructor will be
invoked. Next (#2, #3) we use self instead of pre because self is now
a legitimate instance of wx.Dialog, and (#4) there is no longer any
need to call PostCreate to do its black magic for us because there is
no longer a rogue instance that needs to be transplanted into self.
wx.Image and Python Buffer Objects
----------------------------------
wx.Image is now using the new buffer APIs for the constructors and
methods which accept any object supporting the buffer protocol. These
are methods which allow you to set the raw RGB or Alpha data in the
image in one step. As a consequence of using the new APIs the objects
passed must also implement the new buffer interface in order to be
compatible.
GetData and GetAlpha now return a copy of the image data as a
bytearray object instead of a string object. This means that since
bytearrays are mutable you can do things like make changes to the data
and then use it in the SetData of another image.
GetDataBuffer and GetAlphaBuffer now return memoryview objects, which
allow direct access to the RGB and Alpha buffers inside the image.
Just as in Classic you should not use those memoryview buffers after
the wx.Image has been destroyed. Using the returned memoryview object
you can manipulate the RGB or Alpha data inside the wx.Image without
needing to make a copy of the data.
Just as in Classic the SetDataBuffer and SetAlphaBuffer methods allow
you to tell the wx.Image to use memory buffers in other objects (such
as a numpy array) as its RGB or Alpha data, as long as the other
object supports the new buffer protocol.
wx.DropSource
-------------
We don't (yet) have an easy way to support different APIs per platform
in the wx class constructors, so wx.DropSource (which optionally takes
parameters that should be a wx.Icon on wxGTK or a wx.Cursor on the
other platforms) has been changed to not accept the cursor/icon in the
constructors. Instead you'll have to call either SetCursor or SetIcon
depending on the platform.
wx.DataObject and derived classes
---------------------------------
The wx.DataObject and wx.DataObjectSimple classes can now be
subclassed in Python. wx.DataObject will let you proivide complex
multi-format data objects that do not need to copy the data until one
of the formats is requested from the clipboard or a DnD operation.
wx.DataObjectSimple is a simplification that only deals with one data
format, (although multiple objects can still be provided with
wx.DataObjectComposite.)
Python buffer objects are used for transferring data to/from the
clipboard or DnD partner. Anything that supports the buffer protocol
can be used for setting or providing data, and a memoryview object is
created for the APIs where the data object should fetch from or copy
to a specific memory location. Here is a simple example::
class MyDataObject(wx.DataObjectSimple):
def __init__(self, value=''):
wx.DataObjectSimple.__init__(self)
self.SetFormat(wx.DataFormat("my data format"))
self.myData = bytes(value)
def GetDataSize(self):
return len(self.myData)
def GetDataHere(self, buf):
# copy our local data value to buf
assert isinstance(buf, memoryview)
buf[:] = self.myData
return True
def SetData(self, buf):
# copy from buf to our local data value
assert isinstance(buf, memoryview)
self.myData = buf.tobytes()
return True
Multiple Inheritance
--------------------
The SIP tool currently does not support having more than one wrapped
C++ class as the base classes of a Python class. In most cases this
is not a problem because in wxPython you're more likely to use
multiple inheritance with simple mix-in classes or similar constructs
than needing to inherit from more than one wx class.
However there is at least one use case where that can be a problem,
and that is with the ComboCtrl's wx.ComboPopup class. In wxWidgets
and also in Classic wxPython you're encouraged to use wx.ComboPopup as
a mix-in class combined with the widget class that is going to be
your popup window for the wx.ComboCtrl. This can not currently be
done with Phoenix in the same way, but you can also use a widget class
with a wx.ComboPopup in a has-a relationship rather than an is-a
relationship. See samples/combo/combo1.py for an example.
XRC
-------
The "LoadOnFoo" methods of the XmlResource class were renamed overloads of
the coresponding "LoadFoo" methods. Since we no longer need to rename
overloaded methods the "LoadOn" version has been removed and you should just
use the "LoadFoo" version instead. These methods are used to load some XRC
content onto an existing window, such as a Frame, instead of creating a new
Frame for the content.
wx.PyEvent and wx.PyCommandEvent
--------------------------------
Unlike some other wx.Py classes these two still exist in Phoenix, and are
still the base classes that you should use when creating your own custom
event classes. For the most part they work just like they did in Classic, and
they take care of ensuring that any Python attributes that you assign to
instances of the class will still be there when the event is delivered to an
event handler. There is one main difference from Classic however, and that is
that those attributes are now stored in a dictionary object owned by the C++
instance, instead of being stored directly in the Python instance's
dictionary. In most cases this won't matter to you at all, but if your
derived class has a __getattr__ method (or __setattr__ or __delattr__) then
you will need to get the attributes from that other dictionary instead. You
can get a reference to that dictionary using _getAttrDict(). For example::
def __getattr__(self, name):
d = self._getAttrDict()
if name in d:
return d[name]
return getattr(self._someOtherThing, name)
MakeModal
---------
Since it is usually not a good idea to make arbitrary top-level windows be
modal, (you should just use a wx.Dialog instead,) the MakeModal method has
been removed. The recommended alternative is to use the wx.WindowDisabler
class instead, but if you prefer the semenatics of having a method to call to
turn on or off the modalness of a window then you can add a method like this
to your classes to give you a way to do it::
def MakeModal(self, modal=True):
if modal and not hasattr(self, '_disabler'):
self._disabler = wx.WindowDisabler(self)
if not modal and hasattr(self, '_disabler'):
del self._disabler
.. toctree::
:maxdepth: 2
:hidden:
classic_vs_phoenix