【Python】GUI编程(Tkinter)教程

什么是Tkinter?

Tkinter 是 Python 的标准 GUI 库。Python 使用 Tkinter 可以快速的创建 GUI 应用程序。

由于 Tkinter 是内置到 python 的安装包中、只要安装好 Python 之后就能 import Tkinter 库、而且 IDLE 也是用 Tkinter 编写而成、对于简单的图形界面 Tkinter 还是能应付自如。

使用

导入

import tkinter

注意:Python3.x 版本使用的库名为 tkinter,即首写字母 T 为小写。

创建一个GUI程序

  • 1、导入 Tkinter 模块
  • 2、创建控件
  • 3、指定这个控件的 master, 即这个控件属于哪一个
  • 4、告诉 GM(geometry manager) 有一个控件产生了。
#!/usr/bin/python3
 
import tkinter
top = tkinter.Tk()
# 进入消息循环
top.mainloop()

窗口主体框架 

每一个 tkinter 应用的主体框架都可以包含下面这部分. 定义 window 窗口 和 window的一些属性, 然后书写窗口内容, 最后执行window.mainloop让窗口活起来.

import tkinter as tk

window = tk.Tk()
window.title('my window')
window.geometry('500x500')
#注意:这里的乘是×不是* # 这里是窗口的内容 window.mainloop()

 窗口内容

 Label & Button 标签和按钮

这次我们会建立一个用来描述的标签 tk.Label, 比如:

import tkinter as tk
#创建窗口
window=tk.Tk()
window.title('Mywindow')#窗口的标题
window.geometry('200x100')#窗口的大小
#定义一个label
l = tk.Label(window, 
    text='Hi! this is TK!',    # 标签的文字
    bg='green',     # 标签背景颜色
    font=('Arial', 12),     # 字体和字体大小
    width=15, height=2  # 标签长宽(以字符长度计算)
    )
l.pack()    # 固定窗口位置

window.mainloop()

关于Label的更多内容可以看这里https://www.runoob.com/python/python-tk-label.html

 我们也可以通过变量的形式控制标签的显示, 这时我们引入按钮 tk.Button 的概念, 没点一次按钮, 标签变化一次. 用一下内容替换上面的标签. 并把需要变化的文字存成变量 var:

var = tk.StringVar()    # 这时文字变量储存器
l = tk.Label(window, 
    textvariable=var,   # 使用 textvariable 替换 text, 因为这个可以变化
    bg='green', font=('Arial', 12), width=15, height=2)
l.pack() 

接着我们来做 按钮 tk.Button:

b = tk.Button(window, 
    text='hit me',      # 显示在按钮上的文字
    width=15, height=2, 
    command=hit_me)     # 点击按钮式执行的命令
b.pack()    # 按钮位置

那么点击是的命令我们用 if else 语句来判断. 用 on_hit 来判断当前状态.

on_hit = False  # 默认初始状态为 False
def hit_me():
    global on_hit
    if on_hit == False:     # 从 False 状态变成 True 状态
        on_hit = True
        var.set('you hit me')   # 设置标签的文字为 'you hit me'
    else:       # 从 True 状态变成 False 状态
        on_hit = False
        var.set('') # 设置 文字为空

完整代码:

import tkinter as tk
#创建窗口
window=tk.Tk()
window.title('Mywindow')#窗口的标题
window.geometry('200x100')#窗口的大小
#定义一个label
var=tk.StringVar()#定义一个字符串变量
l = tk.Label(window, 
    textvariable=var,    # 标签的文字
    bg='green',     # 标签背景颜色
    font=('Arial', 12),     # 字体和字体大小
    width=15, height=2  # 标签长宽
    )
l.pack()    # 固定窗口位置
#定义一个全局变量,来表明字符显示与不显示
on_hit=False

#按钮的函数
def hit_me():
    global on_hit#声明全局变量
    if on_hit==False:
        on_hit=True
        var.set('You hit me!')
    else:
        on_hit=False
        var.set('')
#按钮
b=tk.Button(window,text='点我',width=15,height=2,command=hit_me)#点击按钮执行一个名为“hit_me”的函数
b.pack()

window.mainloop()

没有点击时:

Label & Button 标签和按钮

点击第一次:

Label & Button 标签和按钮

点击第二次:

Label & Button 标签和按钮

Entry & Text 输入, 文本框

窗口主体框架 

每一个tkinter应用的主体框架都包含以下几部分:

  • 主窗口: window,及主窗口的一些基本属性(标题、大小)
  • 让窗口活起来:window.mainloop()
import tkinter as tk

window = tk.Tk()
window.title('my window')

##窗口尺寸
window.geometry('200x200')

##显示出来
window.mainloop()

窗口内容(窗口上的控件)

创建按钮分别触发两种情况

b1 = tk.Button(window,text="insert point",width=15,height=2,command=insert_point)
b1.pack()

b2 = tk.Button(window,text="insert end",command=insert_end)
b2.pack()

创建输入框entry,用户输入任何内容都显示为*

