8751| 1
|
[教程] 【Mind+Python】人人都能学会的翻译小助手 |
图 1 翻译小助手运行界面 #项目起源# 上一期我们通过Mind+Python制作了一款天气查询的小助手,本次我们继续使用网络请求库和图形化界面库制作一款翻译助手小程序 下面我们先通过动图来了看一下是如何通过Python 实现翻译功能的 #动图展示# 图 2 翻译小助手动图演示 #程序设计# 通常,我们遇到不认识的英语单词或者短语,会采用查字典或者网络翻译的方式去解决,其中网络翻译是一种快速有效的方式,会被大多数人采用。实现网络翻译常用的网站有有道翻译、百度翻译、谷歌翻译等 百度翻译: 有道翻译: 谷歌翻译: 此类型的网站使用的方法很简单,只需要输入想要翻译的内容即可给出结果,我们本次就以有道翻译网站为例制作一款可以实现中英互译功能的翻译小助手, 其他翻译网站实现翻译的方法大同小异,大家可以自行尝试 #编程思路# 图 3 翻译小城助手程序设计思维导图 #准备工作# 准备编程环境 关于用来编写Python程序的编程环境上一期天气查询小助手 中我们已经做过详细介绍,本次我们还是使用简单易入门的Mind+图形化编程环境进行程序编写,当然Mind+编写的程序其他软件中也是适用的 如果还没有安装Mind+编程环境可以在电脑浏览器登录mind+网站,选择与自己电脑匹配的安装包下载软件 Mind+图形化编程环境下载地址:http://mindplus.cc/ 图 4 mind+下载 软件下载完成后双击安装包安装软件 安装成功,双击mind+图标打开软件 图 5软件安装完成 安装Python库及创建文件 从上一期内容中我们知道Mind+图形化编程环境集成了多种编程模式,分别是实时的scratch模式,涉及多种开源硬件的上传模式以及Python模式,我们使用mind+软件的Python模式,Python模式如下图6 图 6 mind+软件的Python模式 在软件中选择Python模式后,我们点击软件右侧文件目录,在“电脑中的文件”中添加文件,点击位置如下图14红色框所示 图 7 在mind+中添加本地文件 然后,我们在自己熟悉的路径下新建一个专门用来存放Python程序的文件夹并选中该文件夹后点击确定 图 8 选择文件夹 之后,我们点击新建文件,即可在当前文件夹下创建Python程序 我们给新建的文件取一个名字 图 9 命名文件 右击Python程序文件,选择在编辑区打开 图 10 在编辑区打开文件 接下来,我们就可以在程序编辑区随心所欲的编写程序了 图 11 mind+Python模式界面布局 翻译小助手需要访问有道翻译网站获取数据,要获取网络数据,就需要安装HTTP网络请求库“requests”,安装方法如下: 在mind+软件的右上角点击库管理按钮,如下图12所示 图 12 安装第三方库 之后会看到如下界面,在推荐库一栏提供了大部分常用第三方库,可以一键安装,我们点击“爬虫”分类库下面的requests库进行安装,安装完毕会看到“已安装”的提示字样,表明安装完成,如下图13 图 13 安装第三方库 库列表中可以查看目前电脑中已经安装过的第三方库 图 14 已安装库列表 我们除了可以在推荐库一栏选择第三方库进行安装以外,还可以选择PIP模式安装第三方库,这里的PIP 指的是一个 Python 第三方库的管理工具 ,你可以把它简单的理解为,一个大管家,它可以实现对Python 库的查找、下载、安装、卸载等功能,比如安装一个“requests”库,我们只需要在搜索栏输入“requests”即可 图 15 在mind+中使用PIP安装第三方库 “requests”安装完成后,我们可以在程序编辑界面输入如下程序来测试是否安装成功 #导入requests库import requests 用来查看运行结果显示区的按钮在软件的右上角,如图16 图 16 运行按钮 我们点击运行按钮验证“requests”库是否安装成功,如图17 图 17 验证第三方库是否安装成功 如果运行后并没有报错,表示“requests”库安装成功 “requests”库安装成功,接着我们来尝试使用“requests”库访问有道翻译网站,上一期我们使用了“requests.get()”指令获取天气数据,这次同样使用该指令进行初步测试 使用requests库请求网络数据 我们在Mind+中输入如下程序: #导入requests库 import requests #将有道翻译API地址放入“url”变量中 url = 'http://fanyi.youdao.com/ ' #向有道翻译API发送网络请求,并将返回的数据放入变量“ http_data”中http_data = requests.get(url)print(http_data)
图 18 向有道翻译API发送网络请求 程序中通过“requests.get()”语句向有道翻译API地址发送请求,程序运行后返回的原始数据为“Response[200]”, 证明我们已经访问成功了,只是我们需要对程序稍作修改即可查看返回的具体内容,修改内容如下 http_data = requests.get(url).text
我们将原始数据转换为text文本格式后再打印输出,运行结果如下图19 图 19 将html格式数据转换成text文本格式 观察运行结果,大概可以知道,返回的数据为“html”格式,我们需要从中提取一些有用的信息。不过,磨刀不误砍柴工,先在电脑浏览器中访问一下有道翻译网站,熟悉一下翻译流程再进一步修改程序,有道翻译网站如下图20 图 20 浏览器登录有道翻译 我们在有道翻译网站页面中单击鼠标右键,点击检查功能,可以在界面的右侧看到有道翻译网站的后台数据,如下图21所示。仔细观察你会发现这些数据和前文中我们通过“requests.get()”语句请求到的数据是一样的 图 21 查看有道翻译后台数据 我们进一步查看数据,尝试在界面左侧的输入栏中输入“你好”,在翻译栏中会看到自动翻译成英文的“hello”。 图 22 查看有道翻译后台数据 只不过,我们在输入栏中输入内容前,需要按照上图22中的顺序先点击“Network”,再点击“Fetch/HR”选项,接着,我们在输入栏中输入相应内容即可看到如图23的信息了 图 23 查看有道翻译后台数据 从这些信息中,我们可以看出实现一次翻译过程包含的数据, 其中“RequestURl”为翻译的API地址,“Request Method”为网络请求类型 从“Request Method”中我们可以看出有道翻译网站的请求类型为“POST”类型 而上一期天气查询小程序使用的是“requests.get()”请求,“POST”和“GET”有什么不同呢?为什么有道翻译网站使用的网络请求类型是“POST” 其实HTTP网络请求类型包含“GET”和“POST”两种,而“POST”类型和“GET”类型最大的区别是,“POST”类型在网络请求时一般都需要提交表单,也就是在网络请求时还需要向服务器传输各种类型的数据,而“GET”类型的网络请求则只是向服务器获取一些数据,这个获取数据的过程可以理解为简单的查询 知道这些知识背景后,我们再回过头来看翻译小助手的程序,要翻译一个单词或短语需要将翻译的内容发送给有道翻译网站,也就是要在网络请求的同时要携带一部分数据。由此看来,我们应该采用“POST”网络请求类型来完成本次程序的编写。 在网络请求过程中具体应该携带哪些参数呢?我们可以向下查看“Form Data”这一栏的内容,经过前期尝试, 其中“i”、“from”、“to”、“client”、“doctype”是必须携带的参数,其他参数为非必须,当然如果数据不多的话可以不用测试,全部带入也是可以的,数据如图24 图 24 有道翻译中的Form Data数据 了解这些必要的数据后,我们可以继续修改程序 首先,将url变量中的内容修改为“RequestURl”地址 接下来,新建“data”字典,将“POST”网络请求时携带的数据存放在“data”字典中,程序如下 #导入requests库 import requests #将有道翻译API地址放入“url”变量中 url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule' #新建data字典,用来存放POST请求时需要携带的数据 data = {} data['i'] = "你好" data['doctype'] = 'json' data['from'] = 'AUTO' data['to'] = 'AUTO' data['client'] = 'fanyideskweb' #向有道翻译API发送网络请求,并将返回的数据放入变量“ http_data”中http_data = requests.post(url=url,data=data).textprint(http_data)
程序运行结果如下图25 图 25 向有道翻译网站发送POST网络请求结果 观察运行结果,可以看出网络请求后返回了一个字典类型的数据 我们将字典类型的数据内容整理如下: {'type': 'ZH_CN2EN', 'errorCode': 0,' elapsedTime': 0,' translateResult': [ [ {'src': '你好', 'tgt': 'hello' }] ]} 我们知道字典里的内容是从0开始计数的,返回的字典数据中第2项“translateResult”中包含了输入中文“你好”后的翻译结果“hello”,只不过这个数据藏的有点深,它藏在了“translateResult”数据下的第二层列表中,第二层列表的内容又是以字典形式存在的,拿到这个藏的很深的字典数据就是我们最终想要的结果。 我们要做的就是按照字典类型里数据提取的方法将其提取出来即可,在原有程序中增加如下内容 #将http_data中的数据解析为json格式 dict_data = json.loads(http_data) #提取字典中的有效数据 result = dict_data["translateResult"][0][0]["tgt"] print(f'翻译结果:{result}')
程序中我们需要将“POST”网络请求后的数据解析为json格式,之后才能按照字典的方式提取数据,不过在使用json库之前,我们需要导入json库,程序运行结果如下图26 图 26 提取有效翻译数据 目前为止,我们已经可以实现指定的内容翻译了,如何才能实现键盘输入内容实时给出翻译结果呢 有的朋友应该会想到,我们可以使用“input”指令从键盘获取输入内容,没错,我们继续修改程序 #获取要翻译的内容word = input("请输入需要翻译的内容:")#将键盘获取的内容放入字典中data['i'] = word 程序运行后会看到如下图27所示结果,运行结果中红色部分为返回的字典数据,我们可以设置为不打印 图 27 获取键盘输入内容并翻译 也就是删除“print(http_data)”这条指令即可,修改后运行测试,结果如图28 图 28 整理输出打印的数据 测试没问题,我们对程序再稍作修改,将其封装在一个“translate”函数中,程序如下 #导入requests库 import requests #导入json库 import json #翻译函数 deftranslate(): #将有道翻译API地址放入“url”变量中 url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule' #获取要翻译的内容 word = input("请输入需要翻译的内容:") #新建data字典,用来存放POST请求时需要携带的数据 data = {} data['i'] = word data['doctype'] = 'json' data['from'] = 'AUTO' data['to'] = 'AUTO' data['client'] = 'fanyideskweb' #向有道翻译API发送网络请求,并将返回的数据放入变量“http_data”中 http_data = requests.post(url=url,data=data).text #将http_data中的数据解析为json格式 dict_data = json.loads(http_data) #提取字典中的有效数据 result = dict_data["translateResult"][0][0]["tgt"] print(f'翻译结果:{result}')
至此,翻译小助手已经实现了基本的中英文互译功能,接下来我们需要设计一个实用美观的界面,让小程序看得高大上一些 下面,我们就使用Python自带的tkinter库来完成图形化界面的设计 使用Tkinter库设计图形化界面 什么是tkinter库呢,上一期的项目中我们已经知道了 它是一个可以快速的创建图形化的应用界面的自带库 因为Python安装环境自带库,我们可以直接使用,为了不增加难度,我们重新建一个新程序来学习使用tkinter库,基本用法掌握后再与翻译小助手的程序结合 图 29 新建图形化界面设置程序 第一步我们来创建图形化界面 创建窗口 在mind+软件中编写如下程序 #导入tkinter库 from tkinter import * #创建窗口 root = Tk() root.title('翻译小助手')#设置窗口标题 #设置窗口大小(窗口横向长度X窗口纵向长度+距离屏幕左边框的横向距离+距离屏幕上边框的纵向距离) root.geometry('400x350+200+200') root.mainloop()#窗口循环运行
运行上述程序,会看到下图30所示的结果,在电脑屏幕中显示出了一个400像素宽,350像素高的空白窗口 图 30 创建窗口 我们再来看刚才的程序,在窗口界面设置中,root.geometry('400x350+200+200') 里的参数可以来调整窗口尺寸和显示的位置,参数中第1个数字为窗口的宽度,第2个数字为窗口的高度,第3个数字为窗口的左上角距离屏幕左边框的横向距离,第4个数字为窗口的左上角距离屏幕上边框的纵向距离 窗口新建完成,我们就可以在窗口内布置各种组件了 我们先使用Label标签为翻译小助手添加一个标题,关于Label标签在上一期中做过介绍,它是一个用于在指定的窗口中显示文本和图像的组件 设置Label标签 在编程环境中我们输入如下程序 #导入tkinter库 from tkinter import * #创建窗口root = Tk() root.title('翻译小助手')#设置窗口标题 #设置窗口大小(窗口横向长度X窗口纵向长度+距离屏幕左边框的横向距离+距离屏幕上边框的纵向距离) root.geometry('400x350+200+200') #定义label标签 Label(root, text='简易翻译器',#标签的文字 font=('Arial', 12)#设置字体和字号 ).grid(row=0,column=0)# 将标签放置在窗口的第0行,第0列位置 root.mainloop()#窗口循环运行
程序运行后,我们会看到如下图31所示的运行结果,由Label标签设置的“简易翻译器”几个汉字会显示在窗口的左上方也就是第0行,第0列的位置 图 31 放置Label标签 Label标签显示的效果还可以通过修改程序中Label的文字内容“text=”,文字“fg=”或背景颜色“bg=”,字体和字体大小“font=()”以及标签的尺寸“width= ,height= ”来调整Label在窗口中的显示效果,如果不设置文字或背景颜色,则会默认为黑色文字白色背景 从上一期的内容中我们可以知道tkinter中的组件布局显示在窗口的中方法有“pack()”、“place()”以及“grid()”,三种组件布局的方式不可以混用 本文我们使用grid()方法来做讲解 以上,我们成功放置了Label标签,除Label标签外本次翻译小助手程序还会用到tkinter中的Entry输入栏、Button按钮和Text文本框,接下来我们学习Entry输入框的布局方法 Entry输入栏放置 Entry输入框可以用来获取键盘输入的内容也可以用来显示单行文本 可以用来让用户输入用户信息,比如可以使用Entry设置登录网页时的输入框 在这里我们为翻译小助手增加一个Entry输入框,用来获取键盘输入的待翻译内容 在前文中程序中增加Entry程序 #定义输入框 enter = Entry(root)#输入框 enter.grid(row = 1,column=0)#调整位置 root.mainloop()#窗口循环运行
程序运行后,会看到窗口中Label标签下方也就是第1行,第0列的位置增加了一个Entry输入框 图 32增加Entry输入框 如果想要在Entry输入框中添加或删除内容,可以采用下面的方法 enter.delete(0,END)#清空输入框 enter.insert(0,'北京')#输入框中添加文本
获取输入框中的内容可以使用指令 enter.get()#获取输入框中内容
输入框布局完成,接下来我们放置Button按钮 Button按钮放置 Button(按钮)部件是一个标准的Tkinter窗口部件,按钮中可以包含文本或图像,并且你能够将按钮与一个Python函数或方法相关联。当这个按钮被按下时,tkinter自动调用相关联的函数或方法。 比如我们可以在翻译小助手中增加“翻译”、“清空”、“退出”三个按钮 下面我们来设计三个按钮Button,在上述的程序中增加下面一段程序 Button(root, text='翻译',width=10).grid(row = 2, column=0, padx = 10, pady = 5)# 将翻译Button放置在窗口中 Button(root, text = '清空',width=10).grid(row = 2, column = 1, padx = 10, pady = 5)# 将清空Button放置在窗口中 Button(root, text = '退出',width=10).grid(row = 2, column = 2, padx = 10, pady = 5)# 将退出Button放置在窗口中 root.mainloop()
程序运行后会看到如下图33所示结果 图 33 放置Button 按钮 在程序中,我们增加了三个Button按钮组件,其中text用来设置按钮上显示的文字,width、 height用来设置按钮的尺寸,除此之外还可增加command参数用来设置按钮被点击后执行的命令,比如添加点击“翻译”按钮就可以执行访问有道翻译网站的程序,关于command参数的具体设置,窗口界面布置完成后再详细介绍 以上组件布置完成后,我们还需要一个用来显示翻译结果的组件Text Text文本显示框 Text 组件用于显示文本文档,包含纯文本或格式化文本比如可以插入图片,文本,链接等内容,本次翻译小助手只需要显示文字信息即可,我们添加如下程序 #定义text文本框 text = Text(root,width=20,height=10)# 定义文本框的尺寸 text.grid(row = 3, column = 0)# 将文本框放置在窗口中 root.mainloop()
程序运行后会看到在三个Button按钮下方出现了文本显示区域 图 34 放置Text文本显示框 在文本输入框中添加或删除文本的指令是 text.insert('end', "显示内容")#在text显示框中添加内容 text.delete('0.0','end')#清空text显示框 组件布局细节 目前为止,翻译小助手需要的各种组件都已具备,不过我们还需要再优化一下细节,将其位置进行合理调整,将三个按钮分别放置在第2行的第0列、第1列和第2列;将Label标签、Entry输入框和Text文本显示框放置在第0行、第1行和第3行并设置为居中显示,使用“padx”和“pady”指令调整组件和组件、组件和边框之间的距离,修改后的程序如下 #导入tkinter库 from tkinter import * #创建窗口 root = Tk() root.title('翻译小助手')#设置窗口标题 #设置窗口大小(窗口横向长度X窗口纵向长度+距离屏幕左边框的横向距离+距离屏幕上边框的纵向距离) root.geometry('400x350+200+200') #定义label标签 Label(root, text='简易翻译器',#标签的文字 font=('Arial', 12)#设置字体和字号 ).grid(row=0,column=0, columnspan=3,pady = 15)# 将标签放置在窗口中 #定义输入框 enter = Entry(root,width=50)#输入框 enter.grid(row = 1,column=0, columnspan=3,padx = 20, pady = 20)#调整位置 Button(root, text='翻译',width=10).grid(row = 2, column=0, padx = 10, pady = 5) # 将翻译Button放置在窗口中 Button(root, text = '清空',width=10).grid(row = 2, column = 1, padx = 10, pady = 5)# 将清空Button放置在窗口中 Button(root, text = '退出',width=10).grid(row = 2, column = 2, padx = 10, pady = 5)# 将退出Button放置在窗口中 #定义text文本框 text = Text(root,width=50,height=10)# 定义文本框的尺寸 text.grid(row = 3, column = 0, columnspan=3,pady = 15)# 将文本框放置在窗口中 root.mainloop()
位置调整完成后的运行结果如下图35 图 35 组件调整后的布局 Button按钮关联程序 界面布局完成,我们需要为Button按钮设置关联程序,也就是为三个按钮的 command添加对应函数,修改的程序如下 #翻译程序 deftranslate(): pass #退出程序 defclose(): pass #清除 defclear(): pass Button(root, text='翻译',width=10, command=translate).grid(row = 2, column=0, padx = 10, pady = 5) # 将翻译Button放置在窗口中 Button(root, text = '清空',width=10, command=clear).grid(row = 2, column = 1, padx = 10, pady = 5)# 将清空Button放置在窗口中 Button(root, text = '退出',width=10, command=close).grid(row = 2, column = 2, padx = 10, pady = 5)# 将退出Button放置在窗口中 程序中,我们新建了3个函数分别与3个按钮相关联,只不过函数中并没有添加实际内容,之后在里面填写内容即可 比如我们可以将已经做好的翻译程序放入“translate()”函数中,将上一期用到的退出程序放入“close”函数中,在函数“clear”中添加清除输入框和显示框的程序,最后别忘记导入“requests”库、“json”库和消息提示库“messagebox” #导入requests库 import requests #导入json库 import json #导入tkinter库 from tkinter import * #导入消息提示库 from tkinter import messagebox #翻译程序 deftranslate(): #将有道翻译API地址放入“url”变量中 url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule' #获取要翻译的内容 word = enter.get() #新建data字典,用来存放POST请求时需要携带的数据 data = {} data['i'] = word data['doctype'] = 'json' data['from'] = 'AUTO' data['to'] = 'AUTO' data['client'] = 'fanyideskweb' #向有道翻译API发送网络请求,并将返回的数据放入变量“http_data”中 http_data = requests.post(url=url,data=data).text #将http_data中的数据解析为json格式 dict_data = json.loads(http_data) #提取字典中的有效数据 result = dict_data["translateResult"][0][0]["tgt"] print(f'翻译结果:{result}') text.insert('end', result) #在text显示框中添加内容 #退出程序 defclose(): tk_quit = messagebox.askokcancel('提示','真的要退出吗?') if tk_quit == True: root.destroy()#关闭窗口 #清除defclear(): enter.delete(0,END)#清空entry输入框显示框 text.delete('0.0','end') #清空text显示框 美化界面 通过上述完善程序,我们已经实现了预期的中英互译功能,不过还有提升的空间,可以将界面进行美化一下 我们可以增加一个体现翻译特色的logo图片,这里需要强调的是tkinter库只支持gif格式的图片,我们可以使用电脑中自带的画图工具将其他格式的图片转变成gif格式 事先准备如下图片 图 41 准备图片 将其存放在翻译小助手Python程序所在的文件夹中 图 42 将图片和程序放在同一个文件中 图片准备好,我们就可以在程序中导入图片并显示了 导入图片和显示图片的方法如下 Label(root,image=photo2).grid(row = 0,column=2,sticky = W, pady = 10) Label(root,image=photo1).grid(row = 0,column=0,columnspan=2,padx = 10, pady = 10)#显示图片 运行后的结果如下图43 图 43 显示图片 点击退出按钮后的提示 图 46 退出提示 为了让程序更加清晰简洁,我们可以对程序做进一步优化,将图形化界面布局的程序放置在主函数中 最后我们附上本次天气查询小助手的完整程序,当然此程序在其他编程环境同样适用,大家可以自行编译运行 #导入requests库 import requests #导入json库 import json #导入tkinter库 from tkinter import * #导入消息提示库 from tkinter import messagebox #翻译程序deftranslate():#将有道翻译API地址放入“url”变量中 url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule' #获取要翻译的内容 word = enter.get() #新建data字典,用来存放POST请求时需要携带的数据 data = {} data['i'] = word data['doctype'] = 'json' data['from'] = 'AUTO' data['to'] = 'AUTO' data['client'] = 'fanyideskweb' #向有道翻译API发送网络请求,并将返回的数据放入变量“http_data”中 http_data = requests.post(url=url,data=data).text #将http_data中的数据解析为json格式 dict_data = json.loads(http_data) #提取字典中的有效数据 result = dict_data["translateResult"][0][0]["tgt"] print(f'翻译结果:{result}') text.insert('end', result)#在text显示框中添加内容 #退出程序defclose(): tk_quit = messagebox.askokcancel('提示','真的要退出吗?') if tk_quit == True: root.destroy()#关闭窗口 #清除defclear(): enter.delete(0,END)#清空entry输入框 text.delete('1.0','end')#清空text显示框 if __name__ == '__main__': #创建窗口 root = Tk() root.title('翻译小助手')#设置窗口标题 #设置窗口大小(窗口横向长度X窗口纵向长度+距离屏幕左边框的横向距离+距离屏幕上边框的纵向距离) root.geometry('400x350+200+200') photo1=PhotoImage(file="yi.gif")#导入图片 Label(root,image=photo1).grid(row = 0,column=0,columnspan=2,padx = 10, pady = 10)#显示图片 #定义label标签 Label(root, text='简易翻译器',#标签的文字 font=('Arial', 12)#设置字体和字号 ).grid(row=0,column=0,columnspan=2, sticky = E,pady = 10)# 将标签放置在窗口的第0行,第0列位置#定义输入框 enter = Entry(root,width=50)#输入框 enter.grid(row = 1,column=0, columnspan=3,padx = 20, pady = 20)#调整位置 Button(root, text='翻译',width=10, command=translate).grid(row = 2, column=0, padx = 10, pady = 5) # 将翻译Button放置在窗口中 Button(root, text = '清空',width=10, command=clear).grid(row = 2, column = 1, padx = 10, pady = 5)# 将清空Button放置在窗口中 Button(root, text = '退出',width=10, command=close).grid(row = 2, column = 2, padx = 10, pady = 5)# 将退出Button放置在窗口中 #定义text文本框 text = Text(root,width=50,height=10)# 定义文本框的尺寸 text.grid(row = 3, column = 0, columnspan=3,pady = 15)# 将文本框放置在窗口中 root.mainloop()#窗口循环运行 #总结# 至此,我们翻译小助手程序就全部完成了,我们在上一期的基础上进一步掌握了requests库的POST网络请求方法,可以携带数据进行网络请求。掌握了tkinter库中text显示框的使用方法,可以将网络请求的数据以text的形式显示在窗口中。 有了这些技巧的加持,让我们的项目变得更加有趣,相信每个人都会有各种各样的创意想要实现,还在等什么,赶快去试试吧,接下来我们还会分享一些有趣且实用的案例,一起期待吧 更多精彩内容请关注旺仔爸爸造物社 |
© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed