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 //----------------------------------------------------------------------
14 // For compilers that support precompilation, includes "wx/wx.h".
15 #include <wx/wxprec.h>
25 #include <wx/splitter.h>
27 #if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXMGL__)
28 #include "mondrian.xpm"
31 // Import Python and wxPython headers
35 //----------------------------------------------------------------------
38 class MyApp
: public wxApp
41 virtual bool OnInit();
47 class MyFrame
: public wxFrame
50 MyFrame(const wxString
& title
, const wxPoint
& pos
, const wxSize
& size
);
52 wxWindow
* DoPythonStuff(wxWindow
* parent
);
53 void OnExit(wxCommandEvent
& event
);
54 void OnPyFrame(wxCommandEvent
& event
);
60 //----------------------------------------------------------------------
67 MyFrame
*frame
= new MyFrame(_T("Embedded wxPython Test"),
68 wxPoint(50, 50), wxSize(700, 600));
74 void MyApp::Init_wxPython()
80 // Load the wxPython core API. Imports the wxPython.wxc
81 // module and sets a pointer to a function table located there.
84 // Ensure that the new classes defined in the wxPython wrappers are
85 // recognised by the wx RTTI system. (If you don't use wxWindows in
86 // your C++ app you won't need to do this.)
87 wxClassInfo::CleanUpClasses();
88 wxClassInfo::InitializeClasses();
90 // Save the current Python thread state and release the
91 // Global Interpreter Lock.
92 wxPyBeginAllowThreads();
98 // Restore the thread state and tell Python to cleanup after itself.
99 wxPyEndAllowThreads(true);
105 //----------------------------------------------------------------------
114 BEGIN_EVENT_TABLE(MyFrame
, wxFrame
)
115 EVT_MENU(ID_EXIT
, MyFrame::OnExit
)
116 EVT_MENU(ID_PYFRAME
, MyFrame::OnPyFrame
)
121 MyFrame::MyFrame(const wxString
& title
, const wxPoint
& pos
, const wxSize
& size
)
122 : wxFrame(NULL
, -1, title
, pos
, size
,
123 wxDEFAULT_FRAME_STYLE
|wxNO_FULL_REPAINT_ON_RESIZE
)
125 SetIcon(wxICON(mondrian
));
127 wxMenuBar
* mbar
= new wxMenuBar
;
128 wxMenu
* menu
= new wxMenu
;
129 menu
->Append(ID_PYFRAME
, "Make wx&Python frame");
130 menu
->AppendSeparator();
131 menu
->Append(ID_EXIT
, "&Close Frame\tAlt-X");
132 mbar
->Append(menu
, "&File");
138 // Make some child windows from C++
139 wxSplitterWindow
* sp
= new wxSplitterWindow(this, -1);
140 wxPanel
* p1
= new wxPanel(sp
, -1);
141 p1
->SetFont(wxFont(12, wxSWISS
, wxNORMAL
, wxBOLD
));
142 new wxStaticText(p1
, -1,
143 wxT("The frame, menu, splitter, this panel and this text were created in C++..."),
146 // And get a panel from Python
147 wxWindow
* p2
= DoPythonStuff(sp
);
149 sp
->SplitHorizontally(p1
, p2
, GetClientSize().y
/4);
152 void MyFrame::OnExit(wxCommandEvent
& event
)
158 //----------------------------------------------------------------------
159 // This is were the fun begins...
162 char* python_code1
= "\
163 from wxPython.wx import wxFrame\n\
164 f = wxFrame(None, -1, 'Hello from wxPython!', size=(250, 150))\n\
168 void MyFrame::OnPyFrame(wxCommandEvent
& event
)
170 // For simple Python code that doesn't have to interact with the
171 // C++ code in any way, you can execute it with PyRun_SimpleString.
174 // First, whenever you do anyting with Python objects or code, you
175 // *MUST* aquire the Global Interpreter Lock and block other
176 // Python threads from running.
177 bool blocked
= wxPyBeginBlockThreads();
179 // Execute the code in the __main__ module
180 PyRun_SimpleString(python_code1
);
182 // Finally, release the GIL and let other Python threads run.
183 wxPyEndBlockThreads(blocked
);
187 void MyFrame::RedirectStdio()
189 // This is a helpful little tidbit to help debugging and such. It
190 // redirects Python's stdout and stderr to a window that will popup
191 // only on demand when something is printed, like a traceback.
192 char* python_redirect
= "\
194 from wxPython.wx import wxPyOnDemandOutputWindow\n\
195 output = wxPyOnDemandOutputWindow()\n\
196 sys.stdin = sys.stderr = output\n\
198 bool blocked
= wxPyBeginBlockThreads();
199 PyRun_SimpleString(python_redirect
);
200 wxPyEndBlockThreads(blocked
);
206 char* python_code2
= "\
207 import embedded_sample\n\
209 def makeWindow(parent):\n\
210 win = embedded_sample.MyPanel(parent)\n\
214 wxWindow
* MyFrame::DoPythonStuff(wxWindow
* parent
)
216 // More complex embedded situations will require passing C++ objects to
217 // Python and/or returning objects from Python to be used in C++. This
218 // sample shows one way to do it. NOTE: The above code could just have
219 // easily come from a file, or the whole thing could be in the Python
220 // module that is imported and manipulated directly in this C++ code. See
221 // the Python API for more details.
223 wxWindow
* window
= NULL
;
226 // As always, first grab the GIL
227 bool blocked
= wxPyBeginBlockThreads();
229 // Now make a dictionary to serve as the global namespace when the code is
230 // executed. Put a reference to the builtins module in it. (Yes, the
231 // names are supposed to be different, I don't know why...)
232 PyObject
* globals
= PyDict_New();
233 PyObject
* builtins
= PyImport_ImportModule("__builtin__");
234 PyDict_SetItemString(globals
, "__builtins__", builtins
);
237 // Execute the code to make the makeWindow function
238 result
= PyRun_String(python_code2
, Py_file_input
, globals
, globals
);
239 // Was there an exception?
242 wxPyEndBlockThreads();
247 // Now there should be an object named 'makeWindow' in the dictionary that
248 // we can grab a pointer to:
249 PyObject
* func
= PyDict_GetItemString(globals
, "makeWindow");
250 wxASSERT(PyCallable_Check(func
));
252 // Now build an argument tuple and call the Python function. Notice the
253 // use of another wxPython API to take a wxWindows object and build a
254 // wxPython object that wraps it.
255 PyObject
* arg
= wxPyMake_wxObject(parent
);
256 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 error
= SWIG_GetPtrObj(result
, (void**)&window
, "_wxWindow_p");
269 wxASSERT_MSG(!error
, wxT("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 //----------------------------------------------------------------------