e = tk.Entry(window,show='*')
e.pack()

创建一个文本框用于显示

t = tk.Text(window,height=2)
t.pack()

定义触发事件时的函数(注意:因为Python的执行顺序是从上往下,所以函数一定要放在按钮的上面)

def insert_point():
    var = e.get()
    t.insert('insert',var)

def insert_end():
    var = e.get()
    t.insert('end',var)

完整代码:

import tkinter as tk

window = tk.Tk()
window.title('my window')
##窗口尺寸
window.geometry('200x200')
#定义一个输入框entry
e=tk.Entry(window,show=None)#如果是输入密码,可以写show='*'
e.pack()
#定义按钮功能
def insert_point():
    var=e.get()
    t.insert('insert',var)
def insert_end():
    var=e.get()
    t.insert('end',var)#这里还可以定义字符串插入的具体位置,比如t.insert('1.1',var),表示插入到第一行第一列
#定义2个按钮 Button b1 = tk.Button(window,text="insert point",width=15,height=2,command=insert_point) b1.pack() b2 = tk.Button(window,text="insert end",command=insert_end) b2.pack() #定义一个文本框 Text t=tk.Text(window,height=2) t.pack() ##显示出来 window.mainloop()

窗口界面

测试一下 

第一次:在entry中输入tkinter,在text中输入0000并将光标定位在中间位置,点击insert point

Entry & Text 输入, 文本框

第二次:点击insert end

Entry & Text 输入, 文本框

 Listbox 列表部件

创建主窗口

import tkinter as tk

window = tk.Tk()
window.title('my window')
##窗口尺寸
window.geometry('200x200')


##显示出来
window.mainloop()

创建一个label用于显示 

var1 = tk.StringVar()    #创建变量
l =tk.Label(window,bg='yellow',width=4,textvariable=var1)
l.pack()

创建一个方法用于按钮的点击事件

def print_selection():
    value = lb.get(lb.curselection())   #获取当前选中的文本
    var1.set(value)     #为label设置值

创建一个按钮

b1 = tk.Button(window, text='print selection', width=15,
              height=2, command=print_selection)
b1.pack()

创建一个Listbox和变量var2,并将var2的值赋给Listbox

var2 = tk.StringVar()
var2.set((11,22,33,44)) #为变量设置值

#创建Listbox

lb = tk.Listbox(window, listvariable=var2)  #将var2的值赋给Listbox

#创建一个list并将值循环添加到Listbox控件中
list_items = [1,2,3,4]
for item in list_items:
    lb.insert('end', item)  #从最后一个位置开始加入值
lb.insert(1, 'first')       #在第一个位置加入'first'字符
lb.insert(2, 'second')      #在第二个位置加入'second'字符
lb.delete(2)                #删除第二个位置的字符
lb.pack()

完整代码:

import tkinter as tk

window = tk.Tk()
window.title('my window')
##窗口尺寸
window.geometry('200x200')
#创建一个lable
var1 = tk.StringVar()    #创建变量
l =tk.Label(window,bg='yellow',width=4,textvariable=var1)
l.pack()
#按钮事件
def print_selection():
    value = lb.get(lb.curselection())   #获取当前选中的文本
    var1.set(value)     #为label设置值
#创建一个按钮
b1 = tk.Button(window, text='print selection', width=15,
              height=2, command=print_selection)
b1.pack()
#创建一个Listbox和变量var2,并将var2的值赋给Listbox
var2 = tk.StringVar()
var2.set((11,22,33,44)) #为变量设置值

#创建Listbox

lb = tk.Listbox(window, listvariable=var2)  #将var2的值赋给Listbox

#创建一个list并将值循环添加到Listbox控件中
list_items = [1,2,3,4]#定义列表
for item in list_items:
    lb.insert('end', item)  #从最后一个位置开始加入值
lb.insert(1, 'first')       #在第一个位置加入'first'字符
lb.insert(2, 'second')      #在第二个位置加入'second'字符
lb.delete(2)                #删除第二个位置的字符
lb.pack()


##显示出来
window.mainloop()

演示

Radiobutton 选择按钮

这一次的效果将会像下面的图片一样.

Radiobutton 选择按钮

如果选择了某个选项, 效果就会如下.

Radiobutton 选择按钮

radiobutton 部件

首先我们需要定义一个 var 用来将 radiobutton 的值和 Label 的值联系在一起. 然后创建一个radiobutton部分:

var = tk.StringVar()
l = tk.Label(window, bg='yellow', width=20, text='empty')
l.pack()

r1 = tk.Radiobutton(window, text='Option A',
                    variable=var, value='A',
                    command=print_selection)
r1.pack()

其中variable=varvalue='A'的意思就是,当我们鼠标选中了其中一个选项,把value的值A放到变量var中,然后赋值给variable

触发功能

我们将定义一个功能, 用来对选择的 radiobutton 进行操作. print_selection 功能就是选择了某个 radiobutton 后我们会在屏幕上打印的选项.

def print_selection():
    l.config(text='you have selected ' + var.get())

