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