【5万字】文件增量复制【OS库、Tkinter库等】

一、文件增量备份

类似于Win7及以前的公文包,但是单向备份,不修改源文件。
Win10以后没有公文包了,吐槽一下,自己动手做一个!

二、OS库

三、Tkinter库

官方英文文档:https://docs.python.org/3/library/tk.html
官方中文文档:https://docs.python.org/zh-cn/3/library/tkinter.ttk.html
其实中文文档也是夹带着很多英文的,不过确实是官方的,估计是机器翻译的。
在这里插入图片描述

3.1 Tkinter是什么

Tkinter 是使用 python 进行窗口视窗设计的模块。Tkinter模块(“Tk 接口”)是Python的标准Tk GUI工具包的接口。作为 python 特定的GUI界面,是一个图像的窗口,tkinter是python 自带的,可以编辑的GUI界面,我们可以用GUI 实现很多直观的功能,比如想开发一个计算器,如果只是一个程序输入,输出窗口的话,是没用用户体验的。所有开发一个图像化的小窗口,就是必要的。
对于稍有GUI编程经验的人来说,Python的Tkinter界面库是非常简单的。python的GUI库非常多,选择Tkinter,一是最为简单,二是自带库,不需下载安装,随时使用,三则是从需求出发,Python作为一种脚本语言,一种胶水语言,一般不会用它来开发复杂的桌面应用,它并不具备这方面的优势,使用Python,可以把它作为一个灵活的工具,而不是作为主要开发语言,那么在工作中,需要制作一个小工具,肯定是需要有界面的,不仅自己用,也能分享别人使用,在这种需求下,Tkinter是足够胜任的!
这篇文章主要做一个简单概述和实践编程,对于从没有接触过GUI的新手,在脑中树立一个基本的界面编程概念,同时自己也能学会如何简单的实现一些小的图形窗口功能。
对于Tkinter编程,可以用两个比喻来理解:
第一个,作画。我们都见过美术生写生的情景,先支一个画架,放上画板,蒙上画布,构思内容,用铅笔画草图,组织结构和比例,调色板调色,最后画笔勾勒。相应的,对应到tkinter编程,那么我们的显示屏就是支起来的画架,根窗体就是画板,在tkinter中则是Toplevel,画布就是tkinter中的容器(Frame),画板上可以放很多张画布(Convas),tkinter中的容器中也可以放很多个容器,绘画中的构图布局则是tkinter中的布局管理器(几何管理器),绘画的内容就是tkinter中的一个个小组件,一幅画由许多元素构成,而我们的GUI界面,就是有一个个组件拼装起来的,它们就是widget。
第二个,我们小时候都玩过积木,只要发挥创意,相同的积木可以堆出各种造型。tkinter的组件也可以看做一个个积木,形状或许不同,其本质都是一样的,就是一个积木,不管它长什么样子,它始终就是积木!所以这些小组件都有许多共性,另外,个人认为,学习界面编程,最重要的不是一开始学习每个积木的样子,不是学习每个组件怎么用,而是这些组件该怎么放。
初始学习中,怎么放远远比怎么用重要的多。网上有大量的文章资料,基本全是介绍组件怎么用的,对于怎么放,也就是tkinter中的布局管理器,都是一笔带过,这对初学者有点本末倒置,或许绝大部分是转载的原因吧,极少是自己真正写的。组件怎么用不是最迫切的,用到的时候再去了解也不迟,边用边学反而更好。因此我将专门写一章,详细介绍布局管理器的使用。

3.2 Tkinter 模块元素简要说明

在这里插入图片描述
Tkinter支持16个核心的窗口部件,这个16个核心窗口部件类简要描述如下:

  • Button:一个简单的按钮,用来执行一个命令或别的操作。
  • Canvas:组织图形。这个部件可以用来绘制图表和图,创建图形编辑器,实现定制窗口部件。
  • Checkbutton:代表一个变量,它有两个不同的值。点击这个按钮将会在这两个值间切换。
  • Entry:文本输入域。
  • Frame:一个容器窗口部件。帧可以有边框和背景,当创建一个应用程序或dialog(对话)版面时,帧被用来组织其它的窗口部件。
  • Label:显示一个文本或图象。
  • Listbox:显示供选方案的一个列表。listbox能够被配置来得到radiobutton或checklist的行为。
  • Menu:菜单条。用来实现下拉和弹出式菜单。
  • Menubutton:菜单按钮。用来实现下拉式菜单。
  • Message:显示一文本。类似label窗口部件,但是能够自动地调整文本到给定的宽度或比率。
  • Radiobutton:代表一个变量,它可以有多个值中的一个。点击它将为这个变量设置值,并且清除与这同一变量相关的其它radiobutton。
  • Scale:允许你通过滑块来设置一数字值。
  • Scrollbar:为配合使用canvas, entry, listbox, and text窗口部件的标准滚动条。
  • Text:格式化文本显示。允许你用不同的样式和属性来显示和编辑文本。同时支持内嵌图象和窗口。
  • Toplevel:一个容器窗口部件,作为一个单独的、最上面的窗口显示。
  • messageBox:消息框,用于显示你应用程序的消息框。(Python2中为tkMessagebox)
    注意在Tkinter中窗口部件类没有分级;所有的窗口部件类在树中都是兄弟关系。
    所有这些窗口部件提供了Misc和几何管理方法、配置管理方法和部件自己定义的另外的方法。此外,Toplevel类也提供窗口管理接口。这意味一个典型的窗口部件类提供了大约150种方法。

3.3 主要部件

3.3.1 创建主窗口及Label部件(标签)创建使用

我们要学习使用上面提到的这些控件首先要创建一个主窗口,就像作画一样,先要架好架子和画板,然后才能在上面放画纸和各种绘画元素,创建好主窗口才能在上面放置各种控件元素。而创建过程是很简单的,如下:

import tkinter as tk # 使用Tkinter前需要先导入
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字,设置title属性
window.title('My Window')
 
# 第3步,设定窗口的大小(长 * 宽),设置geometry属性
window.geometry('500x300') # 这里的乘是小写字母x
 
# 第4步,在图形界面上设定标签,bg为背景,font为字体,width为长,height为高,这里的长和高是字符数,比如height=2,就是标签有2个字符这么高
label1 = tk.Label(window, text='你好!this is Tkinter', bg='green', font=('Arial', 12), width=30, height=2)
 
# 第5步,放置标签,放置lable的方法有:1)label1.pack(); 2)label1.place();
label1.pack()  # Label内容content区域放置位置,自动调节尺寸
 
# 第6步,主窗口循环显示
window.mainloop()
# 注意,loop因为是循环的意思,window.mainloop就会让window不断的刷新,如果没有mainloop,就是一个静态的window,传入进去的值就不会有循环,mainloop就相当于一个很大的while循环,有个while,每点击一次就会更新一次,所以我们必须要有循环
# 所有的窗口文件都必须有类似的mainloop函数,mainloop是窗口文件的关键的关键。

在这里插入图片描述

3.3.2 Button按钮

Button(按钮)部件是一个标准的Tkinter窗口部件,用来实现各种按钮。按钮能够包含文本或图象,并且你能够将按钮与一个Python函数或方法相关联。当这个按钮被按下时,Tkinter自动调用相关联的函数或方法。
按钮仅能显示一种字体,但是这个文本可以跨行。另外,这个文本中的一个字母可以有下划线,例如标明一个快捷键。默认情况,Tab键用于将焦点移动到一个按钮部件。
按钮部件用来让用户说“马上给我执行这个任务”,通常我们用显示在按钮上的文本或图象来提示。按钮通常用在工具条中或应用程序窗口中,并且用来接收或忽略输入在对话框中的数据。关于按钮和输入的数据的配合,可以参看Checkbutton和Radiobutton部件。
普通的按钮很容易被创建,仅仅指定按钮的内容(文本、位图、图象)和一个当按钮被按下时的回调函数即可:
b = tk.Button(window, text=“hit me”, command=hit_me)
没有回调函数的按钮是没有用的,当你按下这个按钮时它什么也不做。你可能在开发一个应用程序的时候想实现这种按钮,比如为了不干扰你的beta版的测试者:
b = tk.Button(window, text=“Help”, command=DISABLED)

import tkinter as tk # 使用Tkinter前需要先导入
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字,设置title属性
window.title('My Window')
 
# 第3步,设定窗口的大小(长 * 宽),设置geometry属性
window.geometry('500x300') # 这里的乘是小写字母x
 
