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
= "\
209 sys.path.append('.')\n\
210 import embedded_sample\n\
212 def makeWindow(parent):\n\
213 win = embedded_sample.MyPanel(parent)\n\
217 wxWindow
* MyFrame::DoPythonStuff(wxWindow
* parent
)
219 // More complex embedded situations will require passing C++ objects to
220 // Python and/or returning objects from Python to be used in C++. This
221 // sample shows one way to do it. NOTE: The above code could just have
222 // easily come from a file, or the whole thing could be in the Python
223 // module that is imported and manipulated directly in this C++ code. See
224 // the Python API for more details.
226 wxWindow
* window
= NULL
;
229 // As always, first grab the GIL
230 bool blocked
= wxPyBeginBlockThreads();
232 // Now make a dictionary to serve as the global namespace when the code is
233 // executed. Put a reference to the builtins module in it. (Yes, the
234 // names are supposed to be different, I don't know why...)
235 PyObject
* globals
= PyDict_New();
236 PyObject
* builtins
= PyImport_ImportModule("__builtin__");
237 PyDict_SetItemString(globals
, "__builtins__", builtins
);
240 // Execute the code to make the makeWindow function
241 result
= PyRun_String(python_code2
, Py_file_input
, globals
, globals
);
242 // Was there an exception?
245 wxPyEndBlockThreads(blocked
);
250 // Now there should be an object named 'makeWindow' in the dictionary that
251 // we can grab a pointer to:
252 PyObject
* func
= PyDict_GetItemString(globals
, "makeWindow");
253 wxASSERT(PyCallable_Check(func
));
255 // Now build an argument tuple and call the Python function. Notice the
256 // use of another wxPython API to take a wxWindows object and build a
257 // wxPython object that wraps it.
258 PyObject
* arg
= wxPyMake_wxObject(parent
);
259 wxASSERT(arg
!= NULL
);
260 PyObject
* tuple
= PyTuple_New(1);
261 PyTuple_SET_ITEM(tuple
, 0, arg
);
262 result
= PyEval_CallObject(func
, tuple
);
264 // Was there an exception?
268 // Otherwise, get the returned window out of Python-land and
270 bool success
= wxPyConvertSwigPtr(result
, (void**)&window
, _T("wxWindow"));
271 wxASSERT_MSG(success
, _T("Returned object was not a wxWindow!"));
275 // Release the python objects we still have
279 // Finally, after all Python stuff is done, release the GIL
280 wxPyEndBlockThreads(blocked
);
286 //----------------------------------------------------------------------