]> git.saurik.com Git - wxWidgets.git/blame_incremental - wxPython/samples/embedded/embedded.cpp
Noted where the documentation was
[wxWidgets.git] / wxPython / samples / embedded / embedded.cpp
... / ...
CommitLineData
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
38class MyApp : public wxApp
39{
40public:
41 virtual bool OnInit();
42 virtual ~MyApp();
43 void Init_wxPython();
44private:
45 PyThreadState* m_mainTState;
46};
47
48
49class MyFrame : public wxFrame
50{
51public:
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
58private:
59 DECLARE_EVENT_TABLE()
60};
61
62//----------------------------------------------------------------------
63// MyApp methods
64
65
66bool 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
76void 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
98MyApp::~MyApp()
99{
100 // Restore the thread state and tell Python to cleanup after itself.
101 wxPyEndAllowThreads(m_mainTState);
102 Py_Finalize();
103}
104
105IMPLEMENT_APP(MyApp)
106
107//----------------------------------------------------------------------
108
109enum
110{
111 ID_EXIT=1001,
112 ID_PYFRAME
113};
114
115
116BEGIN_EVENT_TABLE(MyFrame, wxFrame)
117 EVT_MENU(ID_EXIT, MyFrame::OnExit)
118 EVT_MENU(ID_PYFRAME, MyFrame::OnPyFrame)
119END_EVENT_TABLE()
120
121
122
123MyFrame::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
154void MyFrame::OnExit(wxCommandEvent& event)
155{
156 Close();
157}
158
159
160//----------------------------------------------------------------------
161// This is were the fun begins...
162
163
164char* python_code1 = "\
165from wxPython.wx import wxFrame\n\
166f = wxFrame(None, -1, 'Hello from wxPython!', size=(250, 150))\n\
167f.Show()\n\
168";
169
170void 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
189void 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 = "\
195import sys\n\
196from wxPython.wx import wxPyOnDemandOutputWindow\n\
197output = wxPyOnDemandOutputWindow()\n\
198sys.stdin = sys.stderr = output\n\
199";
200 wxPyBeginBlockThreads();
201 PyRun_SimpleString(python_redirect);
202 wxPyEndBlockThreads();
203}
204
205
206
207
208char* python_code2 = "\
209import embedded_sample\n\
210\n\
211def makeWindow(parent):\n\
212 win = embedded_sample.MyPanel(parent)\n\
213 return win\n\
214";
215
216wxWindow* 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