# 第4步,在图形界面上设定标签,bg为背景,font为字体,width为长,height为高,这里的长和高是字符数,比如height=2,就是标签有2个字符这么高
var = tk.StringVar('')  # 将label标签的内容设置为字符类型,用var来接收hit_me函数的传出内容用以显示在标签上
print(var, type(var))
label1 = tk.Label(window, textvariable=var, bg='orange', font=('Arial', 12), width=30, height=2)
label1.pack()  # Label内容content区域放置位置,自动调节尺寸,放置lable的方法有:1)label1.pack(); 2)label1.place();

# 第5步,添加按钮,定义一个函数功能(内容自己自由编写),供点击Button按键时调用,调用命令参数command=函数名
on_hit = False
def hit_me():
  global on_hit
  if on_hit == False:
    on_hit = True
    var.set('点我干嘛?')
  else:
    on_hit = False
    var.set('')
 
button1 = tk.Button(window, text='点我', font=('Arial', 12), width=10, height=1, command=hit_me)
button1.pack()
 
# 第6步,主窗口循环显示
window.mainloop()

在这里插入图片描述

3.3.3 Entry单行文本框

Entry是tkinter类中提供的的一个单行文本输入域,用来输入显示一行文本,收集键盘输入(类似 HTML 中的 text)。
需要用户输入用户信息时,比如我们平时使用软件、登录网页时,用户交互界面让我们登录账户信息等时候可以用到。

import tkinter as tk # 使用Tkinter前需要先导入
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字
window.title('My Window')
 
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('300x200+700+70') # 这里的乘是小x
 
# 第4步,在图形界面上设定输入框控件entry并放置控件
e1 = tk.Entry(window, show='*', font=('Arial', 14))  # 显示成密文形式
e2 = tk.Entry(window, show=None, font=('Arial', 14)) # 显示成明文形式
e1.pack()
e2.pack()
 
# 第5步,主窗口循环显示
window.mainloop()

在这里插入图片描述

3.3.4 Text多行文本框

Text是tkinter类中提供的的一个多行文本区域,显示多行文本,可用来收集(或显示)用户输入的文字(类似 HTML 中的 textarea),格式化文本显示,允许你用不同的样式和属性来显示和编辑文本,同时支持内嵌图象和窗口。
在需要显示编辑用户、产品多行信息时,比如显示用户详细描述文字,产品简介等等,支持随时编辑。

import tkinter as tk # 使用Tkinter前需要先导入
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字
window.title('My Window')
 
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('300x200+700+70') # 这里的乘是小x
 
# 第4步,在图形界面上设定输入框控件entry框并放置
e = tk.Entry(window, show = None)#显示成明文形式
e.pack()

# 第7步,创建并放置一个多行文本框text用以显示,指定height=3为文本框是三个字符高度
t = tk.Text(window, height=3)
t.pack()

# 第5步,定义两个触发事件时的函数insert_point和insert_end(注意:因为Python的执行顺序是从上往下,所以函数一定要放在按钮的上面)
def insert_point(): # 在鼠标焦点处插入输入内容
  var = e.get()
  t.insert('insert', var)
def insert_end():  # 在文本框内容最后接着插入输入内容
  var = e.get()
  t.insert('end', var)
 
# 第6步,创建并放置两个按钮分别触发两种情况
b1 = tk.Button(window, text='焦点处插入', width=10, height=2, command=insert_point)
b1.pack()
b2 = tk.Button(window, text='结尾处插入', width=10, height=2, command=insert_end)
b2.pack()

# 第8步,主窗口循环显示
window.mainloop()

在这里插入图片描述

3.3.5 Listbox列表框

Text是tkinter类中提供的的列表框部件,显示供选方案的一个列表。listbox能够被配置来得到radiobutton或checklist的行为。
在有一个很多内容选项组成的列表提供用户选择时会用到。

import tkinter as tk # 使用Tkinter前需要先导入
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字
window.title('My Window')
 
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x
 
# 第4步,在图形界面上创建一个标签label用以显示并放置
var1 = tk.StringVar() # 创建变量,用var1用来接收鼠标点击具体选项的内容
l = tk.Label(window, bg='orange', fg='blue',font=('Arial', 12), width=10, textvariable=var1).pack()
 
# 第6步,创建一个方法用于按钮的点击事件
def print_selection():
  value = lb.get(lb.curselection())  # 获取当前选中的文本
  var1.set(value) # 为label设置值
 
# 第5步,创建一个按钮并放置,点击按钮调用print_selection函数
b1 = tk.Button(window, text='显示选中项', width=15, height=2, command=print_selection).pack()
 
# 第7步,创建Listbox并为其添加内容
var2 = tk.StringVar()
var2.set((1,2,3,4)) # 为变量var2设置值
# 创建Listbox,同时将var2的值赋给Listbox
lb = tk.Listbox(window, listvariable=var2) 
# 创建一个list并将值循环添加到Listbox控件中
list_items = [11,22,33,44]
for item in list_items:
  lb.insert('end', item) # 从最后一个位置开始加入值
lb.insert(1, 'first')    # 在第1个位置加入'first'字符
lb.insert(2, 'second')   # 在第2个位置加入'second'字符
lb.delete(3)        # 删除第3个位置的字符2
lb.pack()
 
# 第8步,主窗口循环显示
window.mainloop()

在这里插入图片描述

3.3.6 Radiobutton单选按钮

Radiobutton:代表一个变量,它可以有多个值中的一个。点击它将为这个变量设置值,并且清除与这同一变量相关的其它radiobutton。
在有一个很多内容选项组成的选项列表提供用户选择时会用到,用户一次只能选择其中一个,不能多选。

import tkinter as tk # 使用Tkinter前需要先导入
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字
window.title('My Window')
 
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x
 
# 第4步,在图形界面上创建一个标签label用以显示并放置
var = tk.StringVar()  # 定义一个var用来将radiobutton的值和Label的值联系在一起.
l = tk.Label(window, bg='orange', width=20, text='')
l.pack()

 # 第6步,定义选项触发函数功能
def print_selection():
  l.config(text='你选中了:' + var.get())
 
# 第5步,创建三个radiobutton选项,其中variable=var, value='A'的意思就是,当我们鼠标选中了其中一个选项,把value的值A放到变量var中,然后赋值给variable
r1 = tk.Radiobutton(window, text='Option A', variable=var, value='A', command=print_selection).pack()
r2 = tk.Radiobutton(window, text='Option B', variable=var, value='B', command=print_selection).pack()
r3 = tk.Radiobutton(window, text='Option C', variable=var, value='C', command=print_selection).pack()
 
# 第7步,主窗口循环显示
window.mainloop()

在这里插入图片描述

3.3.7 Checkbutton多选按钮

import tkinter as tk # 使用Tkinter前需要先导入
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字
window.title('My Window')
 
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x
 
# 第4步,在图形界面上创建一个标签label用以显示并放置
l = tk.Label(window, bg='yellow', width=20, text='')
l.pack()
 
# 第6步,定义触发函数功能
def print_selection():
  if (var1.get() == 1) & (var2.get() == 0):   # 如果选中第一个选项,未选中第二个选项
    l.config(text='我喜欢:' + var_c1.get())
  elif (var1.get() == 0) & (var2.get() == 1):  # 如果选中第二个选项,未选中第一个选项
    l.config(text='我喜欢:' + var_c2.get())
  elif (var1.get() == 0) & (var2.get() == 0):  # 如果两个选项都未选中
    l.config(text= var_c1.get() + '和' + var_c2.get() + '我都不喜欢')
  else:
    l.config(text= var_c1.get() + '和' + var_c2.get() + '我都喜欢')       # 如果两个选项都选中
 
# 第5步,定义两个Checkbutton选项并放置
var1 = tk.IntVar() # 定义var1和var2整型变量用来存放选择行为返回值
var2 = tk.IntVar()
var_c1 = tk.StringVar()
var_c1.set('苹果')
var_c2 = tk.StringVar()
var_c2.set('西瓜')
# 传值原理类似于radiobutton部件
c1 = tk.Checkbutton(window, textvariable=var_c1,variable=var1, onvalue=1, offvalue=0, command=print_selection).pack()  
c2 = tk.Checkbutton(window, textvariable=var_c2,variable=var2, onvalue=1, offvalue=0, command=print_selection).pack()
 
# 第7步,主窗口循环显示
window.mainloop()

在这里插入图片描述

