1 //----------------------------------------------------------------------
3 // Purpose: To serve as an example of how to use wxPython from
4 // within a C++ wxWindows program.
10 // Copyright: (c) 2002 by Total Control Software
11 // Licence: wxWindows license
12 //----------------------------------------------------------------------
17 // For compilers that support precompilation, includes "wx/wx.h".
18 #include <wx/wxprec.h>
28 #include <wx/splitter.h>
30 #if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXMGL__)
31 #include "mondrian.xpm"
34 // Import Python and wxPython headers
35 #include <wx/wxPython/wxPython.h>
38 //----------------------------------------------------------------------
41 class MyApp
: public wxApp
44 virtual bool OnInit();
48 PyThreadState
* m_mainTState
;
52 class MyFrame
: public wxFrame
55 MyFrame(const wxString
& title
, const wxPoint
& pos
, const wxSize
& size
);
57 wxWindow
* DoPythonStuff(wxWindow
* parent
);
58 void OnExit(wxCommandEvent
& event
);
59 void OnPyFrame(wxCommandEvent
& event
);
65 //----------------------------------------------------------------------
71 if ( !Init_wxPython() )
72 // don't start the app if we can't initialize wxPython.
75 MyFrame
*frame
= new MyFrame(_T("Embedded wxPython Test"),
76 wxDefaultPosition
, wxSize(700, 600));
83 bool MyApp::Init_wxPython()
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! *****"));
99 // Save the current Python thread state and release the
100 // Global Interpreter Lock.
101 m_mainTState
= wxPyBeginAllowThreads();
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
113 wxPyEndAllowThreads(m_mainTState
);
121 //----------------------------------------------------------------------
130 BEGIN_EVENT_TABLE(MyFrame
, wxFrame
)
131 EVT_MENU(ID_EXIT
, MyFrame::OnExit
)
132 EVT_MENU(ID_PYFRAME
, MyFrame::OnPyFrame
)
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
)
141 SetIcon(wxICON(mondrian
));
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"));
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
);
158 new wxStaticText(p1
, -1,
159 _T("The frame, menu, splitter, this panel and this text were created in C++..."),
162 // And get a panel from Python
163 wxWindow
* p2
= DoPythonStuff(sp
);
165 sp
->SplitHorizontally(p1
, p2
, GetClientSize().y
/4);
168 void MyFrame::OnExit(wxCommandEvent
& event
)
174 //----------------------------------------------------------------------
175 // This is where the fun begins...
178 char* python_code1
= "\
180 f = wx.Frame(None, -1, 'Hello from wxPython!', size=(250, 150))\n\
184 void MyFrame::OnPyFrame(wxCommandEvent
& event
)
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.
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();
195 // Execute the code in the __main__ module
196 PyRun_SimpleString(python_code1
);
198 // Finally, release the GIL and let other Python threads run.
199 wxPyEndBlockThreads(blocked
);
203 void MyFrame::RedirectStdio()
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
= "\
211 output = wx.PyOnDemandOutputWindow()\n\
212 sys.stdin = sys.stderr = output\n\
214 wxPyBlock_t blocked
= wxPyBeginBlockThreads();
215 PyRun_SimpleString(python_redirect
);
216 wxPyEndBlockThreads(blocked
);
222 char* python_code2
= "\
224 sys.path.append('.')\n\
225 import embedded_sample\n\
227 def makeWindow(parent):\n\
228 win = embedded_sample.MyPanel(parent)\n\
232 wxWindow
* MyFrame::DoPythonStuff(wxWindow
* parent
)
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.
241 wxWindow
* window
= NULL
;
244 // As always, first grab the GIL
245 wxPyBlock_t blocked
= wxPyBeginBlockThreads();
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
);
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?
260 wxPyEndBlockThreads(blocked
);
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
));
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
);
279 // Was there an exception?
283 // Otherwise, get the returned window out of Python-land and
285 bool success
= wxPyConvertSwigPtr(result
, (void**)&window
, _T("wxWindow"));
286 wxASSERT_MSG(success
, _T("Returned object was not a wxWindow!"));
290 // Release the python objects we still have
294 // Finally, after all Python stuff is done, release the GIL
295 wxPyEndBlockThreads(blocked
);
301 //----------------------------------------------------------------------