【tkinter】GUI设计



2018年01月28日    Author:Guofei

文章归类: 0x70_可视化    文章编号: 764

版权声明:本文作者是郭飞。转载随意,但需要标明原文链接,并通知本人
原文链接:https://www.guofei.site/2018/01/28/tkinter.html


tkinter的特点

  • 简单,相比其它GUI设计包,只有基本功能
  • 内置于Python,跨平台

一般的程序架构

tk=tkinter.Tk()
tk.wm_title('中文标题')
label1=tkinter.Label(tk,text='Label')

label1['width']=20
label1['height']=4
label1['background']='red'

label1.pack()
tk.mainloop()

1. Tk()

创建一个新窗口对象

tk = tkinter.Tk()
tk.title("This is a title")  # 窗口的标题
tk.geometry("400x200")  # 窗口的默认大小,x是字母
tk.mainloop()  # 时间循环

2. 控件属性

如示例程序,可以在生成控件时设定控件属性,也可以用类似dict的方法修改控件属性

通用的控件属性

  • Dimensions:尺寸
  • Colors:颜色
  • Fonts:字体
  • Anchor:锚(文本相对应位置参考点)
    • nw, n, ne, w, center, e, sw, s, se
  • Relief styles:浮雕式
  • Bitmaps:显示位图
  • Cursors:光标的外形

3. 界面布局

三种界面布局方式,pack, grid, place

3.1 pack()

tkinter.Button(tk, text="按钮上的文本", command=process_button1).\
    pack(side="left")

默认从上往下排
有以下参数:(用这些参数做布局往往很复杂,建议不用)

  • side:指定停靠在哪个方向,可以是’left’,’top’,’right’,’bottom’
  • fill:’x’,’y’,’both’,’none’,表示填充方法:水平填充,竖直填充,双向填充,不填充
  • expand:YES,NO
  • anchor:(见于通用属性)
  • ipadx:内边距的横方向
  • ipady:内边距的竖直方向
  • padx:外边距的横方向
  • pady:外边距的竖直方向

3.2 grid()

可以把界面设置成数行数列,好处是无论如何拖动窗口,相对位置都不会变化

  • row,column 从0开始的数,行数和列数
  • rowspan, columnspan 从1开始的数,表表示跨越的行数或列数,默认是1
  • stiky: 空间的对齐方式,’n’,’e’,’w’,’s’
  • ipadx, ipady, padx, pady, x, y方向内外边距
import tkinter
tk=tkinter.Tk()
tkinter.Label(tk,text='姓名').grid(row=0,column=0,sticky='e')
tkinter.Entry(tk).grid(row=0,column=1,sticky='e')

tkinter.Label(tk,text='密码').grid(row=1,column=0,sticky='e')
tkinter.Entry(tk).grid(row=1,column=1,columnspan=1,sticky='w')

tkinter.Button(tk,text='登录').grid(row=2,column=1)
tkinter.Button(tk,text='清空').grid(row=0,column=2,rowspan=2,columnspan=1,)#,columnspan=2)

tk.mainloop()

tkinter1.jpg

3.3 place()

不是很推荐

4. 事件绑定

bind用于绑定事件,通用写法是:

窗体对象.bind(事件类型, 回调函数)

事件类型有以下几种:

  • '<Button-1>','<Button-2>','<Button-3>'表示鼠标左中右键
  • '<KeyPress-A>'表示按下A键,A可以换成其它字母
  • '<Control-V>'表示按下ctrl+V,V可以换成其它字母
  • '<F1>'表示按下F1键

回调函数有一个输入,<ButtonPress event state=Mod1 num=1 x=111 y=21>

unbind(事件类型),解除绑定
bind_all()

5. 菜单

add_command

添加菜单项

import tkinter
tk=tkinter.Tk()
menubar=tkinter.Menu(tk)
tk['menu']=menubar
for i in ['文件','编辑','视图','关于']:
    menubar.add_command(label=i)

tk.mainloop()

tkinter2.jpg

add_cascade级联

dict_mul={'文件':['新建','打开','保存','另存为'],
          '编辑':['复制','黏贴','剪切'],
          '视图':['默认视图','新式视图'],
          '关于':['版权信息','其它说明']}

