文章目录
- 前言
- 一、用到的Python模块
- 二、程序说明
- 1.代码
- 2.操作步骤
- 3.PPT模板和EXCEL逻辑文件制作说明
- 建立EXCEL逻辑表
- 配置PPT模板
前言
例如:网上和书本中介绍的ppt自动化方法,多是一步步制作ppt,而实际例行工作中多是修改文字和数字,粘贴表格和图片等。所以研究了下可以通过excel配置ppt制作步骤的方法,便于模板不变材料的半自动化制作。核心是业务,本方法是技术上的辅助,模拟人工制作ppt的步骤。
该方法效果:个人平时25分钟制作完的ppt材料(纯制作,不含数据处理时间)。在excel配置好的情况下,点一下更新链接,然后选择ppt模板和逻辑excel,大概20s可以制作完24页ppt。文字更新速度很快,表格更新需要消耗一点时间。
一、用到的Python模块
1、tkinter:制作简单的操作界面;
2、win32com:模拟ppt和excel软件的操作,感觉与vba类似
3、pandas:读取表格数据用
4、re:判断并修改ppt中文字用
5、os:读取和保存文字用
二、程序说明
1.代码
代码如下:
# coding:utf-8
# Author:Matthew
from tkinter import *
from tkinter import filedialog
from tkinter.ttk import Progressbar
#分割路径和文件名
import os.path
#读取excel文件模块
import pandas as pd
#文本处理模块
import re
#设想,读取excel列表,图片名称、单击、间隔时长、步骤说明
#win32程序的操作模块
import win32com
from win32com.client import Dispatch, constants
import time
class MYauto():
def __init__(self,init_window_name):
#传递实例化的窗口
self.init_windows_name = init_window_name
#文件路径self.folder
#是否找到
self.isfind = 0
self.error_texts =[]
def set_init_window(self):
# 设置窗体标题
self.init_windows_name.title('Python GUI MakePPT.v3')
# 设置窗口大小和位置
self.init_windows_name.geometry('500x500+570+200')
self.label1 = Label(self.init_windows_name, text='请选择PPT模板文件:')
self.text1 = Entry(self.init_windows_name, bg='white', width=30)
self.label2 = Label(self.init_windows_name, text='请选择excel逻辑文件:')
self.text2 = Entry(self.init_windows_name, bg='white', width=30)
self.label3 = Label(self.init_windows_name, text='请修改ppt保存名称:')
self.text3 = Entry(self.init_windows_name, bg='white', width=30)
self.label4 = Label(self.init_windows_name, text='记录:')
self.button1 = Button(self.init_windows_name, text='浏览', width=8, command=self.selectPptfile)
self.button4 = Button(self.init_windows_name, text='浏览', width=8, command=self.selectExcelfile)
self.button2 = Button(self.init_windows_name, text='开始', width=8, command=self.main)
self.button3 = Button(self.init_windows_name, text='保存', width=8, command=self.save_ppt)
self.button5 = Button(self.init_windows_name, text='扫描ppt元素', width=12, command=self.lookshape)
#消息文本框
self.log_data_Text = Text(self.init_windows_name, bg='white', width=60,height=20)
self.log_data_Text.pack()
self.label1.pack()
self.text1.pack()
self.label2.pack()
self.text2.pack()
self.label3.pack()
self.text3.pack()
self.button1.pack()
self.button4.pack()
self.button2.pack()
self.button3.pack()
self.button5.pack()
self.label4.pack()
#设定位置
self.label1.place(x=30, y=30)
self.text1.place(x=150, y=30)
self.label2.place(x=30, y=70)
self.text2.place(x=150, y=70)
self.label3.place(x=30, y=110)
self.text3.place(x=150, y=110)
self.button1.place(x=400, y=26)
self.button4.place(x=400, y=66)
self.button2.place(x=160, y=150)
self.button3.place(x=260, y=150)
self.button5.place(x=30, y=150)
self.label4.place(x=30, y=185)
# 创建滚动条
self.scroll = Scrollbar()
self.log_data_Text.place(x=30, y=210)
# 将滚动条填充
self.scroll.pack(side=RIGHT, fill=Y,padx=10,pady=100) # side是滚动条放置的位置,上下左右。fill是将滚动条沿着y轴填充
# 将滚动条与文本框关联
self.scroll.config(command=self.log_data_Text.yview) # 将文本框关联到滚动条上,滚动条滑动,文本框跟随滑动
self.log_data_Text.config(yscrollcommand=self.scroll.set,state=NORMAL) # 将滚动条关联到文本框
#添加一个进度条
self.var = IntVar()
self.var.set(0)
Progressbar(self.init_windows_name,variable=self.var,length=400).place(x=60, y=185)
#self.progressbar1['value']
#添加菜单
#menu1 = Menu(self.init_windows_name)
#menu1.add_command(label="帮助",command = self.help())
#self.init_windows_name.config(menu=menu1)
#def help(self):
#初始显示信息
self.write_log_to_Text("作者:大豆\n0.扫描ppt元素用于确定表格的shape编号\n1.通过浏览按钮选择好ppt模板和excel数据及逻辑即可开始\n2.完成后,请修改名称后点保存\nPS:逻辑的sheet页一定要放在第一个")
def selectPptfile(self):
#获取ppt模板文件信息
self.file_path = filedialog.askopenfilename(title='选择PPT文件模板', filetypes=[('Ppt', '*.pptx'), ('All Files', '*')])
self.write_log_to_Text(self.file_path)
self.text1.insert(INSERT, self.file_path)
#记录路径文件夹
self.file_folder,self.f = os.path.split(self.file_path)
self.text3.insert(INSERT, self.f)
#打开ppt模板
self.open_ppt(self.file_path)
def selectExcelfile(self):
#获取excel数据
self.file_path2 = filedialog.askopenfilename(title='选择Excel文件模板', filetypes=[('Excel', '*.xlsx'), ('All Files', '*')])
self.write_log_to_Text(self.file_path2)
self.text2.insert(INSERT, self.file_path2)
#记录路径文件夹
self.file_folder2,f2 = os.path.split(self.file_path2)
#打开excel逻辑及数据表,数据表在excel中做了链接
self.open_excel(self.file_path2)
#self.write_log_to_Text(self.Tj)
def stop(self):
#把程序停止
self.isstart = 0
pass
def open_ppt(self,file_path):
self.ppt = win32com.client.Dispatch('PowerPoint.Application')
# 是否展示打开的文件
self.ppt.Visible = True
# 屏蔽错误弹框提示
self.ppt.DisplayAlerts = False
# 打开ppt,r'C:\python\MakePPT\2022年3月份运输优化方案.pptx'
self.pptS = self.ppt.Presentations.Open(file_path)
def open_excel(self,file_path):
self.xlApp = win32com.client.Dispatch("Excel.Application")
# 是否展示打开的文件
self.xlApp.Visible = True
# 屏蔽错误弹框提示
# 打开excel,r'C:\python\MakePPT\逻辑MakePPT.xlsx'
self.xlS = self.xlApp.Workbooks.Open(file_path, False)
def write_textK(self,slide_order):
'''
对文本框内容进行查找,替换【数字】为所需数据或文字
slide_order为ppt页数
'''
for i_shape in range(self.pptS.Slides(slide_order).Shapes.count):
#
shape_type = self.pptS.Slides(slide_order).Shapes(i_shape + 1).type
if shape_type == 17 or shape_type == 1: # 判断是否是文本框,并写入
Text_shape = self.pptS.Slides(slide_order).Shapes(i_shape + 1).TextFrame.TextRange.Text
self.write_log_to_Text(Text_shape)
target_list = re.findall(r'[\[](.*?)[\]]', Text_shape) # 匹配符合条件的【数字】
if target_list == []:#如果没有就下一个
pass
else:
for i_text in target_list:
self.write_log_to_Text(i_text)
# 找到替换所需值或文字
find_target = '[' + i_text + ']'
# 目标所在行
self.write_log_to_Text(find_target)
try:
Row_input = self.xlS.Worksheets(1).Cells.Find(What=find_target).Row
except:
self.write_log_to_Text("找不到该值,导入数据"+find_target)
else:
# 目标所在列
#self.xlS.Worksheets('PPT逻辑').Cells.Find(What=find_target).Column
# 获取G列导入数据,并改成文本格式
data_input = str(self.xlS.Worksheets(1).Cells(Row_input, 7).Value)
# 替换文本框的内容
self.pptS.Slides(slide_order).Shapes(i_shape + 1).TextFrame.TextRange.Text = \
self.pptS.Slides(slide_order).Shapes(i_shape + 1).TextFrame.TextRange.Text.replace(find_target,data_input)
elif shape_type == 19: # 判断是否是表格,并写入
#slide_order,i_shape + 1
#tableshape = Tj.loc[(Tj['类型'] == '表格') & (Tj['ppt页数'] == 2) & (Tj['shape'] == 4)]
tableshape = self.Tj.loc[(self.Tj['类型'] == '表格') & (self.Tj['ppt页数'] == slide_order) & \
(self.Tj['shape'] == i_shape + 1)]
#找要转成图片的表格
tablepic = self.Tj.loc[(self.Tj['类型'] == '图片') & (self.Tj['ppt页数'] == slide_order) & \
(self.Tj['shape'] == i_shape + 1)]
if len(tableshape) == 0 and len(tablepic) == 0:#如果没有就下一个
pass
elif len(tableshape) != 0 and len(tablepic) == 0:
#用表格方式粘贴
for i_table in tableshape['index']:
# shape是i_shape+1,slide是
# excel数据源的单元区域
source_sheet = tableshape['数据源'][i_table]
source_data = tableshape['导入数据'][i_table]
try:
# zh
self.xlS.Worksheets(source_sheet).Range(source_data).Copy()
#保留原格式粘贴
self.pptS.Application.CommandBars.ExecuteMso("PasteSourceFormatting")
#不停一下会出错
time.sleep(0.6)
self.pptS.Application.windows(1).selection.ShapeRange.Left = self.pptS.Slides(slide_order).Shapes(i_shape + 1).Left
self.pptS.Application.windows(1).selection.ShapeRange.Top = self.pptS.Slides(slide_order).Shapes(i_shape + 1).Top
self.pptS.Application.windows(1).selection.ShapeRange.Width = self.pptS.Slides(slide_order).Shapes(i_shape + 1).Width
self.pptS.Application.windows(1).selection.ShapeRange.Height = self.pptS.Slides(slide_order).Shapes(i_shape + 1).Height
#获取需要增大几次字号,相对的
Font_Increase = tableshape['字号增大N次'][i_table]
try:
#如果出错就跳过
Font_inc = int(Font_Increase)
#增大N次
for i_increase in range(Font_inc):
#增大一下字号
self.pptS.Application.CommandBars.ExecuteMso("FontSizeIncrease")
except:
pass
self.write_log_to_Text(
'ppt' + str(slide_order) + '位置' + str(i_shape + 1) + '的表格' + '已原格式粘贴更新')
# 删除原表格
self.pptS.Slides(slide_order).Shapes(i_shape + 1).delete()
except:
error_text = 'ppt' + str(slide_order) + '位置' + str(i_shape + 1) + '的表格' + '原格式粘贴更新失败'
self.write_log_to_Text(error_text)
self.error_texts.append(error_text)
elif len(tableshape) == 0 and len(tablepic) != 0:
#用图片方式粘贴
for i_table in tablepic['index']:
#shape是i_shape+1,slide是
#excel数据源的单元区域
source_sheet = tablepic['数据源'][i_table]
source_data = tablepic['导入数据'][i_table]
try:
#zh
self.xlS.Worksheets(source_sheet).Range(source_data).Copy()
ins_shape = self.pptS.Slides(slide_order).Shapes.PasteSpecial(DataType=3)
#调整图片位置,依靠宽度,解除锁定纵横比
ins_shape.LockAspectRatio = 0
ins_shape.left = self.pptS.Slides(slide_order).Shapes(i_shape+1).Left
ins_shape.Top = self.pptS.Slides(slide_order).Shapes(i_shape+1).Top
ins_shape.Width = self.pptS.Slides(slide_order).Shapes(i_shape+1).Width
ins_shape.Height = self.pptS.Slides(slide_order).Shapes(i_shape+1).Height
self.write_log_to_Text('ppt'+str(slide_order)+'位置'+str(i_shape + 1)+'的表格'+'已用图片更新')
#删除原表格
self.pptS.Slides(slide_order).Shapes(i_shape + 1).delete()
except:
error_text = 'ppt' + str(slide_order) + '位置' + str(i_shape + 1) + '的表格' + '图片更新失败'
self.write_log_to_Text(error_text)
self.error_texts.append(error_text)
else:
#图片和表格两种更新方式冲突,需修改excel
self.write_log_to_Text('ppt' + str(slide_order) + '位置' + str(i_shape + 1) + '表格更新方式冲突,需修改excel')
else:
pass
def save_ppt(self):
#保存ppt
ppt_name = self.text3.get()
if ppt_name == self.f:
self.write_log_to_Text("文件名称重复,请修改")
else:
self.write_log_to_Text(ppt_name)
self.pptS.SaveAs(self.file_folder + '\\' + ppt_name)
def main(self):
#是否继续
self.isstart = 1
#标志是1,则开始执行
#获取ppt逻辑数据
self.Tj = pd.read_excel(self.file_path2,sheet_name=0).reset_index()
#source_data = self.xlS.Worksheets('PPT逻辑')
#从第1页开始,看是否要改
for i_slide in range(self.pptS.Slides.count):
# 切换到目标页
self.pptS.Application.ActiveWindow.View.GotoSlide(i_slide+1)
#开始写入
self.write_textK(i_slide+1)
#进度条
self.var.set(80)
self.write_log_to_Text('更新完成,可能存在以下错误:')
self.write_log_to_Text(self.error_texts)
#self.write_textK(2)
#self.write_log_to_Text(i_slide+1)
pass
def lookshape(self):
i = 1
for slide in self.pptS.Slides:
self.write_log_to_Text("第%d页ppt:" %(i))
i+=1
j = 1
for shape in slide.shapes:
if shape.type == 17:
type = "文本框"
elif shape.type == 19:
type = "表格"
elif shape.type == 1:
type = "形状"
elif shape.type == 13:
type = "图片"
elif shape.type == 7:
type = "公式"
elif shape.type == 14:
type = "占位符"
elif shape.type == 15:
type = "艺术字"
else:
type = "其它"
self.write_log_to_Text("shape %d : %s"%(j,type))
j+=1
pass
def countshape(self,slides_order):
#记录当前ppt中的shape数量,但是新粘贴的好像不计入,那么就默认加1
i=0
for shape in self.pptS.Slides(slides_order).Shapes:
i+=1
return i
#日志打印
def get_current_time(obj):
current_time = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
return current_time
#写入日志
def write_log_to_Text(self,logmsg):
current_time = self.get_current_time()
logmsg_in = str(current_time) +" " + str(logmsg) + "\n" #换行
self.log_data_Text.insert(END, logmsg_in)
self.log_data_Text.see(END)
def operation(self,opt,key):
pass
#if opt == "输入":
if __name__ == '__main__':
init_window = Tk() #实例化出一个父窗口
MAIN_PROCESS = MYauto(init_window)
# 设置根窗口默认属性
MAIN_PROCESS.set_init_window()
init_window.mainloop()
2.操作步骤
1、运行代码
2、选择ppt模板
3、选择逻辑excel
4、运行程序
5、修改文件名并保存
PS:如果第一次使用,需要将ppt制作成模板,并创建excel逻辑和数据表
。
3.PPT模板和EXCEL逻辑文件制作说明
提示:本方法只能更新文本框和表格。
1、PPT模板制作第一步是准备一个经常汇报的ppt
2、将里面要改的文字或数字,改成[1]、[2]、[3]等
3、在excel中写下[1]、[2]、[3]对应的内容
4、表格的话,需要用程序中的扫描,看下表格处于第几个位置(shape)
复制原表的话,可配合字号增大使用;粘成图片的话,凑活看也可以
建立EXCEL逻辑表
提示:EXCEL中必要的列,第一行列名必须有这几个,程序也是依此运行
列1 | ppt页数 |
列2 | 数据源 |
列3 | 类型 |
列4 | shape |
列2 | 目标位置 |
列3 | 导入数据 |
列4 | 字号增大N次 |
ppt页数:写上要修改的ppt页码
数据源:如果是文字不用写,可以做些链接用于自己更新数;如果是表格或图片形式粘表格的话,需要写明取自该excel的哪个sheet页
类型:写明是更新文字还是表格,还是用图片形式更新表格
shape:文字的话不用写,表格的话,需要写明表格的shape(用程序的扫描功能可以看到每页ppt的shape都是啥,找到表格是shape几)
目标位置:写明文字是要替换掉页面上的哪个位置,用英文括号和数字来制作ppt模板,如[1],表格不用写
导入数据:写入用什么来替换掉目标位置。可以写数字或文字
字号增大N次:因为发现表格粘贴后,文字可能会变小,增加此列,定性增大表格字号,相当于手动点字号增加。
其他列是辅助或标注用的。
配置PPT模板
1、想替换掉的地方改成英文中括号+数字
2、想更新表的地方,把表格大小拉至合适,程序复制粘贴后会保持一样大小,并删除原表
PS:这样在excel中可以自己设置各种公式,判断数字大小写不同文字等,并且excel中格式就是粘到ppt的格式,字号粘贴过程中容易变小,可定性增大。使用过程如图
程序文件,可执行exe版文件、ppt和excel示例上传至付费资源中,上面的代码是全部了,用pycharm之类可以自己运行和制作模板。