开源项目官方地址: http://www.xiaoniuhui.com/
原文链接: http://xiaoniuhui.com/#!/用boost-python加快vc程序开发
有两种方式嵌入python:c的方式和boost python的方式。对于c方式,我从来只用它做简单的执行,比如:
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++ 程序。
接下来介绍第二种嵌入python的方式,就是利用boost python来嵌入python。在pyui4win designer中,有一个扫描xml界面配置文件来生成对应python处理类的一个处理就采用了这个方式:
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文件模板的定义。
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')