]>
Commit | Line | Data |
---|---|---|
1 | ||
2 | from wxPython.wx import * | |
3 | from wxPython.html import * | |
4 | ||
5 | #---------------------------------------------------------------------- | |
6 | ||
7 | BTN1 = wxNewId() | |
8 | BTN2 = wxNewId() | |
9 | ||
10 | ||
11 | class TestPanel(wxPanel): | |
12 | def __init__(self, parent, log): | |
13 | wxPanel.__init__(self, parent, -1) | |
14 | self.log = log | |
15 | ||
16 | sizer = wxBoxSizer(wxVERTICAL) | |
17 | html = wxHtmlWindow(self, -1) | |
18 | html.SetPage(overview) | |
19 | sizer.Add(html, 1, wxEXPAND|wxALL, 5) | |
20 | ||
21 | btns = wxBoxSizer(wxHORIZONTAL) | |
22 | btns.Add(50, -1, 1, wxEXPAND) | |
23 | btn1 = wxButton(self, BTN1, "Find My Alter-ego") # don't save a ref to this one | |
24 | btns.Add(btn1) | |
25 | btns.Add(50, -1, 1, wxEXPAND) | |
26 | self.btn2 = wxButton(self, BTN2, "Find Myself") | |
27 | btns.Add(self.btn2) | |
28 | btns.Add(50, -1, 1, wxEXPAND) | |
29 | ||
30 | sizer.Add(btns, 0, wxEXPAND|wxALL, 15) | |
31 | ||
32 | self.SetSizer(sizer) | |
33 | self.SetAutoLayout(true) | |
34 | ||
35 | EVT_BUTTON(self, BTN1, self.OnFindButton1) | |
36 | EVT_BUTTON(self, BTN2, self.OnFindButton2) | |
37 | ||
38 | ||
39 | def OnFindButton1(self, evt): | |
40 | win = self.FindWindowById(BTN1) | |
41 | if win is None: | |
42 | self.log.write("***** OOPS! None returned...\n") | |
43 | return | |
44 | className = win.__class__.__name__ | |
45 | if className in ["wxButton", "wxButtonPtr"]: | |
46 | self.log.write("The types are the same! <grin>\n") | |
47 | else: | |
48 | self.log.write("Got %s, expected wxButton or wxButtonPtr\n" % className) | |
49 | ||
50 | ||
51 | ||
52 | def OnFindButton2(self, evt): | |
53 | win = self.FindWindowById(BTN2) | |
54 | if win is None: | |
55 | self.log.write("***** OOPS! None returned...\n") | |
56 | return | |
57 | if win is self.btn2: | |
58 | self.log.write("The objects are the same! <grin>\n") | |
59 | else: | |
60 | self.log.write("The objects are NOT the same! <frown>\n") | |
61 | ||
62 | ||
63 | #---------------------------------------------------------------------- | |
64 | ||
65 | def runTest(frame, nb, log): | |
66 | win = TestPanel(nb, log) | |
67 | return win | |
68 | ||
69 | #---------------------------------------------------------------------- | |
70 | ||
71 | ||
72 | overview = """\ | |
73 | <html><body> | |
74 | <h2>Original Object Return</h2> | |
75 | ||
76 | <p>Several methods in wxWindows return pointers to base class objects, | |
77 | when in fact the actual object pointed to is of a derived type. Since | |
78 | SWIG isn't able to tell the actual type it just creates a new Python | |
79 | shadow object of the base type to wrap around the base type pointer | |
80 | and returns it. | |
81 | ||
82 | <p>In wxPython this can cause annoying issues. For example if you | |
83 | call: | |
84 | ||
85 | <pre> | |
86 | ||
87 | myText = someWindow.FindWindowById(txtID) | |
88 | </pre> | |
89 | ||
90 | expecting to get a wxTextCtrl you will actually get a wxWindow object | |
91 | instead. If you then try to call SetValue on that object you'll get | |
92 | an exception since there is no such method. This is the reason for | |
93 | the wxPyTypeCast hack that has been in wxPython for so long. | |
94 | ||
95 | <p>Even with wxPyTypeCast there is the issue that the object returned | |
96 | is not the same one that was created in Python originally, but a new | |
97 | object of the same type that wraps the same C++ pointer. If the | |
98 | programmer has set additional attributes of that original object they | |
99 | will not exist in the new object. | |
100 | ||
101 | <p>For a long time now I have wanted to do away with wxPyTypeCast and | |
102 | also find a way to return the original Python object from methods like | |
103 | FindWindowById. This project naturally divides into two phases: | |
104 | ||
105 | <p><ol> | |
106 | ||
107 | <li>Teach the wrapper methods how to return objects of the right type, | |
108 | and be able to then turn wxPyTypeCast in to a no-op. | |
109 | ||
110 | <li>Be able to return the original Python shadow object if it still exists. | |
111 | ||
112 | </ol> | |
113 | ||
114 | <p>The first button below shows the first of these phases (<i>working</i>) | |
115 | and the second will show #2 (<i>not yet working.</i>) | |
116 | ||
117 | </body></html> | |
118 | """ |