GUI图形用户界面编程

GUI(Grapahics User Inerface)编程类似于“搭积木”,将一个个组件(widget)放到窗口中。

常用的GUI库

  1. Tkinter

tkinter(TK interface) 是Python的标准GUI库,支持跨平台的GUI程序开发,tkinter适合小型的GUI程序编写,也特别适合初学者学习GUI编程。

  1. wxPython

wxPython是比较流行的GUI库,适合大型应用程序开发,功能强于tkinter,整体设计框架类似于MFC

  1. PyQT

Qt是一种开源的GUI库,适合大型GUI程序开发,PyQT是Qt工具包标准的Python实现。我们也可以使用Qt Desginer界面设计器快速开发GUI应用程序

Tkinter模块
官方网址

GUI编程的核心步骤

基于tinter模块创建GUI程序包含如下4个核心步骤:

1.创建应用程序主窗口对象(也称:根窗口)

  1. 通过类Tk的无参构造函数 ```python form tkinter import *

root = Tk()

  1. 案例:第一个GUI程序
  2. ```python
  3. from tkinter import *
  4. from tkinter import messagebox
  5. root = Tk()
  6. btn01 = Button(root)
  7. btn01["text"] ="点击"
  8. btn01.pack()
  9. def dianji(e): #e就是事件对象
  10. messagebox.showinfo("Message","点击成功")
  11. print("点击")
  12. btn01.bind("<Button-1>",dianji)
  13. root.mainloop() #调用组件的mian()方法,进入事件循环

G1IF.gif

2.tkinter主窗口

主窗口位置和大小

通过genmetry('wxh±x±y')进行设置。w为宽度,h为高度。+x表示距屏幕左边的距离;-x表示距屏幕右边的距离;+y表示距离屏幕上边的距离;-y表示据屏幕下边的距离。

from tkinter import *
from tkinter import messagebox


root = Tk()

root.title("我的第一个GUI程序")

root.geometry("500x300-100-200")

btn01  = Button(root)
btn01["text"] ="点击"

btn01.pack()

def dianji(e):      #e就是事件对象
    messagebox.showinfo("Message","点击成功")
    print("点击")

btn01.bind("<Button-1>",dianji)
root.mainloop() #调用组件的mian()方法,进入事件循环

image.png

3.GUI编程整体描述

图形用户界面是由一个个组件组成,有的组件还能在里面再放置其他挂件,我们称之为“容器”。
Tkinter的GUI组件关系图如下:

python[进阶四] - 图3

  • Misc和Wm

Tkiner的GUI组件有两个根类。他们都直接继承了object类:

  • Misc:它是所有组件的根父类
  • Wm:它主要提供了一些与窗口管理器通信的功能函数。
  • Tk

Misc和Wm派生出子类Tk,它代表应用程序的主窗口。一般应用程序都需要直接或间接使用Tk

  • Pack、Place、Grid

Pack、Place、Grid是布局管理器。布局管理器管理组件的:大小、位置。通过布局管理器可以将容器中的组件实现合理的排布。

  • BaseWidget

BaseWidget是所有组件的父类

  • Widget

Widget是所有组件的父类。Widget一共有四个父类:BaseWidget、Pack、Grid、Place。意味着,所有GUI组件同时具备这四个父类的属性和方法。

image.png

Tkinter类 名称 简介
Toplevel 顶层 容器类,可用于为其他组件提供单独的容器;Toplevel类似于窗口
Button 按钮 代表按钮组件
Canvas 画布 提供绘图功能,包括直线、矩形、椭圆、多边形、位图等
Checkbutton 复选框 可供用户选择的复选框
Entry 单行输入框 用户可输入内容
Frame 容器 用于装载其他GUI组件
Label 标签 用于显示不可编辑的文本或图标
LabelFrame 容器 也是容器组件、类似于Frame、但它支持添加标题
Listbox 列表框 列出多个选项,供用户选择
Menu 菜单 菜单组件
Menubutton 菜单按钮 用来包含菜单的按钮(包括下拉式、层叠式等)
OptionMenu 菜单按钮 Menubutton的子类,也代表菜单按钮,可通过按钮打开一个按钮
Message 消息框 类似于标签,但可以显示多行文本;后来当Label也能显示多行文本后之后,该组件基本处于废弃状态
PanedWindow 分区窗口 该容器会被划成多个区域,没添加一个组件占一个区域,用户可通过拖动分割线来改变个区域大小
Radiobutton 单选按钮 可供用户点边的单选钮
Scale 滑动条 拖动滑块可设定起始值和结束值,可显示当前位置的精准值
Spinbox 微调选择器 用户可通过该组件的向上、向下箭头选择不同的值
Scrollbar 滚动条 用于组件(文本域、画布、列表框、文本框)提供滚动功能
Text 多行文本框 显示多行文本

4.GUI应用程序类的经典写法

