目录
- 用标准c接口嵌入python
- 用boost python嵌入python
- 用python来实现业务功能
boost python介绍
有两种方式嵌入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++ 程序。
用boost python嵌入python
接下来介绍第二种嵌入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工程中可以找到。
用python来实现业务功能
我们对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')
来源:oschina
链接:https://my.oschina.net/u/159675/blog/157177