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 wx._core module and sets a
86 // local 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 // wxPython will do its own cleanup as part of that process.
99 wxPyEndAllowThreads(m_mainTState
);
106 //----------------------------------------------------------------------
115 BEGIN_EVENT_TABLE(MyFrame
, wxFrame
)
116 EVT_MENU(ID_EXIT
, MyFrame::OnExit
)
117 EVT_MENU(ID_PYFRAME
, MyFrame::OnPyFrame
)
122 MyFrame::MyFrame(const wxString
& title
, const wxPoint
& pos
, const wxSize
& size
)
123 : wxFrame(NULL
, -1, title
, pos
, size
,
124 wxDEFAULT_FRAME_STYLE
|wxNO_FULL_REPAINT_ON_RESIZE
)
126 SetIcon(wxICON(mondrian
));
128 wxMenuBar
* mbar
= new wxMenuBar
;
129 wxMenu
* menu
= new wxMenu
;
130 menu
->Append(ID_PYFRAME
, _T("Make wx&Python frame"));
131 menu
->AppendSeparator();
132 menu
->Append(ID_EXIT
, _T("&Close Frame\tAlt-X"));
133 mbar
->Append(menu
, _T("&File"));
139 // Make some child windows from C++
140 wxSplitterWindow
* sp
= new wxSplitterWindow(this, -1);
141 wxPanel
* p1
= new wxPanel(sp
, -1);
142 p1
->SetFont(wxFont(12, wxSWISS
, wxNORMAL
, wxBOLD
));
143 new wxStaticText(p1
, -1,
144 _T("The frame, menu, splitter, this panel and this text were created in C++..."),
147 // And get a panel from Python
148 wxWindow
* p2
= DoPythonStuff(sp
);
150 sp
->SplitHorizontally(p1
, p2
, GetClientSize().y
/4);
153 void MyFrame::OnExit(wxCommandEvent
& event
)
159 //----------------------------------------------------------------------
160 // This is where the fun begins...
163 char* python_code1
= "\
165 f = wx.Frame(None, -1, 'Hello from wxPython!', size=(250, 150))\n\
169 void MyFrame::OnPyFrame(wxCommandEvent
& event
)
171 // For simple Python code that doesn't have to interact with the
172 // C++ code in any way, you can execute it with PyRun_SimpleString.
175 // First, whenever you do anyting with Python objects or code, you
176 // *MUST* aquire the Global Interpreter Lock and block other
177 // Python threads from running.
178 bool blocked
= wxPyBeginBlockThreads();
180 // Execute the code in the __main__ module
181 PyRun_SimpleString(python_code1
);
183 // Finally, release the GIL and let other Python threads run.
184 wxPyEndBlockThreads(blocked
);
188 void MyFrame::RedirectStdio()
190 // This is a helpful little tidbit to help debugging and such. It
191 // redirects Python's stdout and stderr to a window that will popup
192 // only on demand when something is printed, like a traceback.
193 char* python_redirect
= "\
196 output = wx.PyOnDemandOutputWindow()\n\
197 sys.stdin = sys.stderr = output\n\
199 bool blocked
= wxPyBeginBlockThreads();
200 PyRun_SimpleString(python_redirect
);
201 wxPyEndBlockThreads(blocked
);
207 char* python_code2
= "\
208 import embedded_sample\n\
210 def makeWindow(parent):\n\
211 win = embedded_sample.MyPanel(parent)\n\
215 wxWindow
* MyFrame::DoPythonStuff(wxWindow
* parent
)
217 // More complex embedded situations will require passing C++ objects to
218 // Python and/or returning objects from Python to be used in C++. This
219 // sample shows one way to do it. NOTE: The above code could just have
220 // easily come from a file, or the whole thing could be in the Python
221 // module that is imported and manipulated directly in this C++ code. See
222 // the Python API for more details.
224 wxWindow
* window
= NULL
;
227 // As always, first grab the GIL
228 bool blocked
= wxPyBeginBlockThreads();
230 // Now make a dictionary to serve as the global namespace when the code is
231 // executed. Put a reference to the builtins module in it. (Yes, the
232 // names are supposed to be different, I don't know why...)
233 PyObject
* globals
= PyDict_New();
234 PyObject
* builtins
= PyImport_ImportModule("__builtin__");
235 PyDict_SetItemString(globals
, "__builtins__", builtins
);
238 // Execute the code to make the makeWindow function
239 result
= PyRun_String(python_code2
, Py_file_input
, globals
, globals
);
240 // Was there an exception?
243 wxPyEndBlockThreads(blocked
);
248 // Now there should be an object named 'makeWindow' in the dictionary that
249 // we can grab a pointer to:
250 PyObject
* func
= PyDict_GetItemString(globals
, "makeWindow");
251 wxASSERT(PyCallable_Check(func
));
253 // Now build an argument tuple and call the Python function. Notice the
254 // use of another wxPython API to take a wxWindows object and build a
255 // wxPython object that wraps it.
256 PyObject
* arg
= wxPyMake_wxObject(parent
);
257 wxASSERT(arg
!= NULL
);
258 PyObject
* tuple
= PyTuple_New(1);
259 PyTuple_SET_ITEM(tuple
, 0, arg
);
260 result
= PyEval_CallObject(func
, tuple
);
262 // Was there an exception?
266 // Otherwise, get the returned window out of Python-land and
268 bool success
= wxPyConvertSwigPtr(result
, (void**)&window
, _T("wxWindow"));
269 wxASSERT_MSG(success
, _T("Returned object was not a wxWindow!"));
273 // Release the python objects we still have
277 // Finally, after all Python stuff is done, release the GIL
278 wxPyEndBlockThreads(blocked
);
284 //----------------------------------------------------------------------