通过类Application组织整个GUI程序,类Application继承了Frame及通过继承了拥有父类的特性。

通过构造函数__init()__初始化窗口中的对象,通过createWidgets()方法创建窗口中的对象

Frame框架是一个tkinter组件,表示一个矩形区域。Frame一般作为容器使用,可以放置其他组件,从而实现复杂的布局。

"""测试一个经典的GUI编程的写法,使用面向对象的方式"""
from tkinter import *
from tkinter import messagebox

class Application(Frame):
    """一个经典的GUI程序的类的写法"""

    def __init__(self,master=None):
        super().__init__(master)    #super()代表的是父类的定义,而不是父类对象
        #这里调用父类构造器的目的就是为了使用父类的方法,比如下面的pack()
        self.master = master
        self.pack() #调用布局管理器进行布局和管理

        self.createWiget()

    def createWiget(self):
        """创建组件"""
        self.btn01 = Button(self)
        self.btn01["text"] = "点击送花"
        self.btn01.pack()
        self.btn01["command"] = self.songhua

        #创建一个退出按钮
        self.btnQuit =Button(self,text="退出",command=root.destroy)
        self.btnQuit.pack()

    def songhua(self):
        messagebox.showinfo("送花","送你99朵")

if __name__ == '__main__':

    root = Tk()
    """根窗口对象"""
    root.geometry("400x100+200+300") #窗口大小
    root.title("一个经典的GUI程序测试")
    app = Application(master=root)#传参
    root.mainloop()#调用组件的mian()方法,进入事件循环

image.png

label标签

Label(标签)主要用于显示文本信息,也可以显示图像。

Label(标签)有这样的一些常见属:

  1. width,height:

用于指定区域大小,如果显示是文本,则以单个英文字符大小为单位(一般汉字宽度占2个字符的位置,高度和英文字符一样);如果显示的是图像,则以像素为单位。默认值是根据具体的内容调整。

  1. font:

指定字体个字体大小,如:font=font(font_name,size)

  1. image:

显示在Label上的图像,目前tinter只支持gif格式

  1. fg和bg:

fg(foreground):前景色、bg(background):背景色

  1. justify

针对多行文本的对齐,也可设置justify属性,可选值“left”,“center”or“right”

"""测试label写法,使用面向对象的方式"""
from tkinter import *

class Application(Frame):
    """一个经典的GUI程序的类的写法"""

    def __init__(self,master=None):
        super().__init__(master)    #super()代表的是父类的定义,而不是父类对象
        #这里调用父类构造器的目的就是为了使用父类的方法,比如下面的pack()
        self.master = master
        self.pack() #调用布局管理器进行布局和管理
        self.createWiget()

    def createWiget(self):
        """创建组件"""
        self.label01 = Label(self,text="你好",width=10,height=2,bg="black",fg="white")
        self.label01.pack()

        self.label02 = Label(self, text="你好", width=10, height=2, bg="red", fg="white",
                             font=("font",30))
        self.label02.pack()

        #显示图像
        global photo #把photo声明成局部变量。如果是局部变量。
                    # 本方法执行完毕后图像销毁,窗口显示不出图像
        photo =PhotoImage(file="img/11.gif")
        self.label03 = Label(self,image=photo)
        self.label03.pack()

        #多行文本
        self.label04 =Label(self,text="你好\n人生苦短\n我用python",borderwidth=1,relief="solid",
                            justify="right")
        self.label04.pack()


if __name__ == '__main__':

    root = Tk()
    #根窗口对象
    root.geometry("400x300+200+300") #窗口大小
    root.title("一个Label程序测试")
    app = Application(master=root)#传参
    root.mainloop()#调用组件的mian()方法,进入事件循环

image.png

Options选项

我们可以通过三种方式设置Options选项,这在各种GUI组件中中用法都一致。

  1. 创建对象时,使用命名参数(也叫关键字参数)

    fred = Button( self , fg=”red” , bg=”blue”)

  1. 创建对象时,使用字典索引方式

    fred[ “ fg “ ] = “red” fred[ “ bg “ ] =”blue”

  1. 创建对象后,使用config()方法

    fred.config(f g=”red”, bg=”bule” )

如何查看组件的Options选项

  1. 可以通过打印config()方法的返回值,查看Options选项

print(fred.config)

  1. 通过在IDE中,点击组件对象的构造方法,进入方法内观察:

image.png

class Button(Widget):
    """Button widget."""

    def __init__(self, master=None, cnf={}, **kw):
        """Construct a button widget with the parent MASTER.

        STANDARD OPTIONS

            activebackground, activeforeground, anchor,
            background, bitmap, borderwidth, cursor,
            disabledforeground, font, foreground
            highlightbackground, highlightcolor,
            highlightthickness, image, justify,
            padx, pady, relief, repeatdelay,
            repeatinterval, takefocus, text,
            textvariable, underline, wraplength

        WIDGET-SPECIFIC OPTIONS

            command, compound, default, height,
            overrelief, state, width
        """
        Widget.__init__(self, master, 'button', cnf, kw)