3.3.8 Scale尺度滑条

Scale: 尺度滑条(拉动条),允许你通过滑块来设置一数字值。
在需要用户给出评价等级,或者给出一个评价分数,或者拉动滑动条提供一个具体的数值等等。

import tkinter as tk # 使用Tkinter前需要先导入
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字
window.title('My Window')
 
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x
 
# 第4步,在图形界面上创建一个标签label用以显示并放置
l = tk.Label(window, bg='orange', fg='blue', width=20, text='')
l.pack()
 
# 第6步,定义一个触发函数功能
def print_selection(v):
  l.config(text='你拖到了:' + v)
# 第5步,创建一个尺度滑条,长度200字符,从0到10,以2为刻度,精度为0.01,触发调用print_selection函数
s = tk.Scale(window, label='拖我试试', from_=0, to=10, orient=tk.HORIZONTAL, length=200, showvalue=0,tickinterval=2, resolution=0.01, command=print_selection)
s.pack()
 
# 第7步,主窗口循环显示
window.mainloop()

在这里插入图片描述

3.3.9 Canvas画布

Canvas:画布是一个容器,提供绘图功能(直线、椭圆、多边形、矩形) 可以包含图形或位图,用来绘制图表和图,创建图形编辑器,实现定制窗口部件。
在比如像用户交互界面等,需要提供设计的图标、图形、logo等信息是可以用到画布。
图片可以用画图工具改一下像素大小,以免图片太大,导入画布显示不全。
图片锚定点位置参数图:
在这里插入图片描述

import tkinter as tk # 使用Tkinter前需要先导入
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字
window.title('My Window')
 
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x
 
# 第4步,在图形界面上创建 500 * 200 大小的画布并放置各种元素
canvas = tk.Canvas(window, bg='orange', height=200, width=500)
# 说明图片位置,并导入图片到画布上
image_file = tk.PhotoImage(file='output.png', height=150, width=100) # 图片位置(相对路径,与.py文件同一文件夹下,也可以用绝对路径,需要给定图片具体绝对路径)
image = canvas.create_image(250, 0, anchor='n',image=image_file)    # 图片锚定点(n图片顶端的中间点位置)放在画布(250,0)坐标处
# 定义多边形参数,然后在画布上画出指定图形
x0, y0, x1, y1 = 100, 100, 150, 150
line = canvas.create_line(x0-50, y0-50, x1-50, y1-50)          # 画直线
oval = canvas.create_oval(x0+120, y0+50, x1+120, y1+50, fill='yellow') # 画圆 用黄色填充
arc = canvas.create_arc(x0, y0+50, x1, y1+50, start=0, extent=180)   # 画扇形 从0度打开收到180度结束
rect = canvas.create_rectangle(330, 30, 330+20, 30+20)         # 画矩形正方形
canvas.pack()
 
# 第6步,触发函数,用来一定指定图形
def moveit():
  canvas.move(rect, 2, 2) # 移动正方形rect(也可以改成其他图形名字用以移动一起图形、元素),按每次(x=2, y=2)步长进行移动
 
# 第5步,定义一个按钮用来移动指定图形的在画布上的位置
b = tk.Button(window, text='move item',command=moveit).pack()
 
# 第7步,主窗口循环显示
window.mainloop()

在这里插入图片描述

3.3.10 Menu菜单

Menu:菜单条,用来实现下拉和弹出式菜单,点下菜单后弹出的一个选项列表,用户可以从中选择
在比如像软件或网页交互界面等,需要提供菜单选项功能提供用户选择菜单选项功能时用到。

import tkinter as tk # 使用Tkinter前需要先导入
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字
window.title('My Window')
 
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x
 
# 第4步,在图形界面上创建一个标签用以显示内容并放置
l = tk.Label(window, text='   ', bg='orange')
l.pack()
 
# 第10步,定义一个函数功能,用来代表菜单选项的功能,这里为了操作简单,定义的功能比较简单
counter = 0
def do_job():
  global counter
  l.config(text='do '+ str(counter))
  counter += 1
 
# 第5步,创建一个菜单栏,这里我们可以把他理解成一个容器,在窗口的上方
menubar = tk.Menu(window)
 
# 第6步,创建一个File菜单项(默认不下拉,下拉内容包括New,Open,Save,Exit功能项)
filemenu = tk.Menu(menubar, tearoff=0)
# 将上面定义的空菜单命名为File,放在菜单栏中,就是装入那个容器中
menubar.add_cascade(label='文件', menu=filemenu)
 
# 在File中加入New、Open、Save等小菜单,即我们平时看到的下拉菜单,每一个小菜单对应命令操作。
filemenu.add_command(label='新建', command=do_job)
filemenu.add_command(label='打开', command=do_job)
filemenu.add_command(label='保存', command=do_job)
filemenu.add_separator()  # 添加一条分隔线
filemenu.add_command(label='退出', command=window.quit) # 用tkinter里面自带的quit()函数
 
# 第7步,创建一个Edit菜单项(默认不下拉,下拉内容包括Cut,Copy,Paste功能项)
editmenu = tk.Menu(menubar, tearoff=0)
# 将上面定义的空菜单命名为 Edit,放在菜单栏中,就是装入那个容器中
menubar.add_cascade(label='编辑', menu=editmenu)
 
# 同样的在 Edit 中加入Cut、Copy、Paste等小命令功能单元,如果点击这些单元, 就会触发do_job的功能
editmenu.add_command(label='剪切', command=do_job)
editmenu.add_command(label='复制', command=do_job)
editmenu.add_command(label='粘贴', command=do_job)
 
# 第8步,创建第二级菜单,即菜单项里面的菜单
submenu = tk.Menu(filemenu) # 和上面定义菜单一样,不过此处实在File上创建一个空的菜单
filemenu.add_cascade(label='导入', menu=submenu, underline=0) # 给放入的菜单submenu命名为Import
 
# 第9步,创建第三级菜单命令,即菜单项里面的菜单项里面的菜单命令(有点拗口,笑~~~)
submenu.add_command(label='子菜单1', command=do_job)  # 这里和上面创建原理也一样,在Import菜单项中加入一个小菜单命令Submenu_1
 
# 第11步,创建菜单栏完成后,配置让菜单栏menubar显示出来
window.config(menu=menubar)
 
# 第12步,主窗口循环显示
window.mainloop()

在这里插入图片描述

3.3.11 Frame框架

Frame:框架,用来承载放置其他GUI元素,就是一个容器,是一个在 Windows 上分离小区域的部件, 它能将 Windows 分成不同的区,然后存放不同的其他部件. 同时一个 Frame 上也能再分成两个 Frame, Frame 可以认为是一种容器.
在比如像软件或网页交互界面等,有不同的界面逻辑层级和功能区域划分时可以用到,让交互界面逻辑更加清晰。

import tkinter as tk # 使用Tkinter前需要先导入
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字
window.title('My Window')
 
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x
 
# 第4步,在图形界面上创建一个标签用以显示内容并放置
tk.Label(window, text='标签', bg='orange', font=('Arial', 16)).pack()  # 和前面部件分开创建和放置不同,其实可以创建和放置一步完成
 
# 第5步,创建一个主frame,长在主window窗口上
frame = tk.Frame(window)
frame.pack()
 
# 第6步,创建第二层框架frame,长在主框架frame上面
frame_l = tk.Frame(frame)# 第二层frame,左frame,长在主frame上
frame_r = tk.Frame(frame)# 第二层frame,右frame,长在主frame上
frame_l.pack(side='left')
frame_r.pack(side='right')
 
# 第7步,创建三组标签,为第二层frame上面的内容,分为左区域和右区域,用不同颜色标识
tk.Label(frame_l, text='on the frame_l1', bg='green').pack()
tk.Label(frame_l, text='on the frame_l2', bg='green').pack()
tk.Label(frame_l, text='on the frame_l3', bg='green').pack()
tk.Label(frame_r, text='on the frame_r1', bg='yellow').pack()
tk.Label(frame_r, text='on the frame_r2', bg='yellow').pack()
tk.Label(frame_r, text='on the frame_r3', bg='yellow').pack()
 
# 第8步,主窗口循环显示
window.mainloop()

在这里插入图片描述

3.3.12 messageBox消息框

