用boost python加快vc程序開發

目錄

  • 用標準c接口嵌入python
  • 用boost python嵌入python
  • 用python來實現業務功能

boost python介紹

有兩種方式嵌入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

用boost python嵌入python

接下來介紹第二種嵌入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工程中能夠找到。

用python來實現業務功能

咱們對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')
相關文章
相關標籤/搜索