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
* m_mainTState
;
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 // Ensure that the new classes defined in the wxPython wrappers are
87 // recognised by the wx RTTI system. (If you don't use wxWindow in
88 // your C++ app you won't need to do this.)
89 wxClassInfo::CleanUpClasses();
90 wxClassInfo::InitializeClasses();
92 // Save the current Python thread state and release the
93 // Global Interpreter Lock.
94 m_mainTState
= wxPyBeginAllowThreads();
100 // Restore the thread state and tell Python to cleanup after itself.
101 wxPyEndAllowThreads(m_mainTState
);
107 //----------------------------------------------------------------------
116 BEGIN_EVENT_TABLE(MyFrame
, wxFrame
)
117 EVT_MENU(ID_EXIT
, MyFrame::OnExit
)
118 EVT_MENU(ID_PYFRAME
, MyFrame::OnPyFrame
)
123 MyFrame::MyFrame(const wxString
& title
, const wxPoint
& pos
, const wxSize
& size
)
124 : wxFrame(NULL
, -1, title
, pos
, size
,
125 wxDEFAULT_FRAME_STYLE
|wxNO_FULL_REPAINT_ON_RESIZE
)
127 SetIcon(wxICON(mondrian
));
129 wxMenuBar
* mbar
= new wxMenuBar
;
130 wxMenu
* menu
= new wxMenu
;
131 menu
->Append(ID_PYFRAME
, "Make wx&Python frame");
132 menu
->AppendSeparator();
133 menu
->Append(ID_EXIT
, "&Close Frame\tAlt-X");
134 mbar
->Append(menu
, "&File");
140 // Make some child windows from C++
141 wxSplitterWindow
* sp
= new wxSplitterWindow(this, -1);
142 wxPanel
* p1
= new wxPanel(sp
, -1);
143 p1
->SetFont(wxFont(12, wxSWISS
, wxNORMAL
, wxBOLD
));
144 new wxStaticText(p1
, -1,
145 wxT("The frame, menu, splitter, this panel and this text were created in C++..."),
148 // And get a panel from Python
149 wxWindow
* p2
= DoPythonStuff(sp
);
151 sp
->SplitHorizontally(p1
, p2
, GetClientSize().y
/4);
154 void MyFrame::OnExit(wxCommandEvent
& event
)
160 //----------------------------------------------------------------------
161 // This is were the fun begins...
164 char* python_code1
= "\
165 from wxPython.wx import wxFrame\n\
166 f = wxFrame(None, -1, 'Hello from wxPython!', size=(250, 150))\n\
170 void MyFrame::OnPyFrame(wxCommandEvent
& event
)
172 // For simple Python code that doesn't have to interact with the
173 // C++ code in any way, you can execute it with PyRun_SimpleString.
176 // First, whenever you do anyting with Python objects or code, you
177 // *MUST* aquire the Global Interpreter Lock and block other
178 // Python threads from running.
179 wxPyBeginBlockThreads();
181 // Execute the code in the __main__ module
182 PyRun_SimpleString(python_code1
);
184 // Finally, release the GIL and let other Python threads run.
185 wxPyEndBlockThreads();
189 void MyFrame::RedirectStdio()
191 // This is a helpful little tidbit to help debugging and such. It
192 // redirects Python's stdout and stderr to a window that will popup
193 // only on demand when something is printed, like a traceback.
194 char* python_redirect
= "\
196 from wxPython.wx import wxPyOnDemandOutputWindow\n\
197 output = wxPyOnDemandOutputWindow()\n\
198 sys.stdin = sys.stderr = output\n\
200 wxPyBeginBlockThreads();
201 PyRun_SimpleString(python_redirect
);
202 wxPyEndBlockThreads();
208 char* python_code2
= "\
209 import embedded_sample\n\
211 def makeWindow(parent):\n\
212 win = embedded_sample.MyPanel(parent)\n\
216 wxWindow
* MyFrame::DoPythonStuff(wxWindow
* parent
)
218 // More complex embedded situations will require passing C++ objects to
219 // Python and/or returning objects from Python to be used in C++. This
220 // sample shows one way to do it. NOTE: The above code could just have
221 // easily come from a file, or the whole thing could be in the Python
222 // module that is imported and manipulated directly in this C++ code. See
223 // the Python API for more details.
225 wxWindow
* window
= NULL
;
228 // As always, first grab the GIL
229 wxPyBeginBlockThreads();
231 // Now make a dictionary to serve as the global namespace when the code is
232 // executed. Put a reference to the builtins module in it. (Yes, the
233 // names are supposed to be different, I don't know why...)
234 PyObject
* globals
= PyDict_New();
235 PyObject
* builtins
= PyImport_ImportModule("__builtin__");
236 PyDict_SetItemString(globals
, "__builtins__", builtins
);
239 // Execute the code to make the makeWindow function
240 result
= PyRun_String(python_code2
, Py_file_input
, globals
, globals
);
241 // Was there an exception?
244 wxPyEndBlockThreads();
249 // Now there should be an object named 'makeWindow' in the dictionary that
250 // we can grab a pointer to:
251 PyObject
* func
= PyDict_GetItemString(globals
, "makeWindow");
252 wxASSERT(PyCallable_Check(func
));
254 // Now build an argument tuple and call the Python function. Notice the
255 // use of another wxPython API to take a wxWindows object and build a
256 // wxPython object that wraps it.
257 PyObject
* arg
= wxPyMake_wxObject(parent
);
258 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 error
= SWIG_GetPtrObj(result
, (void**)&window
, "_wxWindow_p");
271 wxASSERT_MSG(!error
, wxT("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();
286 //----------------------------------------------------------------------