import tkinter
tk=tkinter.Tk()
menubar=tkinter.Menu(tk) # 总menu归属于tk
tk['menu']=menubar
for i in dict_mul:
    temp=tkinter.Menu(menubar) # 子menu归属于menubar
    menubar.add_cascade(label=i,menu=temp)
    for j in dict_mul[i]:
        temp.add_command(label=j)
tk.mainloop()

add_separator

插入一个横杠,与正常add_command一样,只是无需参数

15个常见控件

import tkinter

tk = tkinter.Tk()
tk.geometry("400x200")

# 这里填入控件

tk.mainloop()

通用属性

  • bg/background:背景色,英文、RGB值
  • fg/foreground: 前景色

Button()


tkinter.Button(tk,
               text="按钮上的文本",
                command=process_button1  # 按下按钮后调用的函数
               , bg="#070", fg="#707"  # 背景颜色,字体颜色
               ).grid()
  • process_button1 是一个函数
  • bitmap, compound, width, height, anchor, fg, bg, relief

额外

anchor:按钮上内容的位置[取值:n, ne, e, se, s, sw, w, nw, or center,其中n e s w是东南西北的缩写]
cursor:当鼠标移动到按钮上时所显示的光标【arrow:箭头,cross:十字,dot: 点,hand1:手 …….】
font:字体,使用元组来指定一个字体,这个元组包含了一个字体类型名字,一个以磅为单位的高度,代表一个或多个样式的字符串,比如("Times", 10, "bold")
background[可缩写为bg]:背景色,取值可未英文颜色字符串,或者RGB值
foreground[可缩写为fg]:前景色,取值可未英文颜色字符串,或者RGB值
borderwidth[可缩写为bd]::边框大小
activebackground:按钮处于活动状态时使用的背景颜色。
activeforeground:按钮处于活动状态时使用的前景颜色。
disabledforeground:禁用按钮时使用的颜色。
highlightbackground:当按钮没有焦点时用于高亮边框的颜色
relief:边框的装饰
列表里面是relief的可选值:["flat", "raised", "sunken", "solid", "ridge", "groove"]
flat是指按钮边框是平坦的,raise是指按钮边框是凸起的,sunken是指按钮边框是凹入的,solid是指按钮边框是粗边框…
按钮relief的效果:image
padx和pady:指定文本或图象与按钮边框的间距,x,y为x轴,y轴方向
height,widht:按钮的尺寸,height为高度,width为宽度,如果不设置则默认为包括文本内容
state:按钮的状态,可取值:NORMAL, ACTIVE 或 DISABLED。默认值为NORMAL。
justify:对齐方式

Canvas() 画布

可以在画布上插入文字、图形、图片、动画等

import tkinter

tk = tkinter.Tk()
tk.geometry("400x200")

canvas = tkinter.Canvas(tk, width=200, height=200)
canvas.grid()
canvas.create_text(180, 20, text="文字", fill="blue", font=("time", 16))
canvas.create_line((0, 0), (200, 200), width=8)  # 起点坐标和终点坐标
canvas.create_polygon(10, 10, 100, 10, 100, 110, fill="", outline="black")
# 每两个数字构成一个点的坐标,然后依次画过去

# 下面是插入图
myImage = tkinter.PhotoImage(file="CSLO_logo.png")
canvas.create_image(10, 70, anchor=tkinter.NW, image=myImage)
canvas.pack()

# 下面是做动画
mytriangle = canvas.create_polygon(10, 10, 10, 60, 50, 35)
canvas.move(mytriangle, 5, 0)
canvas.itemconfig(mytriangle, fill='blue')
tk.mainloop()

Checkbutton:多选框

Entry():输入框

没有text这一属性

Label()

label = tkinter.Label(text='用户名:',  # 文字
                      bitmap="error",  # 图形
                      compound="center",  # 图形在文字的那个位置,left, right, top, bottom, center
                      )
  • 可以不要 bitmap,也可以不要 text,但如果两个都有,必须有compound
  • bitmap可接收的属性(表示图形):
    • error
    • hourglass
    • info
    • questhead
    • question
    • warning
    • gray12
    • gray25
    • gray50
    • gray75
  • bg,fg表示背景色和字体色
  • width, height 表示宽度和高度