上面代码中有:“standard options 标准选项”和“widget-specific options 组件特定选项”。
常见的选项如下

选项名(别名) 含义
activebackground 指定组件处于激活状态时的背景色
activeforeground 指定组件处于激活状态时的前景色
anchor 指定组件内的信息(比如文本或图片)在组件中如何显示(当所在组件比信息大时,可以看出效果)。必须为下面的值之一:n、ne、e、se、sw、w、nw、或center。比如nw(North West)指定将信息显示在组件的左上角
background(bg) 指定组件正常显示时的背景色
bitmap 指定在组件上显示该选项指定的位图,该选项值可以是Tk_GetBitmap接收的任何形式的位图,位图的显示方式受anchor、justify选项的影响。如果同时指定了bitmap和text,那么bitmap和image,那么image覆盖bitmap
borderwidth 指定组件正常显示时的3D边框宽度,该值可以是Tk_GetPixels接收的任何格式
cursor 指定光标在组件上的样式。该值可以是Tk_GetCursors接受的任何格式
command 指定按组件关联的命令方法,该方法通常在鼠标离开组件时被触发调用
disableforeground 指定组件处于禁用状态时的前景色
font 指定组件上显示文本颜色
foreground(fg) 指定组件正常显示时的前景色
highlightbackground 指定组件在高亮状态下的背景色
highlightcolor 指定组件在高亮状态下的前景色
highlightthickness 指定组件在高亮状态下的周围方形区域的宽度,该值可以是Tk_GetPixels接收的任何格式
height 指定组件的高度,以font选项指定的字体的字符高度为单位,至少为1
image 指定组件中显示的图像,如果设置了image选项、它将会覆盖text、bitmap选项
justify 指定组件内部内容的对齐方式,该选项支持left(左对齐)、center(居中对齐)或right(右对齐)三个值
padx 指定组件内部在水平向上两地的空白,该值可以是Tk_GetPixels接收的任何格式
pady 指定组件内部在垂直方向上两地的空白,该值可以是Tk_GetPixels接收的任何格式
relief 指定组件的3D效果,该选项支持的值包括raised、sunken、flat、ridge、solid、groove。该值之处组件内部相对于外部的外观样式,比如raised表示组件内部相对于外部凸起。
selectbackground 指定组件在选中状态下的背景色
selectborderwidth 指定组件在选中状态下的3D边框的宽度,该值可以是Tk_GetPixels接收的任何格式
selectforeground 指定组件在选中状态的前景色
state 指定组件的当前状态。在选项支持normal(正常)、disable(禁用)这两个值
takefocus 指定组件在键盘遍历(Tab或Shift+Tab)时是否接收焦点,该选项设为1表示接收焦点;设置为0表示不接收焦点
text 指定组件上显示的文本,文本显示格式由组件本身、anchor及justify选项决定
textvariable 指定一个变量名,GUI组件负责显示改变量值转换得到的字符串,文本显示格式由组件本身、anchor及justify选项决定
underline 指定为组件文本的第几个字符下划线,该选项相当于组件绑定了快捷键
width 指定组件的宽度、一font选项指定的字体的字符高度为单位,至少为1
wraplength 对于能支持字符换行的组件,该选项指定每行显示的最大字符数,超过该数量的字符将会撞到下行显示
xscollcommand 通常用于将组件的水平滚动改变(包括内容滚动或宽度发生改变)与水平滚动条的set方法关联,从而让组件的水平滚动改变传递到水平滚动条
yscollcommand 通常用于将组件的垂直滚动改变(包括内容滚动或高度发生改变)与垂直滚动条的set方法关联,从而让组件的垂直滚动改变传递到垂直滚动条

Button

Button(按钮)用来执行用户的单击操作。Button可以包含文本,也可包含图像,按钮被单击后会自动调用对应事件绑定的方法。

"""测试Button组件的基本用法"""

from tkinter import *
from tkinter import messagebox

class Application(Frame):

    def __init__(self,master=None):
        super().__init__(master)
        self.master = master
        self.pack()
        self.createWidget()

    def createWidget(self):
        """创建组件"""
        self.btn01 = Button(root,text="登录",command=self.login)
        self.btn01.pack()

        global photo
        photo = PhotoImage(file="img/11.gif")
        self.btn02 = Button(root, image=photo,command=self.login)
        self.btn02.pack()
        #self.btn02.config(state="disable")#设置按钮为禁用

    def login(self):
        messagebox.showinfo("登录系统","登录成功")

if __name__ == '__main__':

        root = Tk()
        """根窗口对象"""
        root.geometry("400x300+200+300")  # 窗口大小
        root.title("登录系统")
        app = Application(master=root)  # 传参
        root.mainloop()  # 调用组件的mian()方法,进入事件循环

GIF.gif