messageBox:消息框,用于显示你应用程序的消息框。(Python2中为tkMessagebox),其实这里的messageBox就是我们平时看到的弹窗。 我们首先需要定义一个触发功能,来触发这个弹窗,这里我们就放上以前学过的button按钮,通过触发功能,调用messagebox吧,点击button按钮就会弹出提示对话框。
在比如像软件或网页交互界面等,有不同的界面逻辑层级和功能区域划分时可以用到,让交互界面逻辑更加清晰。

import tkinter as tk # 使用Tkinter前需要先导入
import tkinter.messagebox # 要使用messagebox先要导入模块
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字
window.title('My Window')
 
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x
 
# 第5步,定义触发函数功能
def hit_me():
  tkinter.messagebox.showinfo(title='Hi', message='你好!')       # 提示信息对话窗
  # tkinter.messagebox.showwarning(title='Hi', message='有警告!')    # 提出警告对话窗
  # tkinter.messagebox.showerror(title='Hi', message='出错了!')     # 提出错误对话窗
  # print(tkinter.messagebox.askquestion(title='Hi', message='你好!')) # 询问选择对话窗return 'yes', 'no'
  # print(tkinter.messagebox.askyesno(title='Hi', message='你好!'))   # return 'True', 'False'
  # print(tkinter.messagebox.askokcancel(title='Hi', message='你好!')) # return 'True', 'False'
 
# 第4步,在图形界面上创建一个标签用以显示内容并放置
tk.Button(window, text='hit me', bg='green', font=('Arial', 14), command=hit_me).pack()
 
# 第6步,主窗口循环显示
window.mainloop()

在这里插入图片描述

3.3.13 窗口部件三种放置方式pack/grid/place

3.3.13.1 Grid:The Grid Geometry Manager

grid 是方格, 所以所有的内容会被放在这些规律的方格中

for i in range(3):
  for j in range(3):
    tk.Label(window, text=1).grid(row=i, column=j, padx=10, pady=10, ipadx=10, ipady=10)

以上的代码就是创建一个三行三列的表格,其实 grid 就是用表格的形式定位的。这里的参数 row 为行,colum 为列,padx 就是单元格左右间距,pady 就是单元格上下间距,ipadx是单元格内部元素与单元格的左右间距,ipady是单元格内部元素与单元格的上下间距。

import tkinter as tk # 使用Tkinter前需要先导入
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字
window.title('My Window')
 
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x
 
# 第4步,grid 放置方法
for i in range(3):
  for j in range(3):
    tk.Label(window, text=1).grid(row=i, column=j, padx=10, pady=10, ipadx=10, ipady=10)
 
# 第5步,主窗口循环显示
window.mainloop()

在这里插入图片描述

3.3.13.2 Pack:The Pack Geometry Manager

我们常用的pack(), 他会按照上下左右的方式排列.例如:

import tkinter as tk # 使用Tkinter前需要先导入
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字
window.title('My Window')
 
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x
 
# 第4步,pack 放置方法
tk.Label(window, text='上', fg='red').pack(side='top')  # 上
tk.Label(window, text='下', fg='red').pack(side='bottom') # 下
tk.Label(window, text='左', fg='red').pack(side='left')  # 左
tk.Label(window, text='右', fg='red').pack(side='right') # 右
 
# 第5步,主窗口循环显示
window.mainloop()

在这里插入图片描述

3.3.13.3 Place:The Place Geometry Manager

再接下来我们来看place(), 这个比较容易理解,就是给精确的坐标来定位,如此处给的(50, 100),就是将这个部件放在坐标为(x=50, y=100)的这个位置, 后面的参数 anchor=‘nw’,就是前面所讲的锚定点是西北角。例如:

import tkinter as tk # 使用Tkinter前需要先导入
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字
window.title('My Window')
 
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('500x300') # 这里的乘是小x
 
# 第4步,place 放置方法(精准的放置到指定坐标点的位置上)
tk.Label(window, text='Pl', font=('Arial', 60), ).place(x=50, y=100, anchor='nw')
 
# 第5步,主窗口循环显示
window.mainloop()

在这里插入图片描述

3.4 综合练习

3.4.1 用户登录窗口

import tkinter as tk # 使用Tkinter前需要先导入
import tkinter.messagebox
import pickle
 
# 第1步,实例化object,建立窗口window
window = tk.Tk()
 
# 第2步,给窗口的可视化起名字
window.title('Wellcome to Hongwei Website')
 
# 第3步,设定窗口的大小(长 * 宽)
window.geometry('400x300') # 这里的乘是小x
 
# 第4步,加载 wellcome image
canvas = tk.Canvas(window, width=400, height=135, bg='green')
image_file = tk.PhotoImage(file='output.png')
image = canvas.create_image(200, 0, anchor='n', image=image_file)
canvas.pack(side='top')
tk.Label(window, text='Wellcome',font=('Arial', 16)).pack()
 
# 第5步,用户信息
tk.Label(window, text='User name:', font=('Arial', 14)).place(x=10, y=170)
tk.Label(window, text='Password:', font=('Arial', 14)).place(x=10, y=210)
 
# 第6步,用户登录输入框entry
# 用户名
var_usr_name = tk.StringVar()
var_usr_name.set('example@python.com')
entry_usr_name = tk.Entry(window, textvariable=var_usr_name, font=('Arial', 14))
entry_usr_name.place(x=120,y=175)
# 用户密码
var_usr_pwd = tk.StringVar()
entry_usr_pwd = tk.Entry(window, textvariable=var_usr_pwd, font=('Arial', 14), show='*')
entry_usr_pwd.place(x=120,y=215)
 
# 第8步,定义用户登录功能
def usr_login():
  # 这两行代码就是获取用户输入的usr_name和usr_pwd
  usr_name = var_usr_name.get()
  usr_pwd = var_usr_pwd.get()
 
  # 这里设置异常捕获,当我们第一次访问用户信息文件时是不存在的,所以这里设置异常捕获。
  # 中间的两行就是我们的匹配,即程序将输入的信息和文件中的信息匹配。
  try:
    with open('usrs_info.pickle', 'rb') as usr_file:
      usrs_info = pickle.load(usr_file)
  except FileNotFoundError:
    # 这里就是我们在没有读取到`usr_file`的时候,程序会创建一个`usr_file`这个文件,并将管理员
    # 的用户和密码写入,即用户名为`admin`密码为`admin`。
    with open('usrs_info.pickle', 'wb') as usr_file:
      usrs_info = {'admin': 'admin'}
      pickle.dump(usrs_info, usr_file)
      usr_file.close()  # 必须先关闭,否则pickle.load()会出现EOFError: Ran out of input
 
  # 如果用户名和密码与文件中的匹配成功,则会登录成功,并跳出弹窗how are you? 加上你的用户名。
  if usr_name in usrs_info:
    if usr_pwd == usrs_info[usr_name]:
      tkinter.messagebox.showinfo(title='Welcome', message='How are you? ' + usr_name)
    # 如果用户名匹配成功,而密码输入错误,则会弹出'Error, your password is wrong, try again.'
    else:
      tkinter.messagebox.showerror(message='Error, your password is wrong, try again.')
  else: # 如果发现用户名不存在
    is_sign_up = tkinter.messagebox.askyesno('Welcome! ', 'You have not sign up yet. Sign up now?')
    # 提示需不需要注册新用户
    if is_sign_up:
      usr_sign_up()
 
