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();
45 PyThreadState
* main_tstate
;
49 class MyFrame
: public wxFrame
52 MyFrame(const wxString
& title
, const wxPoint
& pos
, const wxSize
& size
);
54 wxWindow
* DoPythonStuff(wxWindow
* parent
);
55 void OnExit(wxCommandEvent
& event
);
56 void OnPyFrame(wxCommandEvent
& event
);
62 //----------------------------------------------------------------------
69 MyFrame
*frame
= new MyFrame(_T("Embedded wxPython Test"),
70 wxPoint(50, 50), wxSize(700, 600));
76 void MyApp::Init_wxPython()
82 // Load the wxPython core API. Imports the wxPython.wxc
83 // module and sets a pointer to a function table located there.
86 // Save the current Python thread state and release the
87 // Global Interpreter Lock.
88 main_tstate
= wxPyBeginAllowThreads();
94 // Restore the thread state and tell Python to cleanup after itself.
95 wxPyEndAllowThreads(main_tstate
);
101 //----------------------------------------------------------------------
110 BEGIN_EVENT_TABLE(MyFrame
, wxFrame
)
111 EVT_MENU(ID_EXIT
, MyFrame::OnExit
)
112 EVT_MENU(ID_PYFRAME
, MyFrame::OnPyFrame
)
117 MyFrame::MyFrame(const wxString
& title
, const wxPoint
& pos
, const wxSize
& size
)
118 : wxFrame(NULL
, -1, title
, pos
, size
,
119 wxDEFAULT_FRAME_STYLE
|wxNO_FULL_REPAINT_ON_RESIZE
)
121 SetIcon(wxICON(mondrian
));
123 wxMenuBar
* mbar
= new wxMenuBar
;
124 wxMenu
* menu
= new wxMenu
;
125 menu
->Append(ID_PYFRAME
, "Make wx&Python frame");
126 menu
->AppendSeparator();
127 menu
->Append(ID_EXIT
, "&Close Frame\tAlt-X");
128 mbar
->Append(menu
, "&File");
134 // Make some child windows from C++
135 wxSplitterWindow
* sp
= new wxSplitterWindow(this, -1);
136 wxPanel
* p1
= new wxPanel(sp
, -1);
137 p1
->SetFont(wxFont(12, wxSWISS
, wxNORMAL
, wxBOLD
));
138 new wxStaticText(p1
, -1,
139 wxT("The frame, menu, splitter, this panel and this text were created in C++..."),
142 // And get a panel from Python
143 wxWindow
* p2
= DoPythonStuff(sp
);
145 sp
->SplitHorizontally(p1
, p2
, GetClientSize().y
/4);
148 void MyFrame::OnExit(wxCommandEvent
& event
)
154 //----------------------------------------------------------------------
155 // This is were the fun begins...
158 char* python_code1
= "\
159 from wxPython.wx import wxFrame\n\
160 f = wxFrame(None, -1, 'Hello from wxPython!', size=(250, 150))\n\
164 void MyFrame::OnPyFrame(wxCommandEvent
& event
)
166 // For simple Python code that doesn't have to interact with the
167 // C++ code in any way, you can execute it with PyRun_SimpleString.
170 // First, whenever you do anyting with Python objects or code, you
171 // *MUST* aquire the Global Interpreter Lock and block other
172 // Python threads from running.
173 wxPyBeginBlockThreads();
175 // Execute the code in the __main__ module
176 PyRun_SimpleString(python_code1
);
178 // Finally, release the GIL and let other Python threads run.
179 wxPyEndBlockThreads();
183 void MyFrame::RedirectStdio()
185 // This is a helpful little tidbit to help debugging and such. It
186 // redirects Python's stdout and stderr to a window that will popup
187 // only on demand when something is printed, like a traceback.
188 char* python_redirect
= "\
190 from wxPython.wx import wxPyOnDemandOutputWindow\n\
191 output = wxPyOnDemandOutputWindow()\n\
192 sys.stdin = sys.stderr = output\n\
194 wxPyBeginBlockThreads();
195 PyRun_SimpleString(python_redirect
);
196 wxPyEndBlockThreads();
202 char* python_code2
= "\
203 import embedded_sample\n\
205 def makeWindow(parent):\n\
206 win = embedded_sample.MyPanel(parent)\n\
210 wxWindow
* MyFrame::DoPythonStuff(wxWindow
* parent
)
212 // More complex embedded situations will require passing C++ objects to
213 // Python and/or returning objects from Python to be used in C++. This
214 // sample shows one way to do it. NOTE: The above code could just have
215 // easily come from a file, or the whole thing coupld be in the Python
216 // module that is imported and manipulated directly in this C++ code. See
217 // the Python API for more details.
219 wxWindow
* window
= NULL
;
222 // As always, first grab the GIL
223 wxPyBeginBlockThreads();
225 // Now make a dictionary to serve as the global namespace when the code is
226 // executed. Put a reference to the builtins module in it. (Yes, the
227 // names are supposed to be different, I don't know why...)
228 PyObject
* globals
= PyDict_New();
229 PyObject
* builtins
= PyImport_ImportModule("__builtin__");
230 PyDict_SetItemString(globals
, "__builtins__", builtins
);
233 // Execute the code to make the makeWindow function
234 result
= PyRun_String(python_code2
, Py_file_input
, globals
, globals
);
235 // Was there an exception?
238 wxPyEndBlockThreads();
243 // Now there should be an object named 'makeWindow' in the dictionary that
244 // we can grab a pointer to:
245 PyObject
* func
= PyDict_GetItemString(globals
, "makeWindow");
246 wxASSERT(PyCallable_Check(func
));
248 // Now build an argument tuple and call the Python function. Notice the
249 // use of another wxPython API to take a wxWindows object and build a
250 // wxPython object that wraps it.
251 PyObject
* arg
= wxPyMake_wxObject(parent
);
252 wxASSERT(arg
!= NULL
);
254 PyObject
* tuple
= PyTuple_New(1);
255 PyTuple_SET_ITEM(tuple
, 0, arg
);
256 result
= PyEval_CallObject(func
, tuple
);
258 // Was there an exception?
262 // Otherwise, get the returned window out of Python-land and
264 bool error
= SWIG_GetPtrObj(result
, (void**)&window
, "_wxWindow_p");
265 wxASSERT_MSG(!error
, wxT("Returned object was not a wxWindow!"));
269 // Release the python objects we still have
273 // Finally, after all Python stuff is done, release the GIL
274 wxPyEndBlockThreads();
280 //----------------------------------------------------------------------