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 //----------------------------------------------------------------------
72 MyFrame
*frame
= new MyFrame(_T("Embedded wxPython Test"),
73 wxPoint(50, 50), wxSize(700, 600));
79 void MyApp::Init_wxPython()
85 // Load the wxPython core API. Imports the wxPython.wxc
86 // module and sets a pointer to a function table located there.
89 // Save the current Python thread state and release the
90 // Global Interpreter Lock.
91 m_mainTState
= wxPyBeginAllowThreads();
97 // Restore the thread state and tell Python to cleanup after itself.
98 wxPyEndAllowThreads(m_mainTState
);
104 //----------------------------------------------------------------------
113 BEGIN_EVENT_TABLE(MyFrame
, wxFrame
)
114 EVT_MENU(ID_EXIT
, MyFrame::OnExit
)
115 EVT_MENU(ID_PYFRAME
, MyFrame::OnPyFrame
)
120 MyFrame::MyFrame(const wxString
& title
, const wxPoint
& pos
, const wxSize
& size
)
121 : wxFrame(NULL
, -1, title
, pos
, size
,
122 wxDEFAULT_FRAME_STYLE
|wxNO_FULL_REPAINT_ON_RESIZE
)
124 SetIcon(wxICON(mondrian
));
126 wxMenuBar
* mbar
= new wxMenuBar
;
127 wxMenu
* menu
= new wxMenu
;
128 menu
->Append(ID_PYFRAME
, _T("Make wx&Python frame"));
129 menu
->AppendSeparator();
130 menu
->Append(ID_EXIT
, _T("&Close Frame\tAlt-X"));
131 mbar
->Append(menu
, _T("&File"));
137 // Make some child windows from C++
138 wxSplitterWindow
* sp
= new wxSplitterWindow(this, -1);
139 wxPanel
* p1
= new wxPanel(sp
, -1);
140 p1
->SetFont(wxFont(12, wxSWISS
, wxNORMAL
, wxBOLD
));
141 new wxStaticText(p1
, -1,
142 _T("The frame, menu, splitter, this panel and this text were created in C++..."),
145 // And get a panel from Python
146 wxWindow
* p2
= DoPythonStuff(sp
);
148 sp
->SplitHorizontally(p1
, p2
, GetClientSize().y
/4);
151 void MyFrame::OnExit(wxCommandEvent
& event
)
157 //----------------------------------------------------------------------
158 // This is where the fun begins...
161 char* python_code1
= "\
162 from wxPython.wx import wxFrame\n\
163 f = wxFrame(None, -1, 'Hello from wxPython!', size=(250, 150))\n\
167 void MyFrame::OnPyFrame(wxCommandEvent
& event
)
169 // For simple Python code that doesn't have to interact with the
170 // C++ code in any way, you can execute it with PyRun_SimpleString.
173 // First, whenever you do anyting with Python objects or code, you
174 // *MUST* aquire the Global Interpreter Lock and block other
175 // Python threads from running.
176 bool blocked
= wxPyBeginBlockThreads();
178 // Execute the code in the __main__ module
179 PyRun_SimpleString(python_code1
);
181 // Finally, release the GIL and let other Python threads run.
182 wxPyEndBlockThreads(blocked
);
186 void MyFrame::RedirectStdio()
188 // This is a helpful little tidbit to help debugging and such. It
189 // redirects Python's stdout and stderr to a window that will popup
190 // only on demand when something is printed, like a traceback.
191 char* python_redirect
= "\
193 from wxPython.wx import wxPyOnDemandOutputWindow\n\
194 output = wxPyOnDemandOutputWindow()\n\
195 sys.stdin = sys.stderr = output\n\
197 bool blocked
= wxPyBeginBlockThreads();
198 PyRun_SimpleString(python_redirect
);
199 wxPyEndBlockThreads(blocked
);
205 char* python_code2
= "\
206 import embedded_sample\n\
208 def makeWindow(parent):\n\
209 win = embedded_sample.MyPanel(parent)\n\
213 wxWindow
* MyFrame::DoPythonStuff(wxWindow
* parent
)
215 // More complex embedded situations will require passing C++ objects to
216 // Python and/or returning objects from Python to be used in C++. This
217 // sample shows one way to do it. NOTE: The above code could just have
218 // easily come from a file, or the whole thing could be in the Python
219 // module that is imported and manipulated directly in this C++ code. See
220 // the Python API for more details.
222 wxWindow
* window
= NULL
;
225 // As always, first grab the GIL
226 bool blocked
= wxPyBeginBlockThreads();
228 // Now make a dictionary to serve as the global namespace when the code is
229 // executed. Put a reference to the builtins module in it. (Yes, the
230 // names are supposed to be different, I don't know why...)
231 PyObject
* globals
= PyDict_New();
232 PyObject
* builtins
= PyImport_ImportModule("__builtin__");
233 PyDict_SetItemString(globals
, "__builtins__", builtins
);
236 // Execute the code to make the makeWindow function
237 result
= PyRun_String(python_code2
, Py_file_input
, globals
, globals
);
238 // Was there an exception?
241 wxPyEndBlockThreads(blocked
);
246 // Now there should be an object named 'makeWindow' in the dictionary that
247 // we can grab a pointer to:
248 PyObject
* func
= PyDict_GetItemString(globals
, "makeWindow");
249 wxASSERT(PyCallable_Check(func
));
251 // Now build an argument tuple and call the Python function. Notice the
252 // use of another wxPython API to take a wxWindows object and build a
253 // wxPython object that wraps it.
254 PyObject
* arg
= wxPyMake_wxObject(parent
);
255 wxASSERT(arg
!= NULL
);
257 PyObject
* tuple
= PyTuple_New(1);
258 PyTuple_SET_ITEM(tuple
, 0, arg
);
259 result
= PyEval_CallObject(func
, tuple
);
261 // Was there an exception?
265 // Otherwise, get the returned window out of Python-land and
267 bool success
= wxPyConvertSwigPtr(result
, (void**)&window
, _T("wxWindow"));
268 wxASSERT_MSG(success
, _T("Returned object was not a wxWindow!"));
272 // Release the python objects we still have
276 // Finally, after all Python stuff is done, release the GIL
277 wxPyEndBlockThreads(blocked
);
283 //----------------------------------------------------------------------