# 第9步,定义用户注册功能
def usr_sign_up():
  def sign_to_Hongwei_Website():
    # 以下三行就是获取我们注册时所输入的信息
    np = new_pwd.get()
    npf = new_pwd_confirm.get()
    nn = new_name.get()
 
    # 这里是打开我们记录数据的文件,将注册信息读出
    with open('usrs_info.pickle', 'rb') as usr_file:
      exist_usr_info = pickle.load(usr_file)
    # 这里就是判断,如果两次密码输入不一致,则提示Error, Password and confirm password must be the same!
    if np != npf:
      tkinter.messagebox.showerror('Error', 'Password and confirm password must be the same!')
 
    # 如果用户名已经在我们的数据文件中,则提示Error, The user has already signed up!
    elif nn in exist_usr_info:
      tkinter.messagebox.showerror('Error', 'The user has already signed up!')
 
    # 最后如果输入无以上错误,则将注册输入的信息记录到文件当中,并提示注册成功Welcome!,You have successfully signed up!,然后销毁窗口。
    else:
      exist_usr_info[nn] = np
      with open('usrs_info.pickle', 'wb') as usr_file:
        pickle.dump(exist_usr_info, usr_file)
      tkinter.messagebox.showinfo('Welcome', 'You have successfully signed up!')
      # 然后销毁窗口。
      window_sign_up.destroy()
 
  # 定义长在窗口上的窗口
  window_sign_up = tk.Toplevel(window)
  window_sign_up.geometry('300x200')
  window_sign_up.title('Sign up window')
 
  new_name = tk.StringVar() # 将输入的注册名赋值给变量
  new_name.set('example@python.com') # 将最初显示定为'example@python.com'
  tk.Label(window_sign_up, text='User name: ').place(x=10, y=10) # 将`User name:`放置在坐标(10,10)。
  entry_new_name = tk.Entry(window_sign_up, textvariable=new_name) # 创建一个注册名的`entry`,变量为`new_name`
  entry_new_name.place(x=130, y=10) # `entry`放置在坐标(150,10).
 
  new_pwd = tk.StringVar()
  tk.Label(window_sign_up, text='Password: ').place(x=10, y=50)
  entry_usr_pwd = tk.Entry(window_sign_up, textvariable=new_pwd, show='*')
  entry_usr_pwd.place(x=130, y=50)
 
  new_pwd_confirm = tk.StringVar()
  tk.Label(window_sign_up, text='Confirm password: ').place(x=10, y=90)
  entry_usr_pwd_confirm = tk.Entry(window_sign_up, textvariable=new_pwd_confirm, show='*')
  entry_usr_pwd_confirm.place(x=130, y=90)
 
  # 下面的 sign_to_Hongwei_Website
  btn_comfirm_sign_up = tk.Button(window_sign_up, text='Sign up', command=sign_to_Hongwei_Website)
  btn_comfirm_sign_up.place(x=180, y=120)
 
# 第7步,login and sign up 按钮
btn_login = tk.Button(window, text='Login', command=usr_login)
btn_login.place(x=120, y=240)
btn_sign_up = tk.Button(window, text='Sign up', command=usr_sign_up)
btn_sign_up.place(x=200, y=240)
 
# 第10步,主窗口循环显示
window.mainloop()

在这里插入图片描述

3.4.2 GUI进阶(ttk)—让界面变得更美

上面介绍的GUI界面有以下两个较大的缺点:

  • 界面比较丑陋,控件种类有限。
    • 界面布局逻辑性差。
      针对以上两个缺点,引入Tkinter 中的ttk组件。
      需要说明的,ttk的很多组件同Tkinter都是相同的,在这种情况下,ttk将覆盖Tkinter的组件,将采用ttk的特性。使用ttk以后的组件,同windows操作系统(这里是win7系统)的外观的一致性更高,看起来也会舒服很多。
      需要注意的是:
      ttk的用法同Tkinter还是相同的,但是有一些属性ttk不再支持,如 Tkinter 中的fg,bg 在ttk中以不被支持,它是通过style这个对象进行支持的,其它的方面还是变化不大。
import tkinter as tk
from tkinter import ttk
from tkinter import scrolledtext
from tkinter import Menu
from tkinter import Spinbox
from tkinter import messagebox as mBox
 
#由于tkinter中没有ToolTip功能,所以自定义这个功能如下
class ToolTip(object):
    def __init__(self, widget):
        self.widget = widget
        self.tipwindow = None
        self.id = None
        self.x = self.y = 0
 
    def showtip(self, text):
        "Display text in tooltip window"
        self.text = text
        if self.tipwindow or not self.text:
            return
        x, y, _cx, cy = self.widget.bbox("insert")
        x = x + self.widget.winfo_rootx() + 27
        y = y + cy + self.widget.winfo_rooty() +27
        self.tipwindow = tw = tk.Toplevel(self.widget)
        tw.wm_overrideredirect(1)
        tw.wm_geometry("+%d+%d" % (x, y))
 
        label = tk.Label(tw, text=self.text, justify=tk.LEFT,
                      background="#ffffe0", relief=tk.SOLID, borderwidth=1,
                      font=("tahoma", "8", "normal"))
        label.pack(ipadx=1)
 
    def hidetip(self):
        tw = self.tipwindow
        self.tipwindow = None
        if tw:
            tw.destroy()
            
#===================================================================          
def createToolTip( widget, text):
    toolTip = ToolTip(widget)
    def enter(event):
        toolTip.showtip(text)
    def leave(event):
        toolTip.hidetip()
    widget.bind('<Enter>', enter)
    widget.bind('<Leave>', leave)
 
# Create instance
win = tk.Tk()   
 
# Add a title       
win.title("Python 图形用户界面")
 
# Disable resizing the GUI
win.resizable(0,0)
 
# Tab Control introduced here --------------------------------------
tabControl = ttk.Notebook(win)          # Create Tab Control
 
tab1 = ttk.Frame(tabControl)            # Create a tab 
tabControl.add(tab1, text='第一页')      # Add the tab
 
tab2 = ttk.Frame(tabControl)            # Add a second tab
tabControl.add(tab2, text='第二页')      # Make second tab visible
 
tab3 = ttk.Frame(tabControl)            # Add a third tab
tabControl.add(tab3, text='第三页')      # Make second tab visible
 
tabControl.pack(expand=1, fill="both")  # Pack to make visible
# ~ Tab Control introduced here -----------------------------------------
 
#---------------Tab1控件介绍------------------#
# We are creating a container tab3 to hold all other widgets
monty = ttk.LabelFrame(tab1, text='控件示范区1')
monty.grid(column=0, row=0, padx=8, pady=4)
 
# Modified Button Click Function
def clickMe():
    action.configure(text='Hello\n ' + name.get())
    action.configure(state='disabled')    # Disable the Button Widget
 
# Changing our Label
ttk.Label(monty, text="输入文字:").grid(column=0, row=0, sticky='W')
 
# Adding a Textbox Entry widget
name = tk.StringVar()
nameEntered = ttk.Entry(monty, width=12, textvariable=name)
nameEntered.grid(column=0, row=1, sticky='W')
 
# Adding a Button
action = ttk.Button(monty,text="点击之后\n按钮失效",width=10,command=clickMe)   
action.grid(column=2,row=1,rowspan=2,ipady=7)
 
ttk.Label(monty, text="请选择一本书:").grid(column=1, row=0,sticky='W')
 
# Adding a Combobox
book = tk.StringVar()
bookChosen = ttk.Combobox(monty, width=12, textvariable=book)
bookChosen['values'] = ('平凡的世界', '亲爱的安德烈','看见','白夜行')
bookChosen.grid(column=1, row=1)
bookChosen.current(0)  #设置初始显示值,值为元组['values']的下标
bookChosen.config(state='readonly')  #设为只读模式
 
# Spinbox callback 
def _spin():
    value = spin.get()
    #print(value)
    scr.insert(tk.INSERT, value + '\n')
 
def _spin2():
    value = spin2.get()
    #print(value)
    scr.insert(tk.INSERT, value + '\n')
     
# Adding 2 Spinbox widget using a set of values
spin = Spinbox(monty, from_=10,to=25, width=5, bd=8, command=_spin) 
spin.grid(column=0, row=2)
 
spin2 = Spinbox(monty, values=('Python3入门', 'C语言','C++', 'Java', 'OpenCV'), width=13, bd=3, command=_spin2) 
spin2.grid(column=1, row=2,sticky='W')
 
# Using a scrolled Text control    
scrolW  = 30; scrolH  =  5
scr = scrolledtext.ScrolledText(monty, width=scrolW, height=scrolH, wrap=tk.WORD)
scr.grid(column=0, row=3, sticky='WE', columnspan=3)
 
# Add Tooltip
createToolTip(spin,       '这是一个Spinbox.')
createToolTip(spin2,      '这是一个Spinbox.')
createToolTip(action,     '这是一个Button.')
createToolTip(nameEntered,'这是一个Entry.')
createToolTip(bookChosen, '这是一个Combobox.')
createToolTip(scr,        '这是一个ScrolledText.')
 
# 一次性控制各控件之间的距离
for child in monty.winfo_children(): 
    child.grid_configure(padx=3,pady=1)
# 单独控制个别控件之间的距离
action.grid(column=2,row=1,rowspan=2,padx=6)
#---------------Tab1控件介绍------------------#
 
 
#---------------Tab2控件介绍------------------#
# We are creating a container tab3 to hold all other widgets -- Tab2
monty2 = ttk.LabelFrame(tab2, text='控件示范区2')
monty2.grid(column=0, row=0, padx=8, pady=4)
# Creating three checkbuttons
chVarDis = tk.IntVar()
check1 = tk.Checkbutton(monty2, text="失效选项", variable=chVarDis, state='disabled')
check1.select()  
check1.grid(column=0, row=0, sticky=tk.W)                 
 