Listbox:列表框

当内容超过可视化区域时使用,如列表框。

Message

Radiobutton:单选框

Scale:范围控件

显示一个数值刻度,为输出限定范围的数字区间

Scrollbar

滚动条控件,当内容超过可视化区域时使用,如列表框。

Text:显示多行文本

Frame:框架

import tkinter

tk = tkinter.Tk()
tk.geometry("400x200")

frame = tkinter.Frame(tk, height=200, width=400, bg="black")
tkinter.Label(frame, text="label").grid()  # 把frame当成个"子区域"使用
frame.grid()

tk.mainloop()

Toplevel:对话框

弹出一个对话框,用法和 Frame 类似

import tkinter

tk = tkinter.Tk()
tk.geometry("400x200")

top_level = tkinter.Toplevel(tk)

top_level.title("Top窗口")
top_level.geometry("100x100")
tkinter.Label(top_level, text="用户名:").pack()

tk.mainloop()

Spinbox:输入控件

与Entry类似,但是可以指定输入范围值

PanedWindow

PanedWindow是一个窗口布局管理的插件,可以包含一个或者多个子控件。

LabelFrame:labelframe

一个简单的容器控件。常用于复杂的窗口布局

tkMessageBox:用于显示你应用程序的消息框。

额外

“打开文件” 的对话框

tkinter.filedialog.asksaveasfilename():选择以什么文件名保存,返回文件名
tkinter.filedialog.asksaveasfile():选择以什么文件保存,创建文件并返回文件流对象
tkinter.filedialog.askopenfilename():选择打开什么文件,返回文件名
tkinter.filedialog.askopenfile():选择打开什么文件,返回IO流对象
tkinter.filedialog.askdirectory():选择目录,返回目录名
tkinter.filedialog.askopenfilenames():选择打开多个文件,以元组形式返回多个文件名
tkinter.filedialog.askopenfiles():选择打开多个文件,以列表形式返回多个IO流对象

实际案例

案例:改控件属性

import tkinter

tk = tkinter.Tk()
tk.geometry("400x200")


def process_button1():
    button["text"] = "123"  # 这样改控件的属性
    button["fg"] = "blue"


button = tkinter.Button(text="button", bg="blue", command=process_button1)
button.grid()

tk.mainloop()

案例1:几张图以及用法

import tkinter
class CanvasDemo:
    def __init__(self):
        window = tkinter.Tk()
        window.title("CanvasDemo")

        self.canvas = tkinter.Canvas(window, width = 200, height = 100, bg = "White")
        self.canvas.pack()

        frame = tkinter.Frame(window)
        frame.pack()

        btRectangle = tkinter.Button(frame, text = "长方形", command = self.displayRect)
        btOval = tkinter.Button(frame, text="椭 圆", command=self.displayOval)
        btArc = tkinter.Button(frame, text = "圆 弧", command = self.displayArc)
        btPolygon = tkinter.Button(frame, text="多边形", command=self.displayPolygon)
        btLine = tkinter.Button(frame, text=" 线 ", command=self.displayLine)
        btString = tkinter.Button(frame, text="文 字", command=self.displayString)
        btClear = tkinter.Button(frame, text="清 空", command=self.clearCanvas)

        btRectangle.grid(row = 1, column = 1)
        btOval.grid(row=1, column=2)
        btArc.grid(row=1, column=3)
        btPolygon.grid(row=1, column=4)
        btLine.grid(row=1, column=5)
        btString.grid(row=1, column=6)
        btClear.grid(row=1, column=7)

        window.mainloop()

    def displayRect(self):
        self.canvas.create_rectangle(10, 10, 190, 90, tags = "rect")
    def displayOval(self):
        self.canvas.create_oval(10, 10, 190, 90, tags = "oval", fill = "red")
    def displayArc(self):
        self.canvas.create_arc(10, 10, 190, 90, start = 0, extent = 90, width = 8, fill = "red", tags = "arc")
    def displayPolygon(self):
        self.canvas.create_polygon(10, 10, 190, 90, 30, 50, tags = "polygon")
    def displayLine(self):
        self.canvas.create_line(10, 10, 190, 90, fill = 'red', tags = "line")
        self.canvas.create_line(10, 90, 190, 10, width = 9, arrow = "last", activefill = "blue", tags = "line")
    def displayString(self):
        self.canvas.create_text(60, 40, text = "Hi,i am a string", font = "Tine 10 bold underline", tags = "string")
    def clearCanvas(self):
        self.canvas.delete("rect", "oval", "arc", "polygon", "line", "string")