当触发这个函数功能时,我们的 label 中就会显示 text 所赋值的字符串即 ‘you have selected’, 后面则是我们所选中的选项 var.get()就是获取到变量 var 的值, 举个例子就是我们一开始所做的将选项 “option A” 选中时的值以 “A” 放入 var 中, 所以获取的也就是A 即如果我们这时候选中 “option A” 选项,label显示的值则是 “you have selected A”.

完整代码:

import tkinter as tk

window = tk.Tk()
window.title('my window')
##窗口尺寸
window.geometry('200x200')
#创建一个lable
var= tk.StringVar()    #创建变量
l =tk.Label(window,bg='yellow',width=20,height=2,text='empty')
l.pack()
#实现将选择的选项显示在lable
def print_selection():
    l.config(text='you have selected'+var.get())

#创建几个Radiobutton
r1 = tk.Radiobutton(window, text='Option A',
                    variable=var, value='A',
                    command=print_selection)
r1.pack()

r2 = tk.Radiobutton(window, text='Option B',
                    variable=var, value='B',
                    command=print_selection)
r2.pack()

r3 = tk.Radiobutton(window, text='Option C',
                    variable=var, value='C',
                    command=print_selection)
r3.pack()

##显示出来
window.mainloop()

演示:

 Scale 尺度

这一次的效果将会像下面的图片一样.

Scale 尺度

如果拖动滚动条, 效果就会如下.

Scale 尺度

Scale 尺度

scale 部件

s = tk.Scale(window, label='try me', from_=5, to=11, orient=tk.HORIZONTAL,
             length=200, showvalue=0, tickinterval=2, resolution=0.01, command=print_selection)
s.pack()

这里的参数label是指scale部件的名称,即在这里scale部件名称为try me

  • 参数from_=5,to=11的意思就是从5到11,即这个滚动条最小值为5,最大值为11(这里使用from_是因为在python中有from这个关键词)
  • 参数orient=tk.HORIZONTAL在这里就是设置滚动条的方向,如我们所看到的效果图,这里HORIZONTAL就是横向。
  • 参数length这里是指滚动条部件的长度,但注意的是和其他部件width表示不同,width表示的是以字符为单位,比如width=4,就是4个字符的长度,而此处的length=200,是指我们常用的像素为单位,即长度为200个像素
  • 参数resolution=0.01这里我们可以借助数学题来理解,我们做的很多数学题都会让我们来保留几位小数,此处的0.01就是保留2位小数,即效果图中的5.00 9.00等等后面的两位小数,如果保留一位就是resolution=0.1 这里的showvalue就是设置在滚动条上方的显示。showvalue=0显示的就是效果图,上方无结果显示,如果改为showvalue=1,则会显示为:

Scale 尺度

参数tickinterval设置的就是坐标的间隔,此处为tickinterval=2,显示的即为效果图中的5.00 7.00 9.00 11.00 如果改为tickinterval=3则为5.00 8.00 11.00:

Scale 尺度

触发功能 

l = tk.Label(window, bg='yellow', width=20, text='empty')
l.pack()

def print_selection(v):
    l.config(text='you have selected ' + v)

这里相比前面多了参数v,这里的参数v即将滚动条定位的数据,即如效果图中最开始,定位到5.00,label中显示you have selected 5.00

完整代码:

import tkinter as tk

window = tk.Tk()
window.title('my window')
##窗口尺寸
window.geometry('200x200')
#创建一个label

l =tk.Label(window,bg='yellow',width=20,height=2,text='empty')
l.pack()
#实现将选择的选项显示在lable
def print_selection(v):
    l.config(text='you have selected'+v)
#创建一个Scale
s=tk.Scale(window,label='Try me',from_=5,to=11,orient=tk.HORIZONTAL,
length=200,showvalue=1,tickinterval=3,resolution=0.01,command=print_selection)
s.pack()

##显示出来
window.mainloop()

 Checkbutton 勾选项

运行之后的效果将会像下面的图片一样,此时不作任何操作.

Checkbutton 勾选项

如果只选中第一个选项,即图中的python, 效果就会如下.

Checkbutton 勾选项

如果只选中第二个选项,即图中的c++, 效果就会如下.

Checkbutton 勾选项

如果两个选项都选中, 效果就会如下.

Checkbutton 勾选项

如果两个选项都不选中, 效果就会如下.

Checkbutton 勾选项

Checkbutton部件

var1 = tk.IntVar()
c1 = tk.Checkbutton(window, text='Python', variable=var1, onvalue=1, offvalue=0,
                    command=print_selection)
c1.pack()

参数onvalue和前面讲的部件radiobutton中的value相似, 当我们选中了这个checkbutton,onvalue的值1就会放入到var1中, 然后var1将其赋值给参数variableoffvalue用法相似,但是offvalue是在没有选中这个checkbutton时,offvalue的值1放入var1,然后赋值给参数variable 这是创建一个checkbutton部件,以此类推,可以创建多个checkbutton

触发功能