chVarUn = tk.IntVar()
check2 = tk.Checkbutton(monty2, text="遵从内心", variable=chVarUn)
check2.deselect()   #Clears (turns off) the checkbutton.
check2.grid(column=1, row=0, sticky=tk.W )                  
 
chVarEn = tk.IntVar()
check3 = tk.Checkbutton(monty2, text="屈于现实", variable=chVarEn)
check3.deselect()
check3.grid(column=2, row=0, sticky=tk.W)                 
 
# GUI Callback function 
def checkCallback(*ignoredArgs):
    # only enable one checkbutton
    if chVarUn.get(): check3.configure(state='disabled')
    else:             check3.configure(state='normal')
    if chVarEn.get(): check2.configure(state='disabled')
    else:             check2.configure(state='normal') 
 
# trace the state of the two checkbuttons  #??
chVarUn.trace('w', lambda unused0, unused1, unused2 : checkCallback())    
chVarEn.trace('w', lambda unused0, unused1, unused2 : checkCallback())   
 
# Radiobutton list
values = ["富强民主", "文明和谐", "自由平等","公正法治","爱国敬业","诚信友善"]
 
# Radiobutton callback function
def radCall():
    radSel=radVar.get()
    if   radSel == 0: monty2.configure(text='富强民主')
    elif radSel == 1: monty2.configure(text='文明和谐')
    elif radSel == 2: monty2.configure(text='自由平等')
    elif radSel == 3: monty2.configure(text='公正法治')
    elif radSel == 4: monty2.configure(text='爱国敬业')
    elif radSel == 5: monty2.configure(text='诚信友善')
 
# create three Radiobuttons using one variable
radVar = tk.IntVar()
 
# Selecting a non-existing index value for radVar
radVar.set(99)    
 
# Creating all three Radiobutton widgets within one loop
for col in range(4):
    #curRad = 'rad' + str(col)  
    curRad = tk.Radiobutton(monty2, text=values[col], variable=radVar, value=col, command=radCall)
    curRad.grid(column=col, row=6, sticky=tk.W, columnspan=3)
for col in range(4,6):
    #curRad = 'rad' + str(col)  
    curRad = tk.Radiobutton(monty2, text=values[col], variable=radVar, value=col, command=radCall)
    curRad.grid(column=col-4, row=7, sticky=tk.W, columnspan=3)
 
style = ttk.Style()
style.configure("BW.TLabel", font=("Times", "10",'bold'))
ttk.Label(monty2, text="   社会主义核心价值观",style="BW.TLabel").grid(column=2, row=7,columnspan=2, sticky=tk.EW)
 
# Create a container to hold labels
labelsFrame = ttk.LabelFrame(monty2, text=' 嵌套区域 ')
labelsFrame.grid(column=0, row=8,columnspan=4)
 
# Place labels into the container element - vertically
ttk.Label(labelsFrame, text="你才25岁,你可以成为任何你想成为的人。").grid(column=0, row=0)
ttk.Label(labelsFrame, text="不要在乎一城一池的得失,要执着。").grid(column=0, row=1,sticky=tk.W)
 
# Add some space around each label
for child in labelsFrame.winfo_children(): 
    child.grid_configure(padx=8,pady=4)
#---------------Tab2控件介绍------------------#
 
 
#---------------Tab3控件介绍------------------#
tab3 = tk.Frame(tab3, bg='#AFEEEE')
tab3.pack()
for i in range(2):
    canvas = 'canvas' + str(col)
    canvas = tk.Canvas(tab3, width=162, height=95, highlightthickness=0, bg='#FFFF00')
    canvas.grid(row=i, column=i)
#---------------Tab3控件介绍------------------#
 
 
#----------------菜单栏介绍-------------------#    
# Exit GUI cleanly
def _quit():
    win.quit()
    win.destroy()
    exit()
    
# Creating a Menu Bar
menuBar = Menu(win)
win.config(menu=menuBar)
 
# Add menu items
fileMenu = Menu(menuBar, tearoff=0)
fileMenu.add_command(label="新建")
fileMenu.add_separator()
fileMenu.add_command(label="退出", command=_quit)
menuBar.add_cascade(label="文件", menu=fileMenu)
 
 
# Display a Message Box
def _msgBox1():
    mBox.showinfo('Python Message Info Box', '通知:程序运行正常!')
def _msgBox2():
    mBox.showwarning('Python Message Warning Box', '警告:程序出现错误,请检查!')
def _msgBox3():
    mBox.showwarning('Python Message Error Box', '错误:程序出现严重错误,请退出!')
def _msgBox4():
    answer = mBox.askyesno("Python Message Dual Choice Box", "你喜欢这篇文章吗?\n您的选择是:") 
    if answer == True:
        mBox.showinfo('显示选择结果', '您选择了“是”,谢谢参与!')
    else:
        mBox.showinfo('显示选择结果', '您选择了“否”,谢谢参与!')
 
# Add another Menu to the Menu Bar and an item
msgMenu = Menu(menuBar, tearoff=0)
msgMenu.add_command(label="通知 Box", command=_msgBox1)
msgMenu.add_command(label="警告 Box", command=_msgBox2)
msgMenu.add_command(label="错误 Box", command=_msgBox3)
msgMenu.add_separator()
msgMenu.add_command(label="判断对话框", command=_msgBox4)
menuBar.add_cascade(label="消息框", menu=msgMenu)
#----------------菜单栏介绍-------------------#
 
 
# Change the main windows icon
win.iconbitmap(r'logo.ico')
 
# Place cursor into name Entry
nameEntered.focus()      
#======================
# Start GUI
#======================
win.mainloop()
 

在这里插入图片描述

3.4.3 词频统计

第一步:输入文章
第二步:建立用于词频计算的空字典
第三步:对文本的每一行计算词频,如果文章长度一般,则不需用一次读一行,一次便可读完。
第四步:从字典中获取数据对到列表中
第五步:对列表中的数据对交换位置,并从大到小进行排序
第六步:输出结果

import tkinter as tk
from tkinter import ttk
from tkinter import scrolledtext
from tkinter import filedialog
from tkinter import messagebox as mBox
 
#获取原文内容
def getText(DIR):
    txt=open(DIR,'r').read()
    return txt
    txt.close()
 
#打开文件
def __opendir():
    srcText.delete('1.0', tk.END) # 先删除所有
        
    # 打开文件夹对话框
    fname = filedialog.askopenfilename(filetypes=( ("Text file", "*.txt*"),("HTML files", "*.html;*.htm")))
    entryvar.set(fname) # 设置变量entryvar,等同于设置部件Entry
        
    if not fname:
        mBox.showwarning('警告', message='未选择文件夹!')  # 弹出消息提示框
 
    #显示需要统计的文本
    Txt=getText(fname)
    srcText.insert(tk.END, Txt)
            
    srcText.update()
    
#手动输入文件名时回车键触发      
def srcEnter(event=None):
    
    fname=DirEntry.get()
    if not fname:
        mBox.showwarning('警告', message='请选择文件!')  # 弹出消息提示框
        
    Txt=getText(fname)
    srcText.insert(tk.END, Txt)
            
    srcText.update()
 
#词频统计
def wordFrequence():
    fname=DirEntry.get()
    if not fname:
        mBox.showwarning('警告', message='请选择文件!')  # 弹出消息提示框
 
    txt=getText(fname)
    
    #对原文进行小写,标点符号转换处理
    txt=txt.lower()
    for ch in '!"#$%&*()+,.-;:<=>?@[]\^_{}|`':
        txt=txt.replace(ch,' ')
 
    #词频统计
    words=txt.split()
    counts={} #用空字典存储统计结果
    for word in words:
        counts[word]=counts.get(word,0)+1
 
    #词频排序
    items=list(counts.items())
    items.sort(key=lambda x:x[1],reverse=True)
 
    #输出排序结果
    num=0
    for i in range(len(counts)):
        word,count=items[i]
        num=i*count+num
 
 
    dstText.insert(tk.END, '单词种类:')
    dstText.insert(tk.END, str(len(items)))
    dstText.insert(tk.END, '\n')
    dstText.insert(tk.END, '单词总数:')
    dstText.insert(tk.END, str(num))
    dstText.insert(tk.END, '\n')
    dstText.insert(tk.END, '词频排序如下:\n')
    dstText.insert(tk.END, '#word:\t\t#counts:\n')
 
    for i in range(len(counts)):
        word,count=items[i]
        dstText.insert(tk.END, word)
        dstText.insert(tk.END, '\t\t')
        dstText.insert(tk.END, count)
        dstText.insert(tk.END, '\n')
 