Entry单行文本框

Entry用来接收一行字符串的控件,如果用户输入的文字长度长于Entry控件的宽度时,文字会自动向后滚动。如果想输入多行文本,需要使用Text控件。

from tkinter import *
from tkinter import messagebox

class Application(Frame):

    def __init__(self,master=None):
        super().__init__(master)
        self.master = master
        self.pack()
        self.createWidget()

    def createWidget(self):
        """创建登录界面的组件"""
        self.label01 = Label(self,text="用户名")
        self.label01.pack()

        #StringVar变量绑定到指定的组件
        #StringVar变量的值发生变化,组件内容也发生变化
        #组件的内容发生变化,StringVar变量的值也发生变化
        v1 = StringVar()
        self.entry01 = Entry(self,textvariable=v1)
        self.entry01.pack()
        v1.set("admin")
        print(v1.get());print(self.entry01.get())

        #创建密码框
        self.label02 = Label(self, text="密码")
        self.label02.pack()
        v2 = StringVar()
        self.entry02 = Entry(self, textvariable=v2,show="*")
        self.entry02.pack()



        Button(self,text="登录",command=self.login).pack()


    def login(self):
        username = self.entry01.get()
        pwd = self.entry02.get()

        print("去数据库比对用户名和密码")
        print("用户名"+username)
        print("密码" + pwd)

        if username =="abc" and pwd=="123":
            messagebox.showinfo("登录系统","登录成功!")
        else:
            messagebox.showinfo("登录系统","登录失败,用户名或密码错误")


if __name__ == '__main__':

    root = Tk()
    #根窗口对象
    root.geometry("400x300+200+300") #窗口大小
    app = Application(master=root)#传参
    root.mainloop()#调用组件的mian()方法,进入事件循环

image.png

image.png

Text多行文本

Text(多行文本框)的主要用于显示多行文本,还可以显示网页链接,图片,HTML页面,甚至CSS样式表,添加组件等。因此,也常常当做简单的文本处理器、文本编辑器或者网页浏览器来使用。比如IDLE就是Text组件构成的。

"""测试Text多行文本框组件的基本用法,使用面向对象的方式"""

from tkinter import *
import webbrowser

class Application(Frame):

    def __init__(self,master=None):
        super().__init__(master)
        self.master=master
        self.pack()
        self.createWidget()

    def createWidget(self):
        self.w1 = Text(root,width=40,height=12,bg="gray")
        #宽度为20个字母(10个汉字),高度为一个行高
        self.w1.pack()

        self.w1.insert(1.0,"0123456789\nabcdefg")
        self.w1.insert(2.3,"人生苦短,我用python\n")
        #1.0第一行,第0列
        #2.3第二行,第3列

        Button(self,text="重复插入文本",command=self.insertText).pack(side="left")
        Button(self,text="返回文本",command=self.returnText).pack(side="left")
        Button(self,text="添加图片",command=self.addImage).pack(side="left")
        Button(self,text="添加组件",command=self.addWidget).pack(side="left")
        Button(self,text="通过tag精准控制文本",command=self.testTag).pack(side="left")

    def insertText(self):
        # INSERT索引表示在光标处插入
        self.w1.insert(INSERT,'PuKe')
        # END索引号表示在最后插入
        self.w1.insert(END,'[abc]')
        self.w1.insert(1.8, "PuKe")

    def returnText(self):
        # Indexes(索引是用来指向Text组件中的文本的位置,Text的组件索引也是对应实际字符之间的位置)
        #核心:行号以1开始 列号以0开始
        print(self.w1.get(1.2,1.6))
        print("所有文本内容:\n"+self.w1.get(1.0,END))

    def addImage(self):
        #global photo
        self.photo = PhotoImage(file="img/11.gif")
        self.w1.image_create(END,image=self.photo)

    def addWidget(self):
        b1 = Button(self.w1, text='你好啊')
        #在text创建组件命令
        self.w1.window_create(INSERT,window=b1)


    def testTag(self):
        self.w1.delete(1.0,END)
        self.w1.insert(INSERT,"good good study,day day up\nABC\n真好啊\n百度,搜一下就知道")
        self.w1.tag_add("good",1.0,1.9)
        self.w1.tag_config("good",background="red",foreground="blue")

        self.w1.tag_add("baidu",4.0,4.2)
        self.w1.tag_config("baidu",underline=True)
        self.w1.tag_bind("baidu","<Button-1>",self.webshow)

    def webshow(self,event):
        webbrowser.open("http://www.baidu.com")


if __name__=='__main__':
    root =Tk()
    root.geometry("450x300+200+300")
    app = Application(master=root)
    root.mainloop()

GIF.gif

Rdiobutton单选按钮

Radiobutton控件用于选择同一组单选按钮中的一个。Radiobutton可以显示文本,也可以显图像。

GIF.gif

canvas画布

canvas*(画布)是一个矩形区域,可以放置图形图像,组件等、

