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 could 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 //----------------------------------------------------------------------