def savefile():
    # 打开文件夹对话框
    dirname = filedialog.askdirectory() 
    outvar.set(dirname) # 设置变量entryvar,等同于设置部件Entry
        
    if not dirname:
        mBox.showwarning('警告', message='请选择保存位置!')  # 弹出消息提示框
 
    fname=dirname+'\词频统计结果.txt'
    outfile = open(fname, "w")
    outfile.writelines(dstText.get(1.0,tk.END))
    outfile.close()
    mBox.showinfo('词频统计', '统计结果保存成功!')
 
def dstEnter(event=None):
    dirname=outvar.get()
    if not dirname:
        mBox.showwarning('警告', message='请选择保存位置!')  # 弹出消息提示框
    fname=dirname+'\词频统计结果.txt'
    outfile = open(fname, "w")
    outfile.writelines(dstText.get(1.0,tk.END))
    outfile.close()
    mBox.showinfo('词频统计', '统计结果保存成功!')
    
# Create instance
win = tk.Tk()   
 
# Add a title       
win.title("词频统计GUI")
 
# Disable resizing the GUI
win.resizable(0,0)
 
 
#---------------窗口控件介绍------------------#
 
#打开文件对话框
SelDirButton = ttk.Button(win, command=__opendir, text='选择文件目录:')
SelDirButton.grid(row=0, column=0,sticky=tk.W,pady=3,padx=3)
 
#文件的目录显示    
entryvar = tk.StringVar() 
DirEntry=ttk.Entry(win, width=30,textvariable=entryvar)
DirEntry.grid(row=1, column=0,sticky=tk.W,pady=3,padx=3)
DirEntry.bind('<Return>', func=srcEnter)
 
#文件内容的显示
srcText = scrolledtext.ScrolledText(win,width=30,height=30)#内容输出框
srcText.grid(row=2, column=0,columnspan=1,sticky=tk.W,pady=3,padx=3)
 
#词频统计按钮
CalcuButton = ttk.Button(win, command=wordFrequence, text='词频统计')
CalcuButton.grid(row=0, column=1,sticky=tk.W,pady=3,padx=3)
 
#统计结果显示
dstText = scrolledtext.ScrolledText(win,width=30,height=30)#内容输出框
dstText.grid(row=2, column=1,columnspan=2,sticky=tk.W,pady=3,padx=3)
 
#保存文件按钮
SavefileButton = ttk.Button(win, command=savefile, text='统计结果保存到:')
SavefileButton.grid(row=0, column=2,sticky=tk.W,pady=3,padx=3)
 
#保存文件目录
outvar = tk.StringVar() 
saveEntry=ttk.Entry(win, width=30,textvariable=outvar)
saveEntry.grid(row=1, column=1,columnspan=2,sticky=tk.W,pady=3,padx=3)
saveEntry.bind('<Return>', func=dstEnter)
 
     
#======================
# Start GUI
#======================
win.mainloop()

在这里插入图片描述

3.4.4 超级聊天窗口

实例中几乎使用tk库中所有的控件,一共包括14种。

#coding:utf-8
from tkinter import *
 
import time
import random 
 