"""测试canvas组件的基本用法,使用面向对象的方式"""
import random
from tkinter import *
from tkinter import messagebox

class Application(Frame):

    def __init__(self,master=None):
        super().__init__(master)
        self.pack()
        self.createWiget()

    def createWiget(self):
        self.canvas = Canvas(self,width=300,height=200,bg="green")
        self.canvas.pack()
        #画一条直线
        line = self.canvas.create_line(10,10,30,20,40,50)
        #画一条矩形
        rect =self.canvas.create_rectangle(50,50,100,100)
        #画一个椭圆,坐标两双。为椭圆的边界矩形左上角和底部右下角
        oval =self.canvas.create_oval(50,50,100,100)

        global photo
        photo = PhotoImage(file="img/11.gif")
        self.canvas.create_image(150,170,image=photo)

        Button(self,text="画10个矩形",command=self.draw50Recg).pack(side="left")

    def draw50Recg(self):
        for i in range(0,10):
            x1 = random.randrange(int(self.canvas["width"])/2)
            y1 = random.randrange(int(self.canvas["height"])/2)
            x2 =x1 + random.randrange(int(self.canvas["width"])/2)
            y2 =y1 + random.randrange(int(self.canvas["height"])/2)
            self.canvas.create_rectangle(x1,y1,x2,y2)



if __name__ =="__main__":
    root=Tk()
    root.geometry("400x500+200+300")
    app=Application(master=root)
    root.mainloop()

GIF.gif

布局管理器

一个GUI应用程序必然有大量的组件,这些组件如何排布需要用到tkinter提供的布局管理器,帮助我们组织、管理在父组件中子组件的布局方式。tkinter提供了三种管理器:pack、grid、place。

grid布局管理器

grid表格布局,采用表格结构组织组件。子组件的位置由行和列的单元格来确定,并且可以跨行和跨列,从而实现复杂的布局。

grid()方法提供的选项

选项 说明 取值范围
column 单元格的列号 从0开始的正整数
columnspan 跨列,跨越的列数 正整数
row 单元格的行号 从0开始的正整数
rowspan 跨行,跨越的行数 正整数
ipadx,ipady 设置子元组之间的间隔,x方向或者y方向,默认单位是像素 非负浮点数,默认0.0
sticky 组件紧贴所在单元格的某一角,对应于东南西北以及四个角 “n”“s”“w”“e”“nw”“sw”“se”“ne”“center”(默认)
from tkinter import *
from tkinter import messagebox

class Application(Frame):

    def __init__(self,master=None):
        super().__init__(master)
        self.master=master
        self.pack()
        self.createWiget()

    def createWiget(self):
        """通过grid布局来实现登录页面"""
        self.label01 = Label(self,text="用户名")
        self.label01.grid(row=0, column=0)
        self.entry01 = Entry(self)
        self.entry01.grid(row=0,column=1)
        Label(self,text="用户名为手机号").grid(row=0,column=2)

        Label(self,text="密码").grid(row=1,column=0)
        Entry(self,show="*").grid(row=1,column=1)

        Button(self,text="登录").grid(row=2,column=1,sticky=EW)
        Button(self,text="取消").grid(row=2,column=1,sticky=E)




if __name__ =="__main__":
    root=Tk()
    root.geometry("400x400+300+500")
    app = Application(master=root)
    root.mainloop()

image.png

通过grid布局实现计算机软件界面

"""计算机软件页面的设计"""

from tkinter import *
from tkinter import messagebox

class Application(Frame):

    def __init__(self,master=None):
        super().__init__(master)
        self.master =master
        self.pack()
        self.createWiget()

    def createWiget(self):
        """通过grid布局实现计算机界面"""
        btnText = (("MC","M+","M-","MR"),
                   ("C","±","/","÷"),
                   (7,8,9,"-"),
                   (4,5,6,"+"),
                   (1,2,3,"="),
                   (0,"."))
        Entry(self).grid(row=0,column=0,columnspan=4,pady=10)
        for rindex,r in enumerate(btnText):
            for cindex,c in enumerate(r):
                if c =="=":
                    Button(self, text=c, width=2).grid(row=rindex + 1, column=cindex, rowspan=2, sticky=NSEW)

                elif c==0:
                    Button(self, text=c, width=2).grid(row=rindex + 1, column=cindex, columnspan=2,sticky=NSEW)

                elif c==".":
                    Button(self, text=c, width=2).grid(row=rindex + 1, column=cindex+1, sticky=NSEW)

                else:
                    Button(self, text=c, width=2).grid(row=rindex + 1, column=cindex, sticky=NSEW)




if __name__== "__main__":
    root=Tk()
    root.geometry("200x200+200+300")
    app = Application(master=root)
    root.mainloop()

image.png

pack布局管理器

