]> git.saurik.com Git - wxWidgets.git/blame - wxPython/samples/embedded/embedded.cpp
HandlePrintClient shouldn't go above a top-level window
[wxWidgets.git] / wxPython / samples / embedded / embedded.cpp
CommitLineData
a2426843
RD
1//----------------------------------------------------------------------
2// Name: embedded.cpp
248834a0 3// Purpose: To serve as an example of how to use wxPython from
a2426843
RD
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
6b7e0a86
RD
14#include <Python.h>
15
16
a2426843
RD
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
6b7e0a86
RD
35#include <wx/wxPython/wxPython.h>
36
a2426843
RD
37
38//----------------------------------------------------------------------
39// Class definitions
40
41class MyApp : public wxApp
42{
43public:
44 virtual bool OnInit();
0625ef68
RD
45 virtual int OnExit();
46 bool Init_wxPython();
6b7e0a86
RD
47private:
48 PyThreadState* m_mainTState;
a2426843
RD
49};
50
51
52class MyFrame : public wxFrame
53{
54public:
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
61private:
62 DECLARE_EVENT_TABLE()
63};
64
65//----------------------------------------------------------------------
66// MyApp methods
67
68
69bool MyApp::OnInit()
70{
0625ef68
RD
71 if ( !Init_wxPython() )
72 // don't start the app if we can't initialize wxPython.
73 return false;
74
a2426843 75 MyFrame *frame = new MyFrame(_T("Embedded wxPython Test"),
0625ef68
RD
76 wxDefaultPosition, wxSize(700, 600));
77 frame->Show(true);
78 return true;
a2426843
RD
79}
80
81
0625ef68
RD
82
83bool MyApp::Init_wxPython()
a2426843
RD
84{
85 // Initialize Python
86 Py_Initialize();
87 PyEval_InitThreads();
88
0625ef68
RD
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
a2426843
RD
99 // Save the current Python thread state and release the
100 // Global Interpreter Lock.
6b7e0a86 101 m_mainTState = wxPyBeginAllowThreads();
0625ef68
RD
102
103 return true;
a2426843
RD
104}
105
106
0625ef68 107int MyApp::OnExit()
a2426843
RD
108{
109 // Restore the thread state and tell Python to cleanup after itself.
0625ef68
RD
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.
6b7e0a86 113 wxPyEndAllowThreads(m_mainTState);
a2426843 114 Py_Finalize();
0625ef68 115 return 0;
a2426843
RD
116}
117
2620b36e 118
a2426843
RD
119IMPLEMENT_APP(MyApp)
120
121//----------------------------------------------------------------------
122
123enum
124{
125 ID_EXIT=1001,
126 ID_PYFRAME
127};
128
129
130BEGIN_EVENT_TABLE(MyFrame, wxFrame)
5d26a7e6
RD
131 EVT_MENU(ID_EXIT, MyFrame::OnExit)
132 EVT_MENU(ID_PYFRAME, MyFrame::OnPyFrame)
a2426843
RD
133END_EVENT_TABLE()
134
135
136
137MyFrame::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;
6b7e0a86 145 menu->Append(ID_PYFRAME, _T("Make wx&Python frame"));
a2426843 146 menu->AppendSeparator();
6b7e0a86
RD
147 menu->Append(ID_EXIT, _T("&Close Frame\tAlt-X"));
148 mbar->Append(menu, _T("&File"));
a2426843
RD
149 SetMenuBar(mbar);
150
151 CreateStatusBar();
152 RedirectStdio();
153
154 // Make some child windows from C++
155 wxSplitterWindow* sp = new wxSplitterWindow(this, -1);
0625ef68
RD
156 wxPanel* p1 = new wxPanel(sp, -1, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER);
157
a2426843 158 new wxStaticText(p1, -1,
6b7e0a86 159 _T("The frame, menu, splitter, this panel and this text were created in C++..."),
a2426843
RD
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
168void MyFrame::OnExit(wxCommandEvent& event)
169{
170 Close();
171}
172
173
174//----------------------------------------------------------------------
6b7e0a86 175// This is where the fun begins...
a2426843
RD
176
177
178char* python_code1 = "\
2620b36e
RD
179import wx\n\
180f = wx.Frame(None, -1, 'Hello from wxPython!', size=(250, 150))\n\
a2426843
RD
181f.Show()\n\
182";
183
184void 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
0625ef68 190 // First, whenever you do anything with Python objects or code, you
a2426843
RD
191 // *MUST* aquire the Global Interpreter Lock and block other
192 // Python threads from running.
6e6b3557 193 wxPyBlock_t blocked = wxPyBeginBlockThreads();
a2426843
RD
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.
da32eb53 199 wxPyEndBlockThreads(blocked);
a2426843
RD
200}
201
202
203void 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 = "\
209import sys\n\
2620b36e
RD
210import wx\n\
211output = wx.PyOnDemandOutputWindow()\n\
a2426843
RD
212sys.stdin = sys.stderr = output\n\
213";
6e6b3557 214 wxPyBlock_t blocked = wxPyBeginBlockThreads();
a2426843 215 PyRun_SimpleString(python_redirect);
da32eb53 216 wxPyEndBlockThreads(blocked);
a2426843
RD
217}
218
219
220
221
222char* python_code2 = "\
b8a42834
RD
223import sys\n\
224sys.path.append('.')\n\
a2426843
RD
225import embedded_sample\n\
226\n\
227def makeWindow(parent):\n\
228 win = embedded_sample.MyPanel(parent)\n\
229 return win\n\
230";
231
232wxWindow* 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
a9f4542f 237 // easily come from a file, or the whole thing could be in the Python
a2426843
RD
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
6e6b3557 245 wxPyBlock_t blocked = wxPyBeginBlockThreads();
a2426843
RD
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();
6b7e0a86 260 wxPyEndBlockThreads(blocked);
a2426843
RD
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);
274 wxASSERT(arg != NULL);
a2426843
RD
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...
6b7e0a86
RD
285 bool success = wxPyConvertSwigPtr(result, (void**)&window, _T("wxWindow"));
286 wxASSERT_MSG(success, _T("Returned object was not a wxWindow!"));
a2426843
RD
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
da32eb53 295 wxPyEndBlockThreads(blocked);
a2426843
RD
296
297 return window;
298}
299
300
301//----------------------------------------------------------------------
302
303
304
305
306
307