def print_selection():
    if (var1.get() == 1) & (var2.get() == 0):   #如果选中第一个选项,未选中第二个选项
        l.config(text='I love only Python ')
    elif (var1.get() == 0) & (var2.get() == 1): #如果选中第二个选项,未选中第一个选项
        l.config(text='I love only C++')
    elif (var1.get() == 0) & (var2.get() == 0):  #如果两个选项都未选中
        l.config(text='I do not love either')
    else:
        l.config(text='I love both')             #如果两个选项都选中

相对于前面学过的 print_selection,这一段比较长,其实功能差不多,只不过加了if...elif...else来选择控制而已即如代码注释,config在前面已经讲过就是将参数text的值显示,这里的var1.get() == 1 就是前面所说的var1获得的变量onvalue=1var1.get() == 0即是var1获得的变量offvalu=0同理var2也是如此。

完整代码:

import tkinter as tk

window = tk.Tk()
window.title('my window')
##窗口尺寸
window.geometry('200x200')
#创建一个lable

l =tk.Label(window,bg='yellow',width=20,height=2,text='empty')
l.pack()
#实现将选择的选项显示在lable
def print_selection():
    if (var1.get() == 1) & (var2.get() == 0):   #如果选中第一个选项,未选中第二个选项
        l.config(text='I love only Python ')
    elif (var1.get() == 0) & (var2.get() == 1): #如果选中第二个选项,未选中第一个选项
        l.config(text='I love only C++')
    elif (var1.get() == 0) & (var2.get() == 0):  #如果两个选项都未选中
        l.config(text='I do not love anything')
    else:
        l.config(text='I love both')             #如果两个选项都选中

var1=tk.IntVar()
var2=tk.IntVar()
#创建2个cheakButton
cl=tk.Checkbutton(window,text='Python',variable=var1,onvalue=1,offvalue=0,command=print_selection)
cl.pack()
c2=tk.Checkbutton(window,text='C++',variable=var2,onvalue=1,offvalue=0,command=print_selection)
c2.pack()
##显示出来
window.mainloop()

演示:

Canvas 画布

运行之后的效果将会像下面的图片一样.

Canvas 画布

如果点击move这个button, 效果就会如下.

Canvas 画布

Canvas部件

canvas = tk.Canvas(window, bg='blue', height=100, width=200)
canvas.pack()

这里的参数和以往学过的部件一样,所以就不再一一解释。 如果你想下载那个 instagram 的图标, 可以点击这里下载, 或者直接右键保存下面的图像.

Canvas 画布

image_file = tk.PhotoImage(file='ins.gif')
image = canvas.create_image(10, 10, anchor='nw', image=image_file)

这里的代码主要是实现我们最终看到的在左上角的那张小图片。 image_file = tk.PhotoImage(file='ins.gif')这一句是创造一个变量存放ins.gif这张图片。 image = canvas.create_image(10, 10, anchor='nw', image=image_file)里面的参数10,10就是图片放入画布的坐标, 而这里的anchor=nw则是把图片的左上角作为锚定点,在加上刚刚给的坐标位置,即可将图片位置确定。 最后一个参数的意思大家应该都知道,就是将刚刚存入的图片变量,赋值给image

x0, y0, x1, y1= 50, 50, 80, 80
line = canvas.create_line(x0, y0, x1, y1)

这段代码主要实现的是画一条直线,后面()中给的参数就是线段两点的坐标,两点确定一条直线。此处给的就是从坐标(50,50)到(80,80)画一条直线。

oval = canvas.create_oval(x0, y0, x1, y1, fill='red')  #创建一个圆,填充色为`red`红色
arc = canvas.create_arc(x0+30, y0+30, x1+30, y1+30, start=0, extent=180)  #创建一个扇形
rect = canvas.create_rectangle(100, 30, 100+20, 30+20)   #创建一个矩形

这里面就是创建扇形时多了两个没见过的参数start=0extent=180,其实就是从0度到180度,就好像扇子的边打开一样。在我们看来就是个半圆, 如果改为extent=90,我们看到的就是一个1/4圆

触发功能 

def moveit():
    canvas.move(rect, 0, 2)

这里的触发不再是以往的print_selection了,哈哈,那么这里的是怎么样的功能呢,首先我们从单词理解来看就是移动的函数,在视频中也演示过了, 就是我们每点一次button 矩形就会移动这里canvas.move(rect, 0, 2)的参数(rect,0,2)就是移动rect这个变量,即我们看到的矩形 后面的0和2,也就是横坐标移动0个单位,纵坐标移动2个单位,简单的说就是每次点击,横向不动,纵向移动两个单位。

完整代码:

import tkinter as tk