pack按照组件的创建顺序将子组件添加到父组件中,按照垂直或者水平方向的自然排布。如果不指定任何选项,默认在父组件中自顶向下垂直添加组件。
pack是代码量最少,最简单的一种,可以用于快速生成界面

pack()方法提供选项

名称 描述 取值范围
expand 当值为“yes”时,side选项无效。组件显示在父配件中心位置,若fill选项为“both”,则填充父组件的剩余空间 “yes”,自然数“no”,0(默认值为“no”或0)
fill 填充x(y)方向上的空间,当属性side=“left”或“right”时,填充“Y”方向,当expand选项“yes”,填充父组件的剩余空间 “x”“y”“both”“none”(默认值为none)
ipax,ipay 设置子组件之间的间隔,x方向或者y方法,默认单位是像素 非负浮点数,默认为0.0
padx,pady 与之并列的组件的间隔,x方向或者y方向,默认单位是像素 非负浮点数,默认为0.0
side 定义停靠在父组件的那一边上 “top”“bottom”“left”“right”(默认值为top)
before 将本组件于所选组件对象之前pack,类似于先创建选定 已经pack后的组件对象
after 将本组件于所选组件对象之后pack,类似于先创建选定组件在本组件 已经pack后组件对象
in_ 将本组件作为所选组件对象的子组件,类似于指定本组件的master为选定组件 已经pack后组件对象
anchor 对齐方式,左对齐w、右对齐e,顶对齐n,底对齐s “n”“s”“w”“e”“nw”“sw”“se”“ne”“center(默认)”

pack适用于简单的垂直或水平排布,复杂的可以使用grid或place

"""测试pack布局管理"""

from  tkinter import *

root = Tk()
root.geometry("700x220")
f1 = Frame(root)
#Frame是一个矩形区域,就是用来放置其他子组件
f1 = Frame(root)
f1.pack()
f2 = Frame(root)
f2.pack()

btnText =("流行风","中国风","日本风","重金属","轻音乐")

for txt in btnText:
    Button(f1,text=txt).pack(side="left",padx="10")

for i in range(1,20):
    Label(f2,width=5,height=10,borderwidth=1,relief="solid",bg="black" if i%2==0 else "white").pack(side="left",padx=2)


root.mainloop()

image.png

place布局管理器

place布局管理器可以通过坐标精准控制组键的位置,适用于一些布局更加灵活的场景。

place()方法的选项

选项 说明 取值范围
x,y 组件左上角的绝对左边(相当于窗口) 非负整数
x和y选项用于设置偏移(像素),如果同时设置relx(rely)个x(y),那么place将优先计算relx和rely,然后再实现x和y指定的偏移量
relx
rely
组件左上角的坐标(相当于父容器) relx是相当父组件的位置,0是最左边,0.5是正中间,1是最右边
relx是相对父组件的位置,0是最上边,0.5是正中间,1是最下边
width
height
组件的宽度和高度 非负整数
relwidth
relheight
组件的宽度和高度(相对父容器) 与relx、rely取值类似,但是相对于父类组件的尺寸
anchor 对齐方式,左对齐w、右对齐e,顶对齐n,底对齐s “n”“s”“w”“e”“nw”“sw”“se”“ne”“center(默认)”
from tkinter import *
root = Tk()
root.geometry("500x300")
root.title("布局管理器place")
root["bg"] = "white"

f1 = Frame(root,width=200,height=200,bg="pink")
f1.place(x=30,y=30)

Button(root,text="你好").place(relx=0.2,x=100,y=20,relwidth=0.2,relheight=0.5)
Button(f1,text="我很好").place(relx=0.6,rely=0.7)
Button(f1,text="我不好").place(relx=0.5,rely=0.2)
root.mainloop()

image.png

"""扑克牌游戏界面的设计"""

from tkinter import *

class Application(Frame):

    def __init__(self,master=None):
        super().__init__(master)
        self.pack()
        self.createWiget()

    def createWiget(self):
        """通过place布局管理器实现扑克牌位置控制"""
        #self.photo = PhotoImage(file="pk/1.gif")
        #self.puke1 = Label(self.master,image=self.photo)
        #self.puke1.place(x=10,y=50)
        self.photos=[PhotoImage(file="pk/"+str(i+1)+".gif") for i in range(10)]
        self.pukes=[Label(self.master,image=self.photos[i]) for i in range(10)]

        for i in range(10):
            self.pukes[i].place(x=10+i*60,y=50)

            #为所有的label增加时间处理
            self.pukes[0].bind_class("Label","<Button-1>",self.chupai)

    def chupai(self,event):
        print(event.widget.winfo_geometry())
        print(event.widget.winfo_y)

        if event.widget.winfo_y()==50:
            event.widget.place(y=30)
        else:
            event.widget.place(y=50)


if __name__ =='__main__':
    root =  Tk()
    root.geometry("1000x500+200+300")
    app = Application(master=root)
    root.mainloop()

GIF.gif

事件处理

