Python自动生成代码(二)- 基于MVP架构的C/C++ 代码生成器实例
- 背景
- 代码解析 - BuildCode_MVP Class
- 代码解析 - Generatexxx()
- 代码解析 - ReplaceStrinFile()
- 代码解析 -Tkinter 图形界面
- 完整代码
- 其他好玩的python脚本
- 博主热门文章推荐:
背景
上篇博客 Python自动生成代码 - 通过tkinter图形化操作生成代码框架 简单介绍了下自动生成代码(代码生成器)及其实现,下面继续通过一个应用案例来探讨:
在写代码过程中,如果有大量频繁重复性的编码、修改操作,或者可以Reuse的各类代码,可以通过Python写一个脚本,自动生成这类代码,就不用每次手写、或者copy了,提高效率。
这里以基于MVP(Model View Presenter)架构 的C/C++代码 作为实例:
在基于MVP架构实际coding中,因为做GUI开发时有非常多的页面,而每一个页面都需要 M/V/P层的代码,这些代码都是一个架构,只是代码中的一些类、变量、页面、头文件等命名不同而已,所以通过代码生成器来一键生成。。。这样做新的界面,只要生成相应代码,再往里面写应用即可
这样就非常方便,对我来说开发上也提高了很多效率,这里分享一下,代码中的模板因为涉及公司已经去掉,如果使用根据自己的代码需要,改变code_Template 即可。
应用场景举例:比如新建固定的代码框架、添加一些既定的软件逻辑,通讯协议、消息模板等等,当需要根据同样架构 再编写一套代码时,或者一个Function时,每次使通过脚本一键生成代码,就不需要每次都写一遍了,同时可以把相关软件逻辑放进去,也能避免出错。
惯例先上图:
部分生成代码:(仅Demo用,在代码中对codeTemplate中根据实际待Generate代码替换)
代码解析 - BuildCode_MVP Class
BuildCode_MVP Class 是通过Generate 创建相关cpp/hpp代码文件及目录,并放在同一目录下。
class BuildCode_MVP:
' Generate code class of Model/View/Presenter Code '
def __init__(self, KeyWord = 'TestInputScreenName'):
self.CmdKeyWord = KeyWord
def Generate(self):
Chpwd = self.CmdKeyWord + 'Screen'
mkdir(Chpwd)
os.chdir(Chpwd)
self.GeneratePresenterCpp()
self.GeneratePresenterHpp()
self.GenerateViewCpp()
self.GenerateViewHpp()
self.GenerateIViewHpp()
os.chdir('../')
TemplateScreenName = "YourCodeName"
TemplateScreenName_View = "YourCodeName"
代码解析 - Generatexxx()
Generatexxx 既创建相关cpp/hpp代码文件,例如下面的GeneratePresenterCpp(),主要是将codeTemplate通过ReplaceStrinFile 替换 template里的字符,将代码模板里的methods、变量、头文件等名字 转换为 输入的字符self.CmdKeyWord作为替换名 。
这里删减了很多和代码逻辑相关的,具体可以根据需要添加 替换、增加code 等功能
def GeneratePresenterCpp(self):
fileName_cpp = self.CmdKeyWord +'Presenter.cpp'
mycode = []
codeTemplate = ''' 这里是需要替换的Generator代码模板
//Generated By Python3 Script
//#include <iostream>
/***************************************************************************//**
@brief
*******************************************************************************/
'''
mycode.append(codeTemplate)
WritetoFile(fileName_cpp,mycode)
print('Presenter: '+ fileName_cpp + ' Generate OK!')
#Replace Template str
ReplaceStrinFile(fileName_cpp, self.TemplateScreenName, self.CmdKeyWord)
ReplaceStrinFile(fileName_cpp, self.TemplateScreenName_View, self.CmdKeyWord.lower())
return(mycode)
代码解析 - ReplaceStrinFile()
ReplaceStrinFile就是遍历文件内容,找到要替换的str 并且通过re.sub执行替换操作
def ReplaceStrinFile(FileName, OldStr, NewStr):
file = open(FileName, 'r')
alllines = file.readlines()
file.close()
file = open(FileName, 'w+')
for eachline in alllines:
a = re.sub(OldStr, NewStr, eachline)
file.writelines(a)
file.close()
代码解析 -Tkinter 图形界面
界面很简单,主要通过CommandInput输入框, Btn 和text显示。
这个UI代码结构也是我之前其他工具沿用的。。
#Tkinter code below
root = Tk()
root.geometry('1000x600')
root.title('MVP Code Generator Tools')
root.config(bg='#f0ffff')
#Lable
Lb_CommandInput = Label(root,text='输入 MVP Screen Name:',\
# bg='#d3fbfb',\
fg='red',\
font=('华文新魏',10),\
width=28,\
height=2,\
relief=RIDGE)
Lb_CommandInput.place(relx=0.125, rely=0.237, relwidth=0.15, relheight=0.05)
Lb_CommandInput = Label(root,text='输入 Signal Name:',\
# bg='#d3fbfb',\
fg='red',\
font=('华文新魏',10),\
width=28,\
height=2,\
relief=RIDGE)
Lb_CommandInput.place(relx=0.125, rely=0.537, relwidth=0.15, relheight=0.05)
intro = Label(root,text='请在下方输入MVP要生成的ScreenName,然后点击Generate',\
bg='#d3fbfb',\
fg='red',\
font=('华文新魏',14),\
width=20,\
height=2,\
relief=RIDGE)
intro.place(relx=0.1, rely=0.1, relwidth=0.8, relheight=0.1)
ContactLable = Label(root, text='联系人:HowardXue H191748',\
# bg='#d3fbfb',\
fg='red',\
font=('',12),\
width=20,\
height=2,\
relief=RIDGE)
ContactLable.place(relx=0.7, rely=0.03, relwidth=0.25, relheight=0.05)
#Output
txt = Text(root, font = ('',10))
txt.place(relx=0.3, rely=0.2, relwidth=0.6, relheight=0.625)
#lable
#Entry
Et_CommandInput = Entry(root, bd =5, relief=GROOVE)
Et_CommandInput.place(relx=0.125, rely=0.3, relwidth=0.15, relheight=0.05)
Et_SignalCommandInput = Entry(root, bd =5, relief=GROOVE)
Et_SignalCommandInput.place(relx=0.125, rely=0.6, relwidth=0.15, relheight=0.05)
#Button
bt_bin2json = Button(root, text='MVP Code Generate', command=OnCommandInput, fg ='blue')
bt_bin2json.place(relx=0.1, rely=0.38, relwidth=0.2, relheight=0.1)
signalButton = Button(root, text='Signal PVID Code Generate', command=OnSignalButton, fg ='blue')
signalButton.place(relx=0.1, rely=0.68, relwidth=0.2, relheight=0.1)
# bt_clear = Button(root, text='Clear', command=clearSendContent, fg ='blue')
# bt_clear.place(relx=0.15, rely=0.825, relwidth=0.2, relheight=0.1)
bt_clear_rcv = Button(root, text='Clear', command=clearRcvContent, fg ='blue')
bt_clear_rcv.place(relx=0.45, rely=0.825, relwidth=0.2, relheight=0.1)
#comboxlist.pack()
root.mainloop()
完整代码
MVPCodeBuilder_Blog.py
#conding=utf-8
import sys
import os
import re
def mkdir(path):
import os
path = path.strip()
path = path.rstrip("\\")
isExists = os.path.exists(path)
if not isExists:
os.makedirs(path)
print(path + ' Create Success')
return True
else:
print(path + ' Folder already exist')
return False
def ReplaceStrinFile(FileName, OldStr, NewStr):
file = open(FileName, 'r')
alllines = file.readlines()
file.close()
file = open(FileName, 'w+')
for eachline in alllines:
a = re.sub(OldStr, NewStr, eachline)
file.writelines(a)
file.close()
def WritetoFile(FileName,Data):
with open(FileName,'w') as record:
strr = "\n"
content = strr.join(Data)
record.write(content+'\n')
class BuildCode_MVP:
' Generate code class of Model/View/Presenter Code '
def __init__(self, KeyWord = 'TestInputScreenName'):
self.CmdKeyWord = KeyWord
def Generate(self):
Chpwd = self.CmdKeyWord + 'Screen'
mkdir(Chpwd)
os.chdir(Chpwd)
self.GeneratePresenterCpp()
self.GeneratePresenterHpp()
self.GenerateViewCpp()
self.GenerateViewHpp()
self.GenerateIViewHpp()
os.chdir('../')
TemplateScreenName = "YourCode"
TemplateScreenName_View = "YourCode"
def GetScreenIDEnum(self):
return 'SCREEN_'+self.CmdKeyWord.upper()
def GetIncludeHeader_Presenter(self):
return '#include "'+self.CmdKeyWord+'Screen/'+self.CmdKeyWord+'Presenter.hpp"'
def GetIncludeHeader_View(self):
return '#include "' + self.CmdKeyWord + 'Screen/' + self.CmdKeyWord + 'View.hpp"'
def GetWrapper_BackBtnClicked(self):
return self.GetScreenIDEnum() + self.CmdKeyWord;
def GeneratePresenterCpp(self):
fileName_cpp = self.CmdKeyWord +'Presenter.cpp'
mycode = []
codeTemplate = ''' 这里是需要替换的Generator代码模板
//Generated By Python3 Script
//#include <iostream>
/***************************************************************************//**
@brief
*******************************************************************************/
'''
mycode.append(codeTemplate)
WritetoFile(fileName_cpp,mycode)
print('Presenter: '+ fileName_cpp + ' Generate OK!')
#Replace Template str
ReplaceStrinFile(fileName_cpp, self.TemplateScreenName, self.CmdKeyWord)
ReplaceStrinFile(fileName_cpp, self.TemplateScreenName_View, self.CmdKeyWord.lower())
return(mycode)
############### HPP ####################
def GeneratePresenterHpp(self):
fileName_hpp = self.CmdKeyWord + 'Presenter.hpp'
mycode = []
mycode.append('\n//Generated By Python3 Script ')
mycode.append('#ifndef _'+ self.CmdKeyWord.upper() +'_PRESENTER_H_ ')
mycode.append('#define _'+ self.CmdKeyWord.upper() + '_PRESENTER_H_ ')
codeTemplate = ''' 这里是需要替换的Generator代码模板
#endif
'''
mycode.append(codeTemplate)
WritetoFile(fileName_hpp, mycode)
print('Presenter: ' + fileName_hpp + ' Generate OK!')
# Replace Template str
ReplaceStrinFile(fileName_hpp, self.TemplateScreenName, self.CmdKeyWord)
ReplaceStrinFile(fileName_hpp, self.TemplateScreenName_View, self.CmdKeyWord.lower())
return (mycode)
def GenerateViewCpp(self):
fileName_cpp = self.CmdKeyWord + 'View.cpp'
mycode = []
codeTemplate = ''' 这里是需要替换的Generator代码模板
//Generated By Python3 Script
#ifdef __cplusplus
extern "C"
{
#endif
'''
mycode.append(codeTemplate)
WritetoFile(fileName_cpp, mycode)
print('View: ' + fileName_cpp + ' Generate OK!')
# Replace Template str
ReplaceStrinFile(fileName_cpp, self.TemplateScreenName, self.CmdKeyWord)
ReplaceStrinFile(fileName_cpp, self.TemplateScreenName_View, self.CmdKeyWord.lower())
return (mycode)
############### HPP ####################
def GenerateViewHpp(self):
fileName_hpp = self.CmdKeyWord + 'View.hpp'
mycode = []
mycode.append('\n//Generated By Python3 Script ')
mycode.append('#ifndef _' + self.CmdKeyWord.upper() + '_VIEW_H_ ')
mycode.append('#define _' + self.CmdKeyWord.upper() + '_VIEW_H_ ')
codeTemplate = ''' 这里是需要替换的Generator代码模板
#endif
'''
mycode.append(codeTemplate)
WritetoFile(fileName_hpp, mycode)
print('View: ' + fileName_hpp + ' Generate OK!')
# Replace Template str
ReplaceStrinFile(fileName_hpp, self.TemplateScreenName, self.CmdKeyWord)
ReplaceStrinFile(fileName_hpp, self.TemplateScreenName_View, self.CmdKeyWord.lower())
return (mycode)
def GenerateIViewHpp(self):
fileName_hpp = 'I'+self.CmdKeyWord + 'View.hpp'
mycode = []
mycode.append('\n//Generated By Python3 Script ')
mycode.append('#ifndef _I_' + self.CmdKeyWord.upper() + '_VIEW_H_ ')
mycode.append('#define _I_' + self.CmdKeyWord.upper() + '_VIEW_H_ ')
codeTemplate = '''
#endif
'''
mycode.append(codeTemplate)
WritetoFile(fileName_hpp, mycode)
print('IView: ' + fileName_hpp + ' Generate OK!')
# Replace Template str
ReplaceStrinFile(fileName_hpp, self.TemplateScreenName, self.CmdKeyWord)
ReplaceStrinFile(fileName_hpp, self.TemplateScreenName_View, self.CmdKeyWord.lower())
return (mycode)
class BuildCode_Signal:
' Generate Signal code '
def __init__(self, KeyWord='TestPVIDValue'):
self.CmdKeyWord = 'Signal_' + KeyWord
self.CmdKeyWord_Input = KeyWord
TemplateSignalName = "TestSignalName"
def GetSignal_PVIDName(self):
return 'PVID_' + self.CmdKeyWord.upper()
def GetSignal_InitCode(self):
codeTemplate = '''
'''
rst = re.sub(self.TemplateSignalName, self.CmdKeyWord, codeTemplate)
return rst
def GetSignal_PVIDCode(self):
codeTemplate = '''
'''
template_mdlsetPVID = "mdl_SetxxxxxxxxScreen_xxxxxxxx"
Generate_mdlsetPVID = "mdl_SetxxxxxxxxScreen_" + self.CmdKeyWord_Input
rst = re.sub(template_mdlsetPVID, Generate_mdlsetPVID, codeTemplate)
template_mdlgetPVID = "mdl_GetxxxxxxxxxxxScreen_xxxxxxx"
Generate_mdlgetPVID = "mdl_GetxxxxxxxxxxxScreen_" + self.CmdKeyWord_Input
rst = re.sub(template_mdlgetPVID, Generate_mdlgetPVID, rst)
return rst_Gen
def GetIncludeHeader_Presenter(self):
return '#include "' + self.CmdKeyWord + 'Screen/' + self.CmdKeyWord + 'Presenter.hpp"'
if __name__ == '__main__':
if(sys.argv[1:] == []):
print('Not input parameter , Use Test Data')
CmdKeyWord = 'TestInput'
else:
CmdKeyWord = sys.argv[1]
# code = BuildCode_MVP(CmdKeyWord)
#code.Generate()
MVPGenerator_Blog.py
# -*- coding: utf-8 -*-
from tkinter import *
from MVPCodeBuilder_Blog import *
print('GUI start...')
def ShowSendtoDUT(wlcmd):
SendDut = '\n\r >>[Failed Log] >>:\n\r'
inputData.insert(END, SendDut)
inputData.insert(END, wlcmd)
def ShowRcvfromDUT(rst):
# RcvDut = ' \n\r >>[MVP Code Generator] >>:\n\r'
# txt.insert(END, RcvDut)
txt.insert(END, rst)
def OnCommandInput():
InputCmd = Et_CommandInput.get()
if(len(InputCmd) == 0):
ShowRcvfromDUT("\n\r未输入内容!")
else:
code = BuildCode_MVP(InputCmd)
code.Generate()
ShowRcvfromDUT('\n\rStatus: All MVP File Generated OK!\n\r')
ShowRcvfromDUT('Here is code for reference use:')
def OnSignalButton():
InputCmd = Et_SignalCommandInput.get()
if (len(InputCmd) == 0):
ShowRcvfromDUT("\n\r未输入内容!")
else:
code = BuildCode_Signal(InputCmd)
ShowRcvfromDUT('Here is code for reference use:')
ShowRcvfromDUT(code.GetSignal_InitCode())
ShowRcvfromDUT(code.GetSignal_PVIDCode())
def clearSendContent():
inputData.delete(1.0, END)
def clearRcvContent():
txt.delete(1.0, END)
#Tkinter code below
root = Tk()
root.geometry('1000x600')
root.title('MVP Code Generator Tools')
root.config(bg='#f0ffff')
#Lable
Lb_CommandInput = Label(root,text='输入 MVP Screen Name:',\
# bg='#d3fbfb',\
fg='red',\
font=('华文新魏',10),\
width=28,\
height=2,\
relief=RIDGE)
Lb_CommandInput.place(relx=0.125, rely=0.237, relwidth=0.15, relheight=0.05)
Lb_CommandInput = Label(root,text='输入 Signal Name:',\
# bg='#d3fbfb',\
fg='red',\
font=('华文新魏',10),\
width=28,\
height=2,\
relief=RIDGE)
Lb_CommandInput.place(relx=0.125, rely=0.537, relwidth=0.15, relheight=0.05)
intro = Label(root,text='请在下方输入MVP要生成的ScreenName,然后点击Generate',\
bg='#d3fbfb',\
fg='red',\
font=('华文新魏',14),\
width=20,\
height=2,\
relief=RIDGE)
intro.place(relx=0.1, rely=0.1, relwidth=0.8, relheight=0.1)
ContactLable = Label(root, text='联系人:HowardXue ',\
# bg='#d3fbfb',\
fg='red',\
font=('',12),\
width=20,\
height=2,\
relief=RIDGE)
ContactLable.place(relx=0.7, rely=0.03, relwidth=0.25, relheight=0.05)
#Output
txt = Text(root, font = ('',10))
txt.place(relx=0.3, rely=0.2, relwidth=0.6, relheight=0.625)
#lable
#Entry
Et_CommandInput = Entry(root, bd =5, relief=GROOVE)
Et_CommandInput.place(relx=0.125, rely=0.3, relwidth=0.15, relheight=0.05)
Et_SignalCommandInput = Entry(root, bd =5, relief=GROOVE)
Et_SignalCommandInput.place(relx=0.125, rely=0.6, relwidth=0.15, relheight=0.05)
#Button
bt_bin2json = Button(root, text='MVP Code Generate', command=OnCommandInput, fg ='blue')
bt_bin2json.place(relx=0.1, rely=0.38, relwidth=0.2, relheight=0.1)
signalButton = Button(root, text='Signal PVID Code Generate', command=OnSignalButton, fg ='blue')
signalButton.place(relx=0.1, rely=0.68, relwidth=0.2, relheight=0.1)
# bt_clear = Button(root, text='Clear', command=clearSendContent, fg ='blue')
# bt_clear.place(relx=0.15, rely=0.825, relwidth=0.2, relheight=0.1)
bt_clear_rcv = Button(root, text='Clear', command=clearRcvContent, fg ='blue')
bt_clear_rcv.place(relx=0.45, rely=0.825, relwidth=0.2, relheight=0.1)
#comboxlist.pack()
root.mainloop()
其他好玩的python脚本
Python实现自动发送邮件 --自动抓取博客/网站中留言的邮箱并发送相应邮件
Python自动生成代码 - 通过tkinter图形化操作并生成代码框架
Python解析CSV数据 - 通过Pandas解析逻辑分析仪导出的CSV数据
Python通过Django搭建网站执行Lua脚本 (实现数据解析)
博主热门文章推荐:
一篇读懂系列:
- 一篇读懂无线充电技术(附方案选型及原理分析)
- 一篇读懂:Android/iOS手机如何通过音频接口(耳机孔)与外设通信
- 一篇读懂:Android手机如何通过USB接口与外设通信(附原理分析及方案选型)
LoRa Mesh系列:
- LoRa学习:LoRa关键参数(扩频因子,编码率,带宽)的设定及解释
- LoRa学习:信道占用检测原理(CAD)
- LoRa/FSK 无线频谱波形分析(频谱分析仪测试LoRa/FSK带宽、功率、频率误差等)
网络安全系列:
- ATECC508A芯片开发笔记(一):初识加密芯片
- SHA/HMAC/AES-CBC/CTR 算法执行效率及RAM消耗 测试结果
- 常见加密/签名/哈希算法性能比较 (多平台 AES/DES, DH, ECDSA, RSA等)
- AES加解密效率测试(纯软件AES128/256)–以嵌入式Cortex-M0与M3 平台为例
嵌入式开发系列:
- 嵌入式学习中较好的练手项目和课题整理(附代码资料、学习视频和嵌入式学习规划)
- IAR调试使用技巧汇总:数据断点、CallStack、设置堆栈、查看栈使用和栈深度、Memory、Set Next Statement等
- Linux内核编译配置(Menuconfig)、制作文件系统 详细步骤
- Android底层调用C代码(JNI实现)
- 树莓派到手第一步:上电启动、安装中文字体、虚拟键盘、开启SSH等
- Android/Linux设备有线&无线 双网共存(同时上内、外网)
AI / 机器学习系列:
- AI: 机器学习必须懂的几个术语:Lable、Feature、Model…
- AI:卷积神经网络CNN 解决过拟合的方法 (Overcome Overfitting)
- AI: 什么是机器学习的数据清洗(Data Cleaning)
- AI: 机器学习的模型是如何训练的?(在试错中学习)
- 数据可视化:TensorboardX安装及使用(安装测试+实例演示)
更多推荐
Python自动生成代码(二)- 基于MVP架构的C/C++ 代码生成器实例
发布评论