window = tk.Tk()
window.title('my window')
##窗口尺寸
window.geometry('200x200')
#新建画布
#显示图片
canvas=tk.Canvas(window,bg='blue',height=100,width=200)
image_file=tk.PhotoImage(file='ins.gif')
image=canvas.create_image(0,0,anchor='nw',image=image_file)
#画线
x0,y0,x1,y1=50,50,80,80
line=canvas.create_line(x0,y0,x1,y1)
#画⚪
oval=canvas.create_oval(x0,y0,x1,y1,fill='red')
#画一个扇形
arc = canvas.create_arc(x0+30, y0+30, x1+30, y1+30, start=0, extent=90)  
#画一个矩形
rect = canvas.create_rectangle(100, 30, 100+20, 30+20)   
canvas.pack()
def moveit():
    canvas.move(rect,0,2)

#创建一个Button
b=tk.Button(window,text='Move',command=moveit)
b.pack()
##显示出来
window.mainloop()

演示:

Menubar 菜单

这一次的效果将会像下面的图片一样.

Menubar 菜单

注意这里的操作系统是苹果的 MacOS, 它的菜单栏位置和 Windows 的不一样.

Menubar 菜单

Menubar 菜单

下面是我们制作整个菜单栏的流程, 我们先需要加入一个 Menubar 作为整体框架, 然后再在 Menubar 中加一些部件.

##创建一个菜单栏,这里我们可以把他理解成一个容器,在窗口的上方
menubar = tk.Menu(window)

##定义一个空菜单单元
filemenu = tk.Menu(menubar, tearoff=0)

##将上面定义的空菜单命名为`File`,放在菜单栏中,就是装入那个容器中
menubar.add_cascade(label='File', menu=filemenu)

##在`File`中加入`New`的小菜单,即我们平时看到的下拉菜单,每一个小菜单对应命令操作。
##如果点击这些单元, 就会触发`do_job`的功能
filemenu.add_command(label='New', command=do_job)
filemenu.add_command(label='Open', command=do_job)##同样的在`File`中加入`Open`小菜单
filemenu.add_command(label='Save', command=do_job)##同样的在`File`中加入`Save`小菜单

filemenu.add_separator()##这里就是一条分割线

##同样的在`File`中加入`Exit`小菜单,此处对应命令为`window.quit`
filemenu.add_command(label='Exit', command=window.quit)

同样的我们在定义另一个菜单Edit也是如此和定义的File菜单一样 这里再来看一下效果中比较不一样的菜单就是File中的Import菜单, 在这个菜单选项中, 我们还能分支出更多的选项.

submenu = tk.Menu(filemenu)##和上面定义菜单一样,不过此处实在`File`上创建一个空的菜单
filemenu.add_cascade(label='Import', menu=submenu, underline=0)##给放入的菜单`submenu`命名为`Import`
submenu.add_command(label="Submenu1", command=do_job)##这里和上面也一样,在`Import`中加入一个小菜单命令`Submenu1`

触发功能

counter = 0
def do_job():
    global counter
    l.config(text='do '+ str(counter))
    counter+=1

这里的功能就是每触发一次命令,counter就会+1,在label上的显示就会从 do 0 ,do 1 , do 2…

完整代码:

import tkinter as tk

window = tk.Tk()
window.title('my window')
##窗口尺寸
window.geometry('200x200')
#新建一个label
l=tk.Label(window,text='',bg='yellow')
l.pack()
#计数
counter = 0
def do_job():
    global counter
    l.config(text='do '+ str(counter))
    counter+=1
#创建菜单
menubar=tk.Menu(window)
#菜单一
filemenu=tk.Menu(menubar,tearoff=0)
#一级菜单
menubar.add_cascade(label='File',menu=filemenu)
#二级菜单
filemenu.add_command(label='New',command=do_job)
filemenu.add_command(label='Open',command=do_job)
filemenu.add_separator()#分割线
filemenu.add_command(label='Exit',command=window.quit)
#菜单二
editmenu=tk.Menu(menubar,tearoff=0)
#一级菜单
menubar.add_cascade(label='Edit',menu=editmenu)
#二级菜单
editmenu.add_command(label='Cut',command=do_job)
editmenu.add_command(label='Paste',command=do_job)
#
#菜单一子菜单
submenu=tk.Menu(filemenu)
#一级菜单
filemenu.add_cascade(label='Import',menu=submenu,underline=0)
#二级菜单
submenu.add_command(label='Submeau1',command=do_job)
submenu.add_command(label='Submeau1',command=do_job)

window.config(menu=menubar)
##显示出来
window.mainloop()

演示:

Frame 框架

这一次的效果将会像下面的图片一样.

Frame 框架

Frame 部件 

Frame 是一个在 Windows 上分离小区域的部件, 它能将 Windows 分成不同的区,然后存放不同的其他部件. 同时一个 Frame 上也能再分成两个 Frame, Frame 可以认为是一种容器.

###定义一个`label`显示`on the window`
tk.Label(window, text='on the window').pack()

###在`window`上创建一个`frame`
frm = tk.Frame(window)
frm.pack()

###在刚刚创建的`frame`上创建两个`frame`,我们可以把它理解成一个大容器里套了一个小容器,即`frm`上有两个`frame` ,`frm_l`和`frm_r`

frm_l = tk.Frame(frm)
frm_r = tk.Frame(frm)