CanvasDemo()

案例2:Menubar

import tkinter
class MenuDemo:
    def __init__(self):
        window = tkinter.Tk()
        window.title("Menu demo")

        menubar = tkinter.Menu(window,bg="red")
        window.config(menu = menubar)

        #创建下拉菜单,并添加到菜单条
        operationMenu = tkinter.Menu(menubar, tearoff = 0)
        menubar.add_cascade(label = "操作", menu = operationMenu)
        operationMenu.add_command(label = "加", command = self.add)
        operationMenu.add_command(label="减", command=self.subtract)
        operationMenu.add_separator()
        operationMenu.add_command(label = "乘", command = self.multiply)
        operationMenu.add_command(label="除", command=self.divide)

        exitMenu = tkinter.Menu(menubar, tearoff = 0)
        menubar.add_cascade(label = "退出", menu = exitMenu)
        exitMenu.add_command(label = "退出", command = window.quit)

        tkinter.mainloop()

    def add(self):
        print("相加")
    def subtract(self):
        print("相减")
    def multiply(self):
        print("相乘")
    def divide(self):
        print("相除")

MenuDemo()

案例3:鼠标事件

import tkinter
class MenuDemo:

    def __init__(self):
        root = tkinter.Tk()

        # create a popup menu
        self.menu = tkinter.Menu(root, tearoff=0)
        self.menu.add_command(label="Undo", command=self.hello)
        self.menu.add_command(label="Redo", command=self.hello)

        # create a canvas
        self.frame = tkinter.Frame(root, width=512, height=512)
        self.frame.pack()

        # attach popup to canvas
        self.frame.bind("<Button-1>", self.popup)
        root.mainloop()

    def popup(self, event):
        self.menu.post(event.x_root, event.y_root)

    def hello(self):
        print("hello!")
MenuDemo()

详解:

widget.bind_all(event, handler)
  • 其中event是一个字符串,表示所触发的事件
  • handler是一个函数,触发事件后调用这个函数

  • event的值(字符串)与对应的描述
    • 当拖拽小部件的时候
    • Button-1、Button-2、Button-3表示左键、中间键、右键点击
    • 当释放鼠标的时候
    • 当双击鼠标的时候
    • 当鼠标光圈进入小部件的时候
    • 当敲击一个键时候
    • 当鼠标光圈离开小部件的时候
    • 当敲击“Enter”键时候,可以将键盘任意一个键和一个事件绑定
    • <Shift+A> 当敲击Shif+A的时候,可以和Alt、Control等组和
    • 点击鼠标3次的时候
  • handler函数的参数对应的属性
    • char 从键盘输入的字符
    • keycode 从键盘输入的键代码
    • keysym 从键盘输入的键符号,”Up”,”Down”,”Left”,”Right”
    • num 鼠标键的数字(1、2、3)
    • widget 出发这个事件的小部件的对象
    • x和y 当前鼠标在小部件的坐标(像素)
    • x_root和y_root 当前鼠标相对于屏幕左上角的坐标(像素)

move

cvs.move(i,dx,dy)
  • canvas上的第i个对象移动dx, dy

tkinter

from tkinter import *

import tkinter.simpledialog as dl
import tkinter.messagebox as mb

#tkinter GUI Input Output Example
#设置GUI
root = Tk()
w = Label(root, text = "Label Title")
w.pack()

#欢迎消息
mb.showinfo("Welcome", "Welcome Message")
guess = dl.askinteger("Number", "Enter a number")

output = 'This is output message'
mb.showinfo("Output: ", output)

参考资料

辛星tkinter教程第二版

https://www.cnblogs.com/progor/p/8505097.html


您的支持将鼓励我继续创作!