開源項目官方地址: http://www.xiaoniuhui.com/ python
原文連接: http://xiaoniuhui.com/#!/用boost-python加快vc程序開發 c++
有兩種方式嵌入python:c的方式和boost python的方式。對於c方式,我歷來只用它作簡單的執行,好比: git
PyRun_SimpleString("import sys"); PyRun_SimpleString( (std::string("if not '") + (LPCSTR)pathA + "' in sys.path: \n" " sys.path.append('" + (LPCSTR)pathA + "')\n").c_str()); PyRun_SimpleString( (std::string("if not '") + (LPCSTR)pathA + "\\PyModule' in sys.path: \n" " sys.path.append('" + (LPCSTR)pathA + "\\PyModule')\n").c_str());第二種方式是經過boost python嵌入python。我基本上都用它。
Boost.Python是著名的c++庫Boost的一個組件,它實現了c++和 python 兩種功能豐富的優秀的語言環境間的無縫協做。Boost.Python的另一個優勢是,它的設計目標就是讓C++程序庫能夠透明地導出到 Python中去。即在徹底不修改原來 C++ 程序的狀況下,導出給Python 用。在這種設計理 念下設計出來的 Boost.Python比同類工具支持了給完善的 C++ 特性,可以最大程度地保證不修改原 C++ 程序。 github
接下來介紹第二種嵌入python的方式,就是利用boost python來嵌入python。在pyui4win designer中,有一個掃描xml界面配置文件來生成對應python處理類的一個處理就採用了這個方式: shell
void CUIDesignerView::OnGenerateCode() { TCHAR szFileName[MAX_PATH]; CString strFilePath=GetDocument()->GetPathName(); boost::python::handle<>* _module = NULL; // Module handle. try { _module = new boost::python::handle<>( PyImport_ImportModule("GenerateCode")); int ret = boost::python::call_method(_module->get(), "GeneratePythonCode", std::string(CStringA(strFilePath).GetBuffer())); switch (ret) { case 0: MessageBox(_T("成功生成代碼"), _T("提示"), MB_ICONINFORMATION); break; case -1: MessageBox(_T("還未實現"), _T("提示"), MB_ICONERROR); break; default: MessageBox(_T("出錯啦"), _T("提示"), MB_ICONERROR); break; } } catch(boost::python::error_already_set const &) { std::string err = parse_python_exception(); MessageBox(CString(CStringA(err.c_str())), _T("提示"), MB_ICONERROR); PyLog().LogText(err.c_str()); PyErr_Clear(); } catch (...) { if (PyErr_Occurred()) { std::string err = parse_python_exception(); PyLog().LogText(err.c_str()); PyErr_Clear(); } } if (_module) delete _module; }
以上是一個完整的用boost python來嵌入python的處理。 其中,parse_python_exception函數是異常信息提取函數。在pyui4win designer工程中能夠找到。
咱們對GenerateCode.py中的代碼更感興趣。看看GenerateCode的代碼:先是py文件模板的定義。 app
codeTemplate =""" # coding=gbk __author__ = 'generated by py-ui4win' import string, os, time from PyUI import * from MsgBox import * from PyFrameBase import * import UICommon from CommonUtil import CommonUtils class {CLASS_NAME}(PyFrameBase): def __init__(self): super({CLASS_NAME}, self).__init__() self.clsName = self.__class__.__name__ self.skinFileName = self.__class__.__name__ + '.xml' # 不要改動 def GetSkinFile(self): return self.skinFileName # 不要改動 def GetWindowClassName(self): return self.clsName # 退出處理 def OnExit(self, sendor, wParam, lParam): self.ExitApp() # 準備顯示前的處理 def OnPrepare(self, sendor, wParam, lParam): {ON_PREPARE} # 界面事件處理 def OnNotify(self, sendor, sType, wParam, lParam): # 用戶點擊事件 if sType == DUI_MSGTYPE_CLICK: {ON_CLICK} # 用戶選擇事件 if sType == DUI_MSGTYPE_ITEMSELECT: {ON_ITEMSELECT} """
以上定義的是代碼生成模板,用"""的字符串語法要比c++清晰,並且比c++簡單多了。若是用c++來定義,裏面要寫一堆 \n了和"號。
如下是根據xml界面文件來生成對應py文件的處理過程。主要在GenerateCode裏。用python寫起來真的是很舒服。 函數
class GenerateCode(): def __init__(self): self.code = '' def GenerateCode(self, skinXmlPath): self.skinXmlPath = skinXmlPath if not os.path.isfile(skinXmlPath): return -2 # 分析xml皮膚 tree = ET.ElementTree(file=skinXmlPath) prepare_code = '' click_code = '' itemselect_code = '' for ctltag in ['Control', 'Label', 'Button', 'Option', 'Edit', 'RichEdit','Combo','Text','CheckBox', \ 'Progress', 'Animation', 'Container', 'HorizontalLayout', 'VerticalLayout', 'TabLayout', 'List', \ 'WebBrowser']: for elem in tree.iter(tag=ctltag): if elem.attrib.has_key('name'): #print elem.tag, elem.attrib # OnPrepare prepare_code += ' self.%s = self.PyFind%s("%s")'%(elem.attrib['name'], ctltag, elem.attrib['name']) + os.linesep # DUI_MSGTYPE_CLICK if ctltag in ['Button', 'Option', 'CheckBox']: click_code += ' elif sendor == "%s":'%elem.attrib['name'] + os.linesep click_code += ' pass' + os.linesep # DUI_MSGTYPE_ITEMSELECT if ctltag in ['Combo', 'List']: itemselect_code += ' elif sendor == "%s":'%elem.attrib['name'] + os.linesep itemselect_code += ' pass' + os.linesep click_code = click_code.replace('elif', 'if', 1) itemselect_code = itemselect_code.replace('elif', 'if', 1) # 組合代碼 if os.path.basename(skinXmlPath) == 'MainFrame.xml': self.saveFile = os.path.dirname(skinXmlPath) + '\\' + 'PyMain.py' # 要保持爲PyMain.py文件 else: self.saveFile = skinXmlPath.replace('.xml','.py') self.codeTemp = codeTemplate.replace('\n', '\r\n') self.code = self.codeTemp.format(\ CLASS_NAME = os.path.basename(skinXmlPath).split('.')[0],\ ON_PREPARE = prepare_code,\ ON_CLICK = click_code if click_code != '' else ' pass',\ ON_ITEMSELECT = itemselect_code if itemselect_code != '' else ' pass'\ ) #寫py文件 outfile = open(self.saveFile, 'wb') outfile.write(self.code) outfile.close() #打開文件 shell32 = ctypes.windll.LoadLibrary("shell32.dll"); shell32.ShellExecuteA(None,'open', 'notepad',self.saveFile,'',1); return 0
能夠看出,用python開發程序的確很爽。若是是用c++來實現這個功能, 光是定義這些個list和set就很瑣碎,並且很沒勁。
如下是測試函數 工具
def GeneratePythonCode( skinXmlPath): return GenerateCode().GenerateCode(skinXmlPath) if __name__ == '__main__': GeneratePythonCode(r'f:\pyui4win\pyui4win\Demo3\skin\MainFrame.xml')