###这里是控制小的`frm`部件在大的`frm`的相对位置,此处`frm_l`就是在`frm`的左边,`frm_r`在`frm`的右边
frm_l.pack(side='left')
frm_r.pack(side='right')

###这里的三个label就是在我们创建的frame上定义的label部件,还是以容器理解,就是容器上贴了标签,来指明这个是什么,解释这个容器。
tk.Label(frm_l, text='on the frm_l1').pack()##这个`label`长在`frm_l`上,显示为`on the frm_l1`
tk.Label(frm_l, text='on the frm_l2').pack()##这个`label`长在`frm_l`上,显示为`on the frm_l2`
tk.Label(frm_r, text='on the frm_r1').pack()##这个`label`长在`frm_r`上,显示为`on the frm_r1`

完整代码:

import tkinter as tk

window = tk.Tk()
window.title('my window')
##窗口尺寸
window.geometry('200x200')
###定义一个`label`显示`on the window`
tk.Label(window, text='on the window').pack()

###在`window`上创建一个`frame`
frm = tk.Frame(window,bg='green')
frm.pack()

###在刚刚创建的`frame`上创建两个`frame`,我们可以把它理解成一个大容器里套了一个小容器,即`frm`上有两个`frame` ,`frm_l`和`frm_r`

frm_l = tk.Frame(frm,bg='red')
frm_r = tk.Frame(frm,bg='blue')

###这里是控制小的`frm`部件在大的`frm`的相对位置,此处`frm_l`就是在`frm`的左边,`frm_r`在`frm`的右边
frm_l.pack(side='left')
frm_r.pack(side='right')

###这里的三个label就是在我们创建的frame上定义的label部件,还是以容器理解,就是容器上贴了标签,来指明这个是什么,解释这个容器。
tk.Label(frm_l, text='on the frm_l1',bg='red').pack()##这个`label`长在`frm_l`上,显示为`on the frm_l1`
tk.Label(frm_l, text='on the frm_l2',bg='red').pack()##这个`label`长在`frm_l`上,显示为`on the frm_l2`
tk.Label(frm_r, text='on the frm_r1',bg='blue').pack()##这个`label`长在`frm_r`上,显示为`on the frm_r1`
##显示出来
window.mainloop()

演示:

messagebox 弹窗

其实这里的messagebox就是我们平时看到的弹窗。 我们首先需要定义一个触发功能,来触发这个弹窗 这里我们就放上以前学过的button按钮

tk.Button(window, text='hit me', command=hit_me).pack()

通过触发功能,调用messagebox

def hit_me():
   tk.messagebox.showinfo(title='Hi', message='hahahaha')

这里点击button按钮就会弹出提示对话窗

 下面给出几种形式

tk.messagebox.showinfo(title='',message='')#提示信息对话窗
tk.messagebox.showwarning()#提出警告对话窗
tk.messagebox.showerror()#提出错误对话窗
tk.messagebox.askquestion()#询问选择对话窗

如果给出如下定义就是打印出我们所选项对应的值

def hit_me():
   print(tk.messagebox.askquestion(title='Hi', message='hahahaha'))

 同样创建方法都是一样的形式

 print(tk.messagebox.askquestion())#返回yes和no
    print(tk.messagebox.askokcancel())#返回true和false
    print(tk.messagebox.askyesno())#返回true和false
    print(tk.messagebox.askretrycancel())#返回true和false

完整代码:

import tkinter as tk
import tkinter.messagebox
window = tk.Tk()
window.title('my window')
##窗口尺寸
window.geometry('200x200')
def hit_me():
    #tk.messagebox.showinfo(title='',message='')#提示信息对话窗
    #tk.messagebox.showwarning()#提出警告对话窗
    #tk.messagebox.showerror()#提出错误对话窗
    #tk.messagebox.askquestion(title='Hi', message='hahahaha')#询问选择对话窗
    print(tk.messagebox.askquestion(title='Hi', message='hahahaha'))#打印出我们所选项对应的值
tk.Button(window,text='Hit me',command=hit_me).pack()

##显示出来
window.mainloop()

演示:

pack grid place 放置位置

pack 

首先我们先看看我们常用的pack(), 他会按照上下左右的方式排列.

tk.Label(window, text='1').pack(side='top')#上
tk.Label(window, text='1').pack(side='bottom')#下
tk.Label(window, text='1').pack(side='left')#左
tk.Label(window, text='1').pack(side='right')#右

grid 

接下里我们在看看grid(), grid 是方格, 所以所有的内容会被放在这些规律的方格中.

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

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

 

place 

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

tk.Label(window, text=1).place(x=20, y=10, anchor='nw')

 完整代码(只能用一种方式放置):

import tkinter as tk

window = tk.Tk()
window.title('my window')
##窗口尺寸
window.geometry('200x200')
#pack
tk.Label(window, text='1').pack(side='top')#上
tk.Label(window, text='1').pack(side='bottom')#下
tk.Label(window, text='1').pack(side='left')#左
tk.Label(window, text='1').pack(side='right')#右
#gird
for i in range(4):
    for j in range(3):
        tk.Label(window, text=1).grid(row=i, column=j, padx=10, pady=10)