一个GUI应用整个生命周期都处在一个消息循环中(event loop)中,它等待事件的发生,并作出相应的处理。

Tkinter 提供了用以处理相关事件的机制,处理函数可被绑定给各个控件的各种事件

widget.bind(event,handler)

鼠标和键盘事件

代码 说明


<1>
1表示鼠标左键按下, 2表示中键,3表示右键
鼠标左键释放
按住鼠标左键移动
鼠标指针进入某一组件区域
鼠标指针离开某一组件区域
滑动滚轮
按下a键,a可用其他键替代
释放a键
按下A键(大写的A)
同时按下alt个a,alt可用ctrl和shift替代
快速按两下a
ctrl和v键同时按下,v可以换成其他键位

event对象常用属性

名称 说明
char 按键字符,仅对键盘事件有效
keycode 按键编码,仅对键盘事件有效
keysym 按键名称,仅对键盘事件有效
比如:按下空格键:键的char:、键的keycode32、键的keysym:space
比如:按下a键:键的char:a、键的keycode:65、键的keysym:a
num 鼠标按键,仅对鼠标事件有效
type 所触发的事件类型
widget 引起事件的组件
width,height 组件改变后的大小,仅Configure有效
x,y 鼠标当前位置,相对于父容器
x_root,y_root 鼠标当前位置,相对于整个屏幕
"""测试键盘和鼠标事件"""

from tkinter import *

root = Tk()
root.geometry("530x300")

c1 = Canvas(root, width=200,height=200,bg="green")
c1.pack()

def mouseTest(event):
    print("鼠标左键单击位置(相当于父容器):{0},{1}".format(event.x,event.y))
    print("鼠标左键单击位置(相当于屏幕):{0},{1}".format(event.x_root,event.y_root))
    print("事件绑定的组件:{0}".format(event.widget))

def testDrag(event):
    c1.create_oval(event.x,event.y,event.x+1,event.y+1)

def keyboardTest(event):
    print("键的keycode:{0},键的char{1},键的keysym:{2}".format(event.keycode,event.char,event.keysym))

def press_a_test(event):
    print("press a")

def release_a_test(event):
    print("release a")

c1.bind("<Button-1>",mouseTest)

c1.bind("<B1-Motion>",testDrag)

root.bind("<KeyPress>",keyboardTest)
root.bind("<KeyPress-a>",press_a_test)
root.bind("<KeyRelease-a>",release_a_test)

root.mainloop()

GIF.gif

lambda表达式

lambda表达式定义的是一个匿名函数,只适合简答输入参数,简单计算返回结果,不适合复杂情况。

lambda定义的匿名函数也有输入、输出只是没有名字。语法格式如下:

lambda 参数值列表:表达式

参数值列表即为输入
表达式计算的结构为输出

add3args=lambda x,y,z:x+y+z
#print(add3args(10,20,30))

上面的lambda表达示相当于如下函数的定义;

def add3args(x,y,z):
    return x+y+z

lambda表达式的参数值列表可以如下内容:

lambda格式 说明
lambda x,y:x*y 函数输入的是x和y,输出的是它们的积
lambda:None 函数没有输入参数,输出的是None
lambda:aaa(3,4) 函数没有输入参数,输出的是aaa(3,4)的结果
lambda *args:sum(args) 输入是任意个数的参数,输出是它们的和
lambda **kwargs:1 输入的是任意键值对参数,输出是1

注意lambda只是一个匿名函数(没有的名字的函数),功能不强,不要过多度使用

GIF.gif

多种时间绑定方法

  • 组件对象的绑定

    1. 通过command属性绑定(适合简单不需要获取event对象)

Button(root,text=""登录)command=login())

  1. 通过bind()方法绑定(适合需要获取event对象)

c1=Canvas();c1.band("<Button>",drawLine)

  • 组件类的绑定

调用对象的bind_class函数,将该组件类所有的组件绑定事件:
w.band_class("Widget","event",eventhanler)

GIF.gif

optionMenu选择项

OptionMenu(选择项)用来做多选一,选中的项在顶部显示。

"""optionmenu的使用测试"""

from tkinter import *

root=Tk()
root.geometry("200x100")
v=StringVar(root)
v.set("你好啊")
om = OptionMenu(root,v,"abc","puke","你好啊")

om["width"]=10
om.pack()

def test1():
    print("ABC",v.get())
#v.set(abc)     #直接修改了optionmenu中选中的值

Button(root,text="确定",command=test1).pack()

root.mainloop()

GIF.gif

Scale移动滑块

Scale(移动滑块)用于指定的数值区间,通过滑块的移动来选择值

"""scale滑块的使用测试"""

from tkinter import *

root=Tk()
root.geometry("400x150")



def test1(value):
    print("滑块的值",value)
    newFont =("宋体",value)
    a.config(font=newFont)

s1 = Scale(root,from_=10,to=50,length=200,tickinterval=5,orient=HORIZONTAL,command=test1)
s1.pack()