def main():
 ###******回调函数定义******###
  
    def sendMsg():                  #发送消息
        strMsg = 'i_chaoren:' + time.strftime("%Y-%m-%d %H:%M:%S",
                                    time.localtime()) + '\n '
        txtMsgList.insert(END, strMsg, 'greencolor')   #插入到tag位置
        txtMsgList.insert(END, txtMsg.get('0.0', END))
        txtMsg.delete('0.0', END)
     
    def cancelMsg():                #取消消息
        txtMsg.delete('0.0', END)
 
    def sendMsgEvent(event):        #发送消息事件
        if event.keysym == "Return":  #按回车键可发送
            sendMsg()
 
    def red():                      #Canvas背景色控制
        imgCanvas.config(bg='red')
    def green():
        imgCanvas.config(bg='green')
    def blue():
        imgCanvas.config(bg='blue')
    def color1():
        names = ['red', 'green', 'blue','yellow','white','SlateGray','SpringGreen','LightSteelBlue','Cyan','BlueViolet','GhostWhite']
        for i in names:
            imgCanvas.config(bg=i)
        time.sleep(0.4)
        imgCanvas.update()
        
    def Oval():                     #Canvas绘制几何图案
        imgCanvas.create_oval(110, 20, 170, 120)
    def Polygon():
        imgCanvas.create_polygon(20, 20, 110, 50,100,110,40,120)
    
    def fontSize(ev=None):          #字体缩放
        timeText2.config(font='Helvetica -%d bold' % sizeScale.get())
        sizeLabel.config(text='字号:%d'% sizeScale.get())
    
    def txtlist():                  #字典实现--书名与内容的对应
        book={'NO.1 《平凡的世界》  路遥':'1.一个平平常常的日子,细蒙蒙的雨丝夹着一星半点的雪花,正纷纷淋淋的向大地飘洒着,时令已快到惊蛰,雪当然再不会存留,往往还没等落地,就消失的无踪无影了,黄土高原严寒而漫长的冬天看来就要过去,但那真正温暖的春天还远远没有到来。\n2、这时候,他也体验到了类似孙少平的那种感觉:只有繁重的体力劳动才使精神上的痛苦变为某种麻木,以致思维局限在机械性活动中。\n3、哭,笑,都是因为欢乐,哭的人知道而笑的人不知道,这欢乐是多少痛苦所换来的。',
            'NO.2 《看见》  柴静':'1.写本身也是一种发现自己的过程,你不写永远都知道自己身上发生了什么。\n2.保持对不同论述的警惕,才能保持自己的独立性。\n3.灵魂变得沉重,是因为爱,因为所爱的东西,眼睁睁在失去,却无能为力。\n4.我可能做不到更好了,但还是要像朱光潜说的那样,此时,此地,此身,此时我能做的事情绝不推诿到下一时刻,此地我能做的事情绝不换另一种境地再去做,此身我能做的事绝不妄想与他人来替代。\n5.如果带着强烈的预设和反感,你就没有办法真的认识这个人。',
            'NO.3 《亲爱的安德烈》龙应台':'1.我也要求你读书用功,不是因为我要你跟别人比较成就,而是因为,我希望你将来会拥有会选择的权利,选择有意义、有时间的工作,而不是被迫谋生。 当你的工作在你的心中有意义,你就有成就感。当你的工作给你时间,不剥夺你的生活,你就有尊严。成就感和尊严,给你快乐。\n2.农村中长大的孩子,会接触更真实的社会,接触更丰富的生活,会感受到人间的各种悲欢离合。所以更能形成那种原始的,正面的价值观—那“愚昧无知”的渔村,确实没有给我知识,但是给了我一种能力,悲悯同情的能力,使得我在日后面对权利的傲慢、欲望的嚣张和种种时代的虚假时,仍旧得以穿透,看见文明的核心关怀所在。'}
        txtText.delete(0.0,END)
        txtText.insert(END,book[txtSpinbox.get()])
    def message():                  #弹出窗口
        messagebox.showinfo("联系人搜索","这是一个假的功能!!")
        
    ###******回调函数定义******###
        
        
    
    #创建窗口 
    t = Tk()
    t.title('超级聊天窗口')     # 窗口名称
    t.resizable(0, 0)           # 禁止调整窗口大小
        
    
    ###******创建frame容器******###
    
    #第一列
    frmA1 = Frame(width=180, height=30)
    frmA2 = Frame(width=180, height=290)
    frmA3 = Frame(width=180, height=140) 
    frmA4 = Frame(width=180, height=30) 
    #第二列
    frmB1 = Frame(width=350, height=320)
    frmB2 = Frame(width=350, height=150)
    frmB3 = Frame(width=350, height=30)
    #第三列
    frmC1 = Frame(width=200, height=30)
    frmC11= Frame(width=200, height=290)
    frmC2 = Frame(width=200, height=150)
    frmC3 = Frame(width=200, height=30)
    
    ###******创建frame容器******###
    
    
    ###******创建控件******###
    
    #1.Text控件
    txtMsgList = Text(frmB1)                          #frmB1表示父窗口
    #创建并配置标签tag属性
    txtMsgList.tag_config('greencolor',               #标签tag名称
                            foreground='#008C00')       #标签tag前景色,背景色为默认白色
    
    txtMsg = Text(frmB2);
    txtMsg.bind("<KeyPress-Return>", sendMsgEvent)    #事件绑定,定义快捷键
    
    timeText=Text(frmC2,font=("Times", "28", "bold italic"),height=1,bg="PowderBlue")
    timeText2=Text(frmC2,fg="blue",font=("Times", "12","bold italic"))
    
    txtText=Text(frmC11,font=("Times", "11",'bold'),  #字体控制
                width=24,height=15,                  #文本框的宽(in characters )和高(in lines) (not pixels!)
                spacing2=5,                          #文本的行间距
                bd=2,                                #边框宽度
                padx=5,pady=5,                       #距离文本框四边的距离
                selectbackground='blue',             #选中文本的颜色
                state=NORMAL)                        #文本框是否启用 NORMAL/DISABLED
    txtText.insert(END,'1.一个平平常常的日子,细蒙蒙的雨丝夹着一星半点的雪花,正纷纷淋淋的向大地飘洒着,时令已快到惊蛰,雪当然再不会存留,往往还没等落地,就消失的无踪无影了,黄土高原严寒而漫长的冬天看来就要过去,但那真正温暖的春天还远远没有到来。\n2、这时候,他也体验到了类似孙少平的那种感觉:只有繁重的体力劳动才使精神上的痛苦变为某种麻木,以致思维局限在机械性活动中。\n3、哭,笑,都是因为欢乐,哭的人知道而笑的人不知道,这欢乐是多少痛苦所换来的。')
                                                        # insert(插入位置,插入内容)
    #2.Button控件
    btnSend = Button(frmB3, text='发 送', width = 8,cursor='heart', command=sendMsg)
    btnCancel = Button(frmB3, text='取消', width = 8,cursor='shuttle', command=cancelMsg)
    btnSerch=Button(frmA1, text='搜索联系人',         #button的显示内容
                    width = 9,height=1,               #宽和高
                    cursor='man',                     #光标样式     
                    command =message)                 #回调函数
    
    #3.Entry控件
    entrySerch=Entry(frmA1, bd =3,width=14,
                    show='*')                        #输入值以掩码显示    
    
    #4.Scrollbar控件
    scroLianxi = Scrollbar(frmA2,width=22,cursor='pirate',troughcolor="blue") 
    
    #5.Listbox控件
    listLianxi = Listbox(frmA2, width=22,height=16,
                        yscrollcommand = scroLianxi.set )  #连接listbox 到 vertical scrollbar
    Linkman=['曹操','刘备','孙权','关羽','张飞','赵云','马超','黄忠','张郃','姜维','夏侯惇','魏延','张辽','周瑜','贾诩','典韦','吕布','袁绍','袁术','貂蝉','董卓','华佗','诸葛亮','郭嘉','孙策','孙坚','太史慈','鲁肃','黄盖','程普','程昱','司马懿','曹丕','曹植','曹睿']
    for line in Linkman:
        listLianxi.insert(END, "  联系人   ------   " + str(line))
    scroLianxi.config( command = listLianxi.yview )   #scrollbar滚动时listbox同时滚动
    
    #6.Canvas控件
    imgCanvas=Canvas(frmA3,bg='ivory')
    
    #7.Radiobutton控件
    var = IntVar()                                    #设置variable和value可以保证只有一个按钮被按下
    R1 = Radiobutton(frmA4, text="多边形", variable=var, value=1,command=Polygon)
    R2 = Radiobutton(frmA4, text="椭圆", variable=var, value=2,command=Oval)
    
    #8.Menubutton控件
    colorMenubt =  Menubutton (frmA4, text="画板颜色", relief=RAISED )
    
    #9.Menu控件
    colorMenubt.menu  =  Menu ( colorMenubt, tearoff = 0 )
    colorMenubt["menu"]  =  colorMenubt.menu
    
    colorMenubt.menu.add_checkbutton ( label="红色",command=red)
    colorMenubt.menu.add_checkbutton ( label="绿色",command=green)
    colorMenubt.menu.add_checkbutton ( label="蓝色",command=blue)
    colorMenubt.menu.add_separator()       #添加菜单分隔符
    colorMenubt.menu.add_checkbutton ( label="连续色",command=color1)
    
    #10.Scale控件
    sizeScale = Scale(frmC3,length=135,width=18,from_=10, to=35,orient=HORIZONTAL,command=fontSize,cursor='star',
                        showvalue=0,         #不显示数值
                        sliderlength=30,     #滑块的长度             
                        troughcolor='ivory') #滑动条底色
    sizeScale.set(20)                      #设置滑块的初始值
    
    #11.Label控件
    sizeLabel = Label(frmC3,width=8,height=1,bd=1, relief=RIDGE)
    nameLabel = Label(frmC1, text='   Favorite Book List',font="Times 16 bold italic")
    
    #12.Spinbox控件
    txtSpinbox = Spinbox(frmC11,width=24,command=txtlist)
    txtSpinbox.config(values=['NO.1 《平凡的世界》  路遥','NO.2 《看见》  柴静','NO.3 《亲爱的安德烈》龙应台'])
    
    ###******创建控件******###
    
    
    ###******窗口布局******###
    
    frmA1.grid(row=0, column=0, padx=10, pady=3)
    frmA2.grid(row=1, column=0, padx=10)
    frmA3.grid(row=2, column=0, rowspan=1)
    frmA4.grid(row=3, column=0, rowspan=1)
    
    frmB1.grid(row=0, column=1, columnspan=1, rowspan=2, padx=1, pady=3)
    frmB2.grid(row=2, column=1, columnspan=1, padx=1, pady=1)
    frmB3.grid(row=3, column=1, columnspan=1, padx=1)
    
    frmC1.grid(row=0, column=2, rowspan=1, padx=1, pady=1)
    frmC11.grid(row=1, column=2, rowspan=1, padx=1, pady=1)  
    frmC2.grid(row=2, column=2, rowspan=1, padx=1, pady=1)
    frmC3.grid(row=3, column=2, padx=1)
    
    ###******窗口布局******###
    
    
    #固定大小
    frmA1.grid_propagate(0)
    frmA2.grid_propagate(0)
    frmA3.grid_propagate(0)
    #frmA4.grid_propagate(0)
    
    frmB1.grid_propagate(0)
    frmB2.grid_propagate(0)
    frmB3.grid_propagate(0)
    
    frmC1.grid_propagate(0)
    frmC11.grid_propagate(0)  
    frmC2.grid_propagate(0)
    frmC3.grid_propagate(0)
    
    
    ###******控件布局******### 
    
    btnSend.grid(row=0, column=0)
    btnCancel.grid(row=0, column=1)
    btnSerch.grid(row=0,column=1)
    
    nameLabel.grid()
    sizeLabel.grid(row=0,column=0)
    
    txtMsgList.grid()
    txtMsg.grid()
    
    entrySerch.grid(row=0,column=0)
    
    scroLianxi.grid(row=0,column=1,ipady=120)
    
    listLianxi.grid(row=0,column=0)
    
    imgCanvas.grid(row=0,column=0,sticky=N)
    
    colorMenubt.grid(row=0,column=0)
    
    R1.grid(row=0,column=1) 
    R2.grid(row=0,column=2)
    
    timeText.grid(row=0,column=0)
    timeText2.grid(row=1,column=0,sticky=E+W)
    txtText.grid(row=1,column=0,pady=5)
    
    sizeScale.grid(row=0,column=1)
    txtSpinbox.grid(row=0,column=0)
    
    ###******控件布局******### 
    
    
    #时间模块,开启之后会影响运行速度
    ''' 
    while 1:
        Time1 = time.strftime("   %H:%M:%S",time.localtime()) + '\n '
        Time2 = time.strftime("  %Y/%m/%d",time.localtime()) + '\n '
        Time3 = time.strftime("   %A",time.localtime()) + '\n '
                                
        timeText.insert(END, Time1)
        timeText2.insert(END, Time2)
        timeText2.insert(END, Time3)
                                
        time.sleep(1)
        timeText.update()
        timeText.delete(1.0,END)
        timeText2.delete(1.0,END)
    '''
    #主事件循环
    t.mainloop()
 
if __name__ == '__main__':
    main()

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

岳涛@心馨电脑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值