#place
tk.Label(window, text=1).place(x=20, y=10, anchor='nw')
##显示出来
window.mainloop()

例子 登录窗口1

这一次效果图是这样的:

例子 登录窗口1

都是前面熟悉的参数。为了防止大家忘记,特意加上代码注释。

界面创建 

# welcome image
canvas = tk.Canvas(window, height=200, width=500)#创建画布
image_file = tk.PhotoImage(file='welcome.gif')#加载图片文件
image = canvas.create_image(0,0, anchor='nw', image=image_file)#将图片置于画布上
canvas.pack(side='top')#放置画布(为上端)

这里创建的就是我们效果图中的welcome, 如果你想使用和我一样的 welcome 的图片, 你可以在这里下载。

# user information
tk.Label(window, text='User name: ').place(x=50, y= 150)#创建一个`label`名为`User name: `置于坐标(50,150)
tk.Label(window, text='Password: ').place(x=50, y= 190)

var_usr_name = tk.StringVar()#定义变量
var_usr_name.set('example@python.com')#变量赋值'example@python.com'
entry_usr_name = tk.Entry(window, textvariable=var_usr_name)#创建一个`entry`,显示为变量`var_usr_name`即图中的`example@python.com`
entry_usr_name.place(x=160, y=150)
var_usr_pwd = tk.StringVar()
entry_usr_pwd = tk.Entry(window, textvariable=var_usr_pwd, show='*')#`show`这个参数将输入的密码变为`***`的形式
entry_usr_pwd.place(x=160, y=190)

这里就是创建我们熟悉的登录界面,就是常见的用户名,密码。

# login and sign up button
btn_login = tk.Button(window, text='Login', command=usr_login)#定义一个`button`按钮,名为`Login`,触发命令为`usr_login`
btn_login.place(x=170, y=230)
btn_sign_up = tk.Button(window, text='Sign up', command=usr_sign_up)
btn_sign_up.place(x=270, y=230)

这里定义的就是我们的登录按钮。

触发功能

def usr_login():
    pass
def usr_sign_up():
    pass

本节我们只是把登录的界面做出来,并没有对触发功能详细的去定义。等下节会继续完善这个例子。

例子 登录窗口2

这一次效果图是这样的:

例子 登录窗口2

触发的 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中的数据对比。针对正确的密码和错误的密码分别对待.

#如果用户名和密码与文件中的匹配成功,则会登录成功,并跳出弹窗`how are you?`加上你的用户名。
if usr_name in usrs_info:
    if usr_pwd == usrs_info[usr_name]:
        tk.messagebox.showinfo(title='Welcome', message='How are you? ' + usr_name)
    ##如果用户名匹配成功,而密码输入错误,则会弹出'Error, your password is wrong, try again.'
    else:
        tk.messagebox.showerror(message='Error, your password is wrong, try again.')
else:   # 如果发现用户名不存在
    is_sign_up = tk.messagebox.askyesno('Welcome',
                           'You have not sign up yet. Sign up today?')
    # 提示需不需要注册新用户
    if is_sign_up:
        usr_sign_up()

下面是用户名存在但是一个密码正确, 一个密码错误.

例子 登录窗口2

例子 登录窗口2

下面是用户不存在, 提示需不需要注册一个新的用户.

例子 登录窗口2

因为本节只是定义usr_sign_up并没有实质功能,所以选择之后没有太大变化。 这一部分就是匹配的主要内容,如果匹配成功,就会登录进去,否则就会失败。

本节主要是详细介绍登录功能,下节会继续完善注册命令。 

例子 登录窗口3

这一次效果图是这样的:

例子 登录窗口3

usr_sign_up 界面

window_sign_up = tk.Toplevel(window)
window_sign_up.geometry('350x200')
window_sign_up.title('Sign up window')

这一段首先是创建一个注册的窗口。这里和以往不同的是,多了一个tk.Toplevel我们打个比方,就好像我们前面所学 的frame一样,就是在编辑的功能下还有很多功能一样,这里就是在主体窗口的window上创建一个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=150, 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=150, 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=150, y=90)

# 下面的 sign_to_Mofan_Python 我们再后面接着说
btn_comfirm_sign_up = tk.Button(window_sign_up, text='Sign up', command=sign_to_Mofan_Python)
btn_comfirm_sign_up.place(x=150, y=130)

相信大家对这一段代码已经很熟悉了,因为这是大家前面所学过的知识。其实就是像我们平时所见的注册窗口有一样,在Sign up window窗口 上添加new_name new_pwd, new_pwd_confirm,还有最后一个注册按钮。这里便于大家复习,我们将new_name这段详细介绍一下(如代码注释)。 到这里就完成了我们这个注册的主要界面用户名,密码,确认密码。效果图如下:

例子 登录窗口3

sign_to_Mofan_Python() 功能 