a=Label(root,text="你好啊",width=10,height=1,bg="black",fg="white")
a.pack()



root.mainloop()

GIF.gif

颜色选择框

颜色选择框可以帮助我们设置背景色、前景色、画笔颜色、字体颜色等等。

"""askcolor颜色选择框的测试,改变背景色"""

from tkinter import *
from tkinter.colorchooser import *

root=Tk()
root.geometry("400x150")



def test1():
    s1 = askcolor(color="red",title="选择背景颜色")
    print(s1)
    #s1的值是:(0,0,0.0,255.99609375),‘#000ff’
    root.config(bg=s1[1])

Button(root,text="选择背景色",command=test1).pack()

root.mainloop()

image.png

文件对话框

文件对话框帮助我们实现可视化的操作目、操作文件、最后,将文件、目录的信息传入到程序中。文件对话框包含如下一些常用函数:

函数名 对话框 说明
askopenfilename(**options) 文件对话框 返回打开的文件名
askopenfilenames(**options) 返回打开的多个文件名列表
askopenfile(**options) 返回打开文件对象
askopenfiles(**options) 返回打开文件对象的列表
askdirectory(**options) 目录对话框 返回目录名
asksavefile(**options) 保存对话框 返回保存的文件对象
asksaveasfilename(**options) 返回保存的文件名

命名参数options的常见值如下:

参数名 说明
defaultextension 默认后缀:.xxx
用户没有输入则自动添加
filetype[(label,pattern)1,(labe2,pattern2)] 文件显示过滤器
initaldir 初始目录
parent 父窗口,默认根窗口
title 窗口标题
"""文件对话框获取文件"""

from tkinter import *
from tkinter.filedialog import *

root=Tk()
root.geometry=("400*100")

def test1():
    f = askopenfilename(title="上传文件",initialdir="f:",filetypes=[("视频文件","mp4")])

    #print(f)

    show["text"]=f

Button(root,text="选择编辑的视频文件",command=test1).pack()

show = Label(root,width=40,height=3,bg="green")
show.pack()

root.mainloop()

GIF.gif

#coding=utf-8
from tkinter import *
from tkinter.filedialog import *

root=Tk()
root.geometry("400x100")

def test():
   with askopenfile(title="上传文件",initialdir="d:",filetypes=[("文本文件",".txt")]) as f:

       show["text"]=f.read()

Button(root,text="选择读取的文本文件",command=test).pack()

show = Label(root,width=40,height=3,bg="green")
show.pack()

root.mainloop()

image.png

简单输入对话框

simpledialog(简单对话框)包含如下常用函数:

函数名 说明
askfloat(title,prompt,**kw) 输入并返回浮点数
askinteger(title,prompt,**kw) 输入并返回整型
askstring 输入并返回字符串

参数中,title表示窗口标题;prompt是提示信息;命名参数kw为各种选项;initialvalue(初始值)、minvalue(最小值)、maxvalue(最大值)

"""简单的对话框"""
from tkinter import *
from tkinter.simpledialog import *

root=Tk()
root.geometry("400x100")

def test1():
    a = askinteger(title="输入年龄",prompt="请输入年龄",initialvalue=18,minvalue=1,maxvalue=150)
    #askstring、askfloat框使用方式一样
    show["text"]=a

Button(root,text="多少啊",command=test1).pack()

show = Label(root,width=40,height=3,bg="green")
show.pack()

root.mainloop()

GIF.gif

通用消息框

message(通用消息框)用于个用户简单的交互,用户点击确定、取消。

函数名 说明 示例
askokcancel(title,message,**options) ok/cancel对话框 image.png
askquestion(title,message,**options) yes/no问题对话框 image.png
askretrycancel(title,message,**options) retry/cancel问题对话框 image.png
showerror(title,message,**options) 错误消息对话框 image.png
showinfo(title,message,**options) 消息框 image.png
showwarning(title,message,**options) 警告消息框 image.png
#coding=utf-8
from tkinter import *
from tkinter.simpledialog import *
from tkinter.messagebox import *

root=Tk()
root.geometry("400x100")

a1=askokcancel(title="哈喽",message="你好")
print(a1)

root.mainloop()

菜单

GUI编程通常都有菜单,方便用户的交互,一般分为两种:

  1. 主菜单

主菜单通常位于GU程序上方
image.png

  1. 上下文菜单

快捷键菜单(上下文菜单)是通过鼠标右键单击组件而弹出的菜单,一般是和这个组件的相关的操作,比如:剪切、复制、粘贴属性等。
步骤如下:

  1. 创建菜单

menuber = tk.Menu(root)
menubar.add_command(label=""字体)

  1. 绑定鼠标右键单击事件

def test(event):
menubar.post(event.x_root,event.y_root)#在鼠标右键
单击坐标出显示菜单
root.bind("<Button-3>",test)