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