def usr_sign_up():
    def sign_to_Mofan_Python():
        ##以下三行就是获取我们注册时所输入的信息
        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:
            tk.messagebox.showerror('Error', 'Password and confirm password must be the same!')

        ##如果用户名已经在我们的数据文件中,则提示`'Error', 'The user has already signed up!'`
        elif nn in exist_usr_info:
            tk.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)
            tk.messagebox.showinfo('Welcome', 'You have successfully signed up!')
            ##然后销毁窗口。
            window_sign_up.destroy()

这里其实和前面所讲的login功能类似,如代码注释。

注册成功就是我们一开始展示的效果图。

到此,我们的这个程序已经完善。这里给大家奉上我们最后的成果。

完整代码:

import tkinter as tk
import pickle
import tkinter.messagebox
window = tk.Tk()
window.title('Welcome To Myapp!')
##窗口尺寸
window.geometry('450x300')
# welcome image
canvas = tk.Canvas(window, height=200, width=500)#创建画布
image_file = tk.PhotoImage(file='welcome.gif')#加载图片文件
image = canvas.create_image(0,0, anchor='nw', image=image_file)#将图片置于画布上
canvas.pack(side='top')#放置画布(为上端)
# user information
tk.Label(window, text='用户名: ').place(x=50, y= 150)#创建一个`label`名为`User name: `置于坐标(50,150)
tk.Label(window, text='密码: ').place(x=50, y= 190)
#用户名输入框
var_usr_name = tk.StringVar()#定义变量
var_usr_name.set('example@python.com')#变量赋值'example@python.com'
entry_usr_name = tk.Entry(window, textvariable=var_usr_name)#创建一个`entry`,显示为变量`var_usr_name`即图中的`example@python.com`
entry_usr_name.place(x=160, y=150)
#密码输入框
var_usr_pwd = tk.StringVar()
entry_usr_pwd = tk.Entry(window, textvariable=var_usr_pwd, show='*')#`show`这个参数将输入的密码变为`***`的形式
entry_usr_pwd.place(x=160, y=190)
#登录事件
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 EOFError:
 ##这里就是我们在没有读取到`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)
#如果用户名和密码与文件中的匹配成功,则会登录成功,并跳出弹窗`how are you?`加上你的用户名。
    if usr_name in usrs_info:
        if usr_pwd == usrs_info[usr_name]:
            tk.messagebox.showinfo(title='欢迎', message='你好' + usr_name)
    ##如果用户名匹配成功,而密码输入错误,则会弹出'Error, your password is wrong, try again.'
        else:
            tk.messagebox.showerror(message='错误,你的密码有问题,请重新输入')
    else:   # 如果发现用户名不存在
        is_sign_up = tk.messagebox.askyesno('Welcome',
                           '你还没有注册,现在注册?')
    # 提示需不需要注册新用户
    if is_sign_up:
        usr_sign_up()
#注册事件
def usr_sign_up():
    def sign_to_app():
         ##以下三行就是获取我们注册时所输入的信息
        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:
            tk.messagebox.showerror('Error', '两次密码输入不一致哦!')

        ##如果用户名已经在我们的数据文件中,则提示`'Error', 'The user has already signed up!'`
        elif nn in exist_usr_info:
            tk.messagebox.showerror('Error', '这个用户名已经注册了!')

        ##最后如果输入无以上错误,则将注册输入的信息记录到文件当中,并提示注册成功`'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)
            tk.messagebox.showinfo('Welcome', '你成功注册了!')
            ##然后销毁窗口。
            window_sign_up.destroy()

    window_sign_up = tk.Toplevel(window)
    window_sign_up.geometry('350x200')
    window_sign_up.title('用户注册')
    #新用户名
    new_name = tk.StringVar()#将输入的注册名赋值给变量
    new_name.set('example@python.com')#将最初显示定为'example@python.com'
    tk.Label(window_sign_up, text='用户名: ').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=150, y=10)#`entry`放置在坐标(150,10).
    #新密码
    new_pwd = tk.StringVar()
    tk.Label(window_sign_up, text='密码: ').place(x=10, y=50)
    entry_usr_pwd = tk.Entry(window_sign_up, textvariable=new_pwd, show='*')
    entry_usr_pwd.place(x=150, y=50)
    #防止密码填错
    new_pwd_confirm = tk.StringVar()
    tk.Label(window_sign_up, text='重复密码: ').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=150, y=90)
    # 下面的 sign_to_app 
    btn_comfirm_sign_up = tk.Button(window_sign_up, text='注册', command=sign_to_app)
    btn_comfirm_sign_up.place(x=150, y=130)




# 登录和注册按钮
btn_login = tk.Button(window, text='登录', command=usr_login)#定义一个`button`按钮,名为`Login`,触发命令为`usr_login`
btn_login.place(x=170, y=230)
btn_sign_up = tk.Button(window, text='注册', command=usr_sign_up)
btn_sign_up.place(x=270, y=230)

##显示出来
window.mainloop()

演示:


版权声明:本文为muzihuaner原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。