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 //---------------------------------------------------------------------- 
  71     if ( !Init_wxPython() ) 
  72         // don't start the app if we can't initialize wxPython. 
  75     MyFrame 
*frame 
= new MyFrame(_T("Embedded wxPython Test"), 
  76                                  wxDefaultPosition
, wxSize(700, 600)); 
  83 bool MyApp::Init_wxPython() 
  89     // Load the wxPython core API.  Imports the wx._core_ module and sets a 
  90     // local pointer to a function table located there.  The pointer is used 
  91     // internally by the rest of the API functions. 
  92     if ( ! wxPyCoreAPI_IMPORT() ) { 
  93         wxLogError(wxT("***** Error importing the wxPython API! *****")); 
  99     // Save the current Python thread state and release the 
 100     // Global Interpreter Lock. 
 101     m_mainTState 
= wxPyBeginAllowThreads(); 
 109     // Restore the thread state and tell Python to cleanup after itself. 
 110     // wxPython will do its own cleanup as part of that process.  This is done 
 111     // in OnExit instead of ~MyApp because OnExit is only called if OnInit is 
 113     wxPyEndAllowThreads(m_mainTState
); 
 121 //---------------------------------------------------------------------- 
 130 BEGIN_EVENT_TABLE(MyFrame
, wxFrame
) 
 131     EVT_MENU(ID_EXIT
,      MyFrame::OnExit
) 
 132     EVT_MENU(ID_PYFRAME
,   MyFrame::OnPyFrame
) 
 137 MyFrame::MyFrame(const wxString
& title
, const wxPoint
& pos
, const wxSize
& size
) 
 138     : wxFrame(NULL
, -1, title
, pos
, size
, 
 139               wxDEFAULT_FRAME_STYLE
|wxNO_FULL_REPAINT_ON_RESIZE
) 
 141     SetIcon(wxICON(mondrian
)); 
 143     wxMenuBar
* mbar 
= new wxMenuBar
; 
 144     wxMenu
*    menu 
= new wxMenu
; 
 145     menu
->Append(ID_PYFRAME
, _T("Make wx&Python frame")); 
 146     menu
->AppendSeparator(); 
 147     menu
->Append(ID_EXIT
, _T("&Close Frame\tAlt-X")); 
 148     mbar
->Append(menu
, _T("&File")); 
 154     // Make some child windows from C++ 
 155     wxSplitterWindow
* sp 
= new wxSplitterWindow(this, -1); 
 156     wxPanel
* p1 
= new wxPanel(sp
, -1, wxDefaultPosition
, wxDefaultSize
, wxSUNKEN_BORDER
); 
 158     new wxStaticText(p1
, -1, 
 159                  _T("The frame, menu, splitter, this panel and this text were created in C++..."), 
 162     // And get a panel from Python 
 163     wxWindow
* p2 
= DoPythonStuff(sp
); 
 165     sp
->SplitHorizontally(p1
, p2
, GetClientSize().y
/4); 
 168 void MyFrame::OnExit(wxCommandEvent
& event
) 
 174 //---------------------------------------------------------------------- 
 175 // This is where the fun begins... 
 178 char* python_code1 
= "\ 
 180 f = wx.Frame(None, -1, 'Hello from wxPython!', size=(250, 150))\n\ 
 184 void MyFrame::OnPyFrame(wxCommandEvent
& event
) 
 186     // For simple Python code that doesn't have to interact with the 
 187     // C++ code in any way, you can execute it with PyRun_SimpleString. 
 190     // First, whenever you do anything with Python objects or code, you 
 191     // *MUST* aquire the Global Interpreter Lock and block other 
 192     // Python threads from running. 
 193     wxPyBlock_t blocked 
= wxPyBeginBlockThreads(); 
 195     // Execute the code in the __main__ module 
 196     PyRun_SimpleString(python_code1
); 
 198     // Finally, release the GIL and let other Python threads run. 
 199     wxPyEndBlockThreads(blocked
); 
 203 void MyFrame::RedirectStdio() 
 205     // This is a helpful little tidbit to help debugging and such.  It 
 206     // redirects Python's stdout and stderr to a window that will popup 
 207     // only on demand when something is printed, like a traceback. 
 208     char* python_redirect 
= "\ 
 211 output = wx.PyOnDemandOutputWindow()\n\ 
 212 sys.stdin = sys.stderr = output\n\ 
 214     wxPyBlock_t blocked 
= wxPyBeginBlockThreads(); 
 215     PyRun_SimpleString(python_redirect
); 
 216     wxPyEndBlockThreads(blocked
); 
 222 char* python_code2 
= "\ 
 224 sys.path.append('.')\n\ 
 225 import embedded_sample\n\ 
 227 def makeWindow(parent):\n\ 
 228     win = embedded_sample.MyPanel(parent)\n\ 
 232 wxWindow
* MyFrame::DoPythonStuff(wxWindow
* parent
) 
 234     // More complex embedded situations will require passing C++ objects to 
 235     // Python and/or returning objects from Python to be used in C++.  This 
 236     // sample shows one way to do it.  NOTE: The above code could just have 
 237     // easily come from a file, or the whole thing could be in the Python 
 238     // module that is imported and manipulated directly in this C++ code.  See 
 239     // the Python API for more details. 
 241     wxWindow
* window 
= NULL
; 
 244     // As always, first grab the GIL 
 245     wxPyBlock_t blocked 
= wxPyBeginBlockThreads(); 
 247     // Now make a dictionary to serve as the global namespace when the code is 
 248     // executed.  Put a reference to the builtins module in it.  (Yes, the 
 249     // names are supposed to be different, I don't know why...) 
 250     PyObject
* globals 
= PyDict_New(); 
 251     PyObject
* builtins 
= PyImport_ImportModule("__builtin__"); 
 252     PyDict_SetItemString(globals
, "__builtins__", builtins
); 
 255     // Execute the code to make the makeWindow function 
 256     result 
= PyRun_String(python_code2
, Py_file_input
, globals
, globals
); 
 257     // Was there an exception? 
 260         wxPyEndBlockThreads(blocked
); 
 265     // Now there should be an object named 'makeWindow' in the dictionary that 
 266     // we can grab a pointer to: 
 267     PyObject
* func 
= PyDict_GetItemString(globals
, "makeWindow"); 
 268     wxASSERT(PyCallable_Check(func
)); 
 270     // Now build an argument tuple and call the Python function.  Notice the 
 271     // use of another wxPython API to take a wxWindows object and build a 
 272     // wxPython object that wraps it. 
 273     PyObject
* arg 
= wxPyMake_wxObject(parent
, false); 
 274     wxASSERT(arg 
!= NULL
); 
 275     PyObject
* tuple 
= PyTuple_New(1); 
 276     PyTuple_SET_ITEM(tuple
, 0, arg
); 
 277     result 
= PyEval_CallObject(func
, tuple
); 
 279     // Was there an exception? 
 283         // Otherwise, get the returned window out of Python-land and 
 285         bool success 
= wxPyConvertSwigPtr(result
, (void**)&window
, _T("wxWindow")); 
 286         wxASSERT_MSG(success
, _T("Returned object was not a wxWindow!")); 
 290     // Release the python objects we still have 
 294     // Finally, after all Python stuff is done, release the GIL 
 295     wxPyEndBlockThreads(blocked
); 
 301 //----------------------------------------------------------------------