]> git.saurik.com Git - wxWidgets.git/blob - wxPython/samples/embedded/embedded.cpp
updated
[wxWidgets.git] / wxPython / samples / embedded / embedded.cpp
1 //----------------------------------------------------------------------
2 // Name: embedded.cpp
3 // Purpose: To serve as an example of how to use wxPython from
4 // within a C++ wxWindows program.
5 //
6 // Author: Robin Dunn
7 //
8 // Created: 1-May-2002
9 // RCS-ID: $Id$
10 // Copyright: (c) 2002 by Total Control Software
11 // Licence: wxWindows license
12 //----------------------------------------------------------------------
13
14 #include <Python.h>
15
16
17 // For compilers that support precompilation, includes "wx/wx.h".
18 #include <wx/wxprec.h>
19
20 #ifdef __BORLANDC__
21 #pragma hdrstop
22 #endif
23
24 #ifndef WX_PRECOMP
25 #include <wx/wx.h>
26 #endif
27
28 #include <wx/splitter.h>
29
30 #if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXMGL__)
31 #include "mondrian.xpm"
32 #endif
33
34 // Import Python and wxPython headers
35 #include <wx/wxPython/wxPython.h>
36
37
38 //----------------------------------------------------------------------
39 // Class definitions
40
41 class MyApp : public wxApp
42 {
43 public:
44 virtual bool OnInit();
45 virtual int OnExit();
46 bool Init_wxPython();
47 private:
48 PyThreadState* m_mainTState;
49 };
50
51
52 class MyFrame : public wxFrame
53 {
54 public:
55 MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
56 void RedirectStdio();
57 wxWindow* DoPythonStuff(wxWindow* parent);
58 void OnExit(wxCommandEvent& event);
59 void OnPyFrame(wxCommandEvent& event);
60
61 private:
62 DECLARE_EVENT_TABLE()
63 };
64
65 //----------------------------------------------------------------------
66 // MyApp methods
67
68
69 bool MyApp::OnInit()
70 {
71 if ( !Init_wxPython() )
72 // don't start the app if we can't initialize wxPython.
73 return false;
74
75 MyFrame *frame = new MyFrame(_T("Embedded wxPython Test"),
76 wxDefaultPosition, wxSize(700, 600));
77 frame->Show(true);
78 return true;
79 }
80
81
82
83 bool MyApp::Init_wxPython()
84 {
85 // Initialize Python
86 Py_Initialize();
87 PyEval_InitThreads();
88
89 // Load the wxPython core API. Imports the wx._core_ module and sets a
90 // local pointer to a function table located there. The pointer is used
91 // internally by the rest of the API functions.
92 if ( ! wxPyCoreAPI_IMPORT() ) {
93 wxLogError(wxT("***** Error importing the wxPython API! *****"));
94 PyErr_Print();
95 Py_Finalize();
96 return false;
97 }
98
99 // Save the current Python thread state and release the
100 // Global Interpreter Lock.
101 m_mainTState = wxPyBeginAllowThreads();
102
103 return true;
104 }
105
106
107 int MyApp::OnExit()
108 {
109 // Restore the thread state and tell Python to cleanup after itself.
110 // wxPython will do its own cleanup as part of that process. This is done
111 // in OnExit instead of ~MyApp because OnExit is only called if OnInit is
112 // successful.
113 wxPyEndAllowThreads(m_mainTState);
114 Py_Finalize();
115 return 0;
116 }
117
118
119 IMPLEMENT_APP(MyApp)
120
121 //----------------------------------------------------------------------
122
123 enum
124 {
125 ID_EXIT=1001,
126 ID_PYFRAME
127 };
128
129
130 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
131 EVT_MENU(ID_EXIT, MyFrame::OnExit)
132 EVT_MENU(ID_PYFRAME, MyFrame::OnPyFrame)
133 END_EVENT_TABLE()
134
135
136
137 MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
138 : wxFrame(NULL, -1, title, pos, size,
139 wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE)
140 {
141 SetIcon(wxICON(mondrian));
142
143 wxMenuBar* mbar = new wxMenuBar;
144 wxMenu* menu = new wxMenu;
145 menu->Append(ID_PYFRAME, _T("Make wx&Python frame"));
146 menu->AppendSeparator();
147 menu->Append(ID_EXIT, _T("&Close Frame\tAlt-X"));
148 mbar->Append(menu, _T("&File"));
149 SetMenuBar(mbar);
150
151 CreateStatusBar();
152 RedirectStdio();
153
154 // Make some child windows from C++
155 wxSplitterWindow* sp = new wxSplitterWindow(this, -1);
156 wxPanel* p1 = new wxPanel(sp, -1, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
157
158 new wxStaticText(p1, -1,
159 _T("The frame, menu, splitter, this panel and this text were created in C++..."),
160 wxPoint(10,10));
161
162 // And get a panel from Python
163 wxWindow* p2 = DoPythonStuff(sp);
164
165 sp->SplitHorizontally(p1, p2, GetClientSize().y/4);
166 }
167
168 void MyFrame::OnExit(wxCommandEvent& event)
169 {
170 Close();
171 }
172
173
174 //----------------------------------------------------------------------
175 // This is where the fun begins...
176
177
178 char* python_code1 = "\
179 import wx\n\
180 f = wx.Frame(None, -1, 'Hello from wxPython!', size=(250, 150))\n\
181 f.Show()\n\
182 ";
183
184 void MyFrame::OnPyFrame(wxCommandEvent& event)
185 {
186 // For simple Python code that doesn't have to interact with the
187 // C++ code in any way, you can execute it with PyRun_SimpleString.
188
189
190 // First, whenever you do anything with Python objects or code, you
191 // *MUST* aquire the Global Interpreter Lock and block other
192 // Python threads from running.
193 wxPyBlock_t blocked = wxPyBeginBlockThreads();
194
195 // Execute the code in the __main__ module
196 PyRun_SimpleString(python_code1);
197
198 // Finally, release the GIL and let other Python threads run.
199 wxPyEndBlockThreads(blocked);
200 }
201
202
203 void MyFrame::RedirectStdio()
204 {
205 // This is a helpful little tidbit to help debugging and such. It
206 // redirects Python's stdout and stderr to a window that will popup
207 // only on demand when something is printed, like a traceback.
208 char* python_redirect = "\
209 import sys\n\
210 import wx\n\
211 output = wx.PyOnDemandOutputWindow()\n\
212 sys.stdin = sys.stderr = output\n\
213 ";
214 wxPyBlock_t blocked = wxPyBeginBlockThreads();
215 PyRun_SimpleString(python_redirect);
216 wxPyEndBlockThreads(blocked);
217 }
218
219
220
221
222 char* python_code2 = "\
223 import sys\n\
224 sys.path.append('.')\n\
225 import embedded_sample\n\
226 \n\
227 def makeWindow(parent):\n\
228 win = embedded_sample.MyPanel(parent)\n\
229 return win\n\
230 ";
231
232 wxWindow* MyFrame::DoPythonStuff(wxWindow* parent)
233 {
234 // More complex embedded situations will require passing C++ objects to
235 // Python and/or returning objects from Python to be used in C++. This
236 // sample shows one way to do it. NOTE: The above code could just have
237 // easily come from a file, or the whole thing could be in the Python
238 // module that is imported and manipulated directly in this C++ code. See
239 // the Python API for more details.
240
241 wxWindow* window = NULL;
242 PyObject* result;
243
244 // As always, first grab the GIL
245 wxPyBlock_t blocked = wxPyBeginBlockThreads();
246
247 // Now make a dictionary to serve as the global namespace when the code is
248 // executed. Put a reference to the builtins module in it. (Yes, the
249 // names are supposed to be different, I don't know why...)
250 PyObject* globals = PyDict_New();
251 PyObject* builtins = PyImport_ImportModule("__builtin__");
252 PyDict_SetItemString(globals, "__builtins__", builtins);
253 Py_DECREF(builtins);
254
255 // Execute the code to make the makeWindow function
256 result = PyRun_String(python_code2, Py_file_input, globals, globals);
257 // Was there an exception?
258 if (! result) {
259 PyErr_Print();
260 wxPyEndBlockThreads(blocked);
261 return NULL;
262 }
263 Py_DECREF(result);
264
265 // Now there should be an object named 'makeWindow' in the dictionary that
266 // we can grab a pointer to:
267 PyObject* func = PyDict_GetItemString(globals, "makeWindow");
268 wxASSERT(PyCallable_Check(func));
269
270 // Now build an argument tuple and call the Python function. Notice the
271 // use of another wxPython API to take a wxWindows object and build a
272 // wxPython object that wraps it.
273 PyObject* arg = wxPyMake_wxObject(parent, false);
274 wxASSERT(arg != NULL);
275 PyObject* tuple = PyTuple_New(1);
276 PyTuple_SET_ITEM(tuple, 0, arg);
277 result = PyEval_CallObject(func, tuple);
278
279 // Was there an exception?
280 if (! result)
281 PyErr_Print();
282 else {
283 // Otherwise, get the returned window out of Python-land and
284 // into C++-ville...
285 bool success = wxPyConvertSwigPtr(result, (void**)&window, _T("wxWindow"));
286 wxASSERT_MSG(success, _T("Returned object was not a wxWindow!"));
287 Py_DECREF(result);
288 }
289
290 // Release the python objects we still have
291 Py_DECREF(globals);
292 Py_DECREF(tuple);
293
294 // Finally, after all Python stuff is done, release the GIL
295 wxPyEndBlockThreads(blocked);
296
297 return window;
298 }
299
300
301 //----------------------------------------------------------------------