Python记8(tkinter

2023-11-15

目录

1、参考:

2、窗口:

2.1、创建窗口 Tk()、长宽geometry()、屏幕宽高、拉伸窗口resizable()、窗口名title()、循环mainloop()、获取窗口大小:

from tkinter import *

root = Tk()                     # Tk():实例化tk类,需配合后面root.mainloop()才能循环显示弹框

width, height = root.winfo_screenwidth(), root.winfo_screenheight() # 获取屏幕宽度和高度:1280, 720

# .geometry():宽300,长60,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.geometry('300x60+500+300')

root.resizable(False, False)    # 不准拉伸(宽,高)
root.title('这是title')          # .title():设置弹框名称
root.mainloop()                 # mainloop()    :循环弹窗

运行得到:
在这里插入图片描述

  • 获取窗口大小:
from tkinter import *

root = Tk(); root.geometry('300x60+500+300'); root.title('这是title')


print("循环前窗口宽{}\t高{}".format(root.winfo_width(), root.winfo_height()))  # 循环前窗口宽1	高1

def Btn1_fun():
    print("窗口宽{}\t高{}".format(root.winfo_width(), root.winfo_height()))     # 窗口宽300	高60

Button(root, text="按钮1", command=Btn1_fun).pack()       # 点击按钮就执行 Btn1_fun()


root.mainloop()                 # mainloop()    :循环弹窗

# 输出:
循环前窗口宽11
窗口宽30060

关于侦听窗口大小变化,参见后面 事件处理相关内容

2.2、窗口最大化/最小化/正常显示 state()、iconify()、attributes

from tkinter import * 
from tkinter.filedialog import askopenfilename
import time

root = Tk();root.geometry('400x150+500+300');root.title('这是title')

root.state('icon')                      # icon:窗口最小化显示,normal:正常显示,zoomed:最大化

print(root.state())                     # state()没有参数可以返回窗口状态,打印:icon

# 另外最小化可以使用root.iconify() 

# 可以使用attributes属性最大化窗口显示,但是会连窗口标题和电脑任务栏都覆盖掉:
root.attributes("-fullscreen", True)
print(root.state())                     # 打印:zoomed

# 循环弹窗
root.mainloop()

2.3、隐藏、显示窗口

(隐藏之后不知道在哪里找回,以后学到再更新)
root.withdraw()可将根窗体隐藏,其作用是将窗体移动到另一个地方但并不销毁它。
root.deiconify()还原窗口

2.4、关闭窗口

在这里插入图片描述

from tkinter import *
from tkinter.messagebox import *

root = Tk();root.geometry('400x150+500+300');root.title('这是title')

def fun():
    if askokcancel("退出", "确认退出程序吗?"):
        root.destroy()
        
root.protocol("WM_DELETE_WINDOW", fun)

root.mainloop()

2.5、其他设置

函数名 解析
root.iconbitmap(“图标路径”) 设置窗口图标
root.update() 刷新窗口
root.after(second,command) 自动触发事件,表示多少秒以后自动执行command
root.maxsize() 设置窗体大小最大值(不带参数时获取最大值)
root.minsize() 设置窗体大小最小值(不带参数时获取最小值)
root.attributes(“-toolwindow”, True) 设置为工具窗口(没有最大最小按钮)
root.attributes(“-topmost”, True) 使窗口保持处于顶层
root.attributes(’-transparentcolor’,‘blue’) 设置透明色,blue可替换其他颜色
root.attributes(’-alpha’,0.5) 设置窗口透明度,0~1之间
root[‘background’]=‘blue’ 设置窗口背景色,blue可替换其他颜色
root.overrideredirect(True) 隐藏窗口边框和标题栏(缺点:脱离windows窗口管理,窗口也不会出现在任务栏,且无法设置最大化、最小化,否则会报错)
root.resizable(True,True) 设置窗口x,y方向的可变性(也可设0或1等)
root.winfo_screenwidth()
root.winfo_screenheight()
获取屏幕分辨率(屏幕的高和宽)

3、Label标签:

显示文本/图像

3.1、3种设置属性的方式:

本质上都是操作键值对

3.1.1、创建时初始化:fred = Button(self, fg=“red”, bg=“blue”)

class Label(Widget):
    """Label widget which can display text and bitmaps."""

    def __init__(self, master=None, cnf={}, **kw):
        """Construct a label 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, takefocus, text,
            textvariable, underline, wraplength

        WIDGET-SPECIFIC OPTIONS

            height, state, width

        """
        Widget.__init__(self, master, 'label', cnf, kw)
  • 看初始化函数参数列表,传递master、字典对象cnf、关键字参数(也就是**kw)
  • 下文示例代码:Label(root,text=“这是Label的文本” , font=(‘黑体’,15))
    root就是self,“text=“这是Label的文本” , font=(‘黑体’,15)”都被**kw接收为字典的键值对
  • 改为:Label(root, dict(text=“这是Label的文本” , font=(‘黑体’,15)))
    root是self,dict(text=“这是Label的文本” , font=(‘黑体’,15))被cnf接收
  • 调用父类 Widget的初始化函数:
Widget.__init__(self, master, 'label', cnf, kw)
  • 然后,Widget类继承BaseWidget类(这里没看得很明白)
class Widget(BaseWidget, Pack, Place, Grid):
    """Internal class.

    Base class for a widget which can be positioned with the geometry managers
    Pack, Place or Grid."""
    pass
  • BaseWidget类
class BaseWidget(Misc):
    """Internal class."""

	def _setup(self, master, cnf):
		这里省略...
		
	def __init__(self, master, widgetName, cnf={}, kw={}, extra=()):
        """Construct a widget with the parent widget MASTER, a name WIDGETNAME
        and appropriate options."""
        if kw:		# 逻辑:如果kw存在,就将cnf, kw合并merge
            cnf = _cnfmerge((cnf, kw))
        self.widgetName = widgetName
        BaseWidget._setup(self, master, cnf)
        if self._tclCommands is None:
            self._tclCommands = []
        classes = [(k, v) for k, v in cnf.items() if isinstance(k, type)]
        for k, v in classes:
            del cnf[k]
        self.tk.call(
            (widgetName, self._w) + extra + self._options(cnf))
        for k, v in classes:
            k.configure(self, v)

3.1.2、字典索引方式:fred[“fg”]=“red” # fred[“bg”]=“blue”

部分IDE按Ctrl后点击“label[“bg”] = “yellow””的中括号可进入__init__.py文件,实际调用了:

def __setitem__(self, key, value)
===> def configure(self, cnf=None, **kw):
===> def _configure(self, cmd, cnf, kw):

class Misc:
	省略。。。
    def __setitem__(self, key, value):
        self.configure({key: value})
    
    def configure(self, cnf=None, **kw):
        """Configure resources of a widget.

        The values for resources are specified as keyword
        arguments. To get an overview about
        the allowed keyword arguments call the method keys.
        """
        return self._configure('configure', cnf, kw)
            
   	def _configure(self, cmd, cnf, kw):
        """Internal function."""
        if kw:  # 参见2.1.1.1创建时初始化,都是将2个字典cnf、kw融合
            cnf = _cnfmerge((cnf, kw))
        elif cnf:
            cnf = _cnfmerge(cnf)
        if cnf is None:
            return self._getconfigure(_flatten((self._w, cmd)))
        if isinstance(cnf, str):
            return self._getconfigure1(_flatten((self._w, cmd, '-'+cnf)))
        self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))

调用:self.configure({key: value})

3.1.3、 config()方法:fred.config(fg=“red”, bg=“blue”)

class Misc:

    def configure(self, cnf=None, **kw):
        """Configure resources of a widget.

        The values for resources are specified as keyword
        arguments. To get an overview about
        the allowed keyword arguments call the method keys.
        """
        return self._configure('configure', cnf, kw)

	config = configure # config方法就是self.configure

3.2、常用属性:

属性 描述
width,height 若是文本,则单个英文字符为1单位(汉字占2字符);若是图像,则以1像素为1单位。默认值是根据所显示具体内容动态调整
font 字体、字体大小,(font_name, size)
image 图像,目前仅仅支持gif格式
fg、bg 前景色(foreground)、背景色(background)
justify 文字对齐方式,如:“left” “right” “right”

3.3、示例代码

from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('300x40+500+300')    # 宽300,长40,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 不准拉伸(宽,高)
root.title('这是title')              # 设置弹框名称

# 设置一个文字Label,grid()是网格化布局,默认是从上往下,从左往右为0 1 2...
# 布局管理器pack/grid/place只可以使用一个,将button 显示到窗口上
label = Label(root,text="这是Label的文本" , font=('黑体',15))
label.grid()        # 也可以用label.pack()

label["bg"] = "yellow"      # 索引方式设置背景色
label.config(fg="blue")     # config()设置前景色


root.mainloop()                      # 循环弹窗

在这里插入图片描述

4、button

语法:

w = Button ( master, option=value, ... )

master: 按钮的父容器。
options: 可选项,即该按钮的可设置的属性。这些选项可以用键 = 值的形式设置,并以逗号分隔。

from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('400x150+500+300')    # 宽400,高150,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 是否拉伸(宽,高)
root.title('这是title')             # 设置弹框名称

def Btn1_fun(event):
    print("1")

Btn1 = Button(root, text="按钮1", command=Btn1_fun)       # 点击按钮就执行 Btn1_fun()
Btn1.pack()


Button(root, text="退出", command=root.destroy).pack()    # 退出按钮

root.mainloop()                      # 循环弹窗

在这里插入图片描述

4.1、options(属性):

options 描述 options 描述
activebackground 当鼠标放上去时,按钮的背景色 activeforeground 当鼠标放上去时,按钮的前景色
bd 按钮边框的大小,默认为 2 个像素 bg 按钮的背景色
command 按钮关联的函数,当按钮被点击时,执行该函数 fg 按钮的前景色(按钮文本的颜色)
font 文本字体 height 按钮的高度
highlightcolor 要高亮的颜色 image 按钮上要显示的图片
justify 显示多行文本的时候,设置不同行之间的对齐方式,可选项包括LEFT, RIGHT, CENTER padx 按钮在x轴方向上的内边距(padding),是指按钮的内容与按钮边缘的距离
pady 按钮在y轴方向上的内边距(padding) relief 边框样式,设置控件3D效果,可选的有:flat(无边框)、sunken、raised(默认)、groove、ridge。默认为 FLAT。
state 设置按钮组件状态,可选的有active(正点击状态),disabled(不可点击),normal。默认 normal。 underline 下划线。默认按钮上的文本都不带下划线。取值就是带下划线的字符串索引,为 0 时,第一个字符带下划线,为 1 时,前两个字符带下划线,以此类推
width 按钮的宽度,如未设置此项,其大小以适应按钮的内容(文本或图片的大小) wraplength 限制按钮每行显示的字符的数量
text 按钮的文本内容 anchor 锚选项,控制文本的位置,默认为中心center,可选n,e,s,w,ne,se,sw,nw

4.2、方法

方法 描述
flash() 在激活状态颜色和正常颜色之间闪烁几次单选按钮,但保持它开始时的状态。
invoke() 单击按钮

5、单选按钮Radiobutton、复选按钮Checkbutton

简单理解就是单项选择、多项选择,按钮可以是文本、图片

  • 单选按钮:
    在这里插入图片描述
from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('300x30+500+300')    # 宽300,高30,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 不准拉伸(宽,高)
root.title('这是title')             # 设置弹框名称

str1 = StringVar()
str1.set("A")

def confirm():
    print(str1.get())

button1 = Radiobutton(root, text="A选项", value="A", variable=str1)  # 就是将value的值传递给variable,因此打印str1是"A"
button2 = Radiobutton(root, text="B选项", value="B", variable=str1)

button1.pack(side="left")
button2.pack(side="left")

Button(root, text="确定", command=confirm).pack(side="left")

Button(root, text="退出", command=root.destroy).pack(side="left")     # 退出按钮,靠左侧排列

root.mainloop()                      # 循环弹窗
  • 复选按钮:

在这里插入图片描述

from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('300x30+500+300')    # 宽300,高30,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 不准拉伸(宽,高)
root.title('这是title')             # 设置弹框名称

int_1 = IntVar()	# 需要用2个变量分别接收2个选项
int_1.set(1)
int_2 = IntVar()
int_2.set(1)

def confirm():
    print(int_1.get())
    print(int_2.get())

button1 = Checkbutton(root, text="A选项", onvalue=1, offvalue=0, variable=int_1)  # 就是将value的值传递给variable,因此打印str1是"A"
button2 = Checkbutton(root, text="B选项", onvalue=1, offvalue=0, variable=int_2)

button1.pack(side="left")
button2.pack(side="left")

Button(root, text="确定", command=confirm).pack(side="left")

Button(root, text="退出", command=root.destroy).pack(side="left")     # 退出按钮,靠左侧排列

root.mainloop()                      # 循环弹窗

6、Entry 单行文本框、messagebox 弹窗

  • Entry的可选参数参考:https://blog.csdn.net/qq_41556318/article/details/85108328
  • 接受一行字符串(多行字符请用Text控件)。如果用户输入的文字长度长于Entry控件的宽度时,文字会自动向后滚动。
  • 可以使用tkinter定义的类型接受文本框内容:

tkinter.Variable派生了:
  tkinter.BooleanVar
  tkinter.IntVar
  tkinter.DoubleVar
  tkinter.StringVar

from tkinter import *
from tkinter import messagebox

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('300x100+500+300')    # 宽300,长100,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 不准拉伸(宽,高)
root.title('这是title')              # 设置弹框名称

entryStr = StringVar()          # 接收文本框字符,StringVar 继承 tkinter.Variable
entryStr.set("显示默认值")

entry = Entry(root, textvariable=entryStr)  # 文本框中的内容和entryStr是联动的
entry.pack()
Entry(root, textvariable=entryStr, show="*").pack()


def tanchuang():
    print(entry.get())
    messagebox.showinfo("弹窗标题", "弹窗内容")
button = Button(root, text="点击弹窗", command=tanchuang)
button.pack()

Button(root, text="退出", command=root.destroy).pack()

root.mainloop()                      # 循环弹窗

在这里插入图片描述

7、Text 多行文本框

  • 显示多行文本,可以显示图片、HTML页面、网页链接、CSS样式表、添加组件。

7.1、创建Text,插入insert(),删除delete():

Text组件默认就可以手动输入删除文本的,Ctrl C、Ctrl V、上下滚动等操作都可以用

from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('400x200+500+300')    # 宽400,高200,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 不准拉伸(宽,高)
root.title('这是title')             # 设置弹框名称


text = Text(root, width=40, height=12, bg="green")   # 宽40列字符,高12行字符
text.pack()
text.insert(1.0, "这里显示\n默认文本123")   # 列从0列开始,行从1行开始,1.0表示从第1列第0列插入(就是最左上角)
text.insert(2.2, "abc")                 # 1汉字和1字母都是占1列
text.delete(2.7, END)                   # 删除 2行7列之后的文本,就是删了"123"

def insertText():
    text.insert(index=INSERT, chars="光标处插入的文本")    # INSERT索引:在光标处插入
    text.insert(index=END, chars="\n文末处插入文本")       # END索引:文末处插入文本
    
    
Button(root, text="重复插入文本", command=insertText).pack(side="left") # side默认是竖直排列

root.mainloop()                      # 循环弹窗

在这里插入图片描述

7.2、返回文本 get()

from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('400x200+500+300')    # 宽300,长100,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 不准拉伸(宽,高)
root.title('这是title')             # 设置弹框名称


text = Text(root, width=40, height=12, bg="green")
text.pack()
text.insert(1.0, "这里显示\n默认文本")   # 列从0列开始,行从1行开始,1.0表示从第1列第0列插入(就是最左上角)
text.insert(2.2, "abc")                 # 1汉字和1字母都是占1列

def returnText():
    print(text.get(1.2, 2.3))                       # 返回 [1行2列,2行3列) 文本,注意最左上为1.0
    print("\n所有文本:\n" + text.get(1.0, END))     # 返回所有文本
    
Button(root, text="返回文本", command=returnText).pack(side="left")   # side默认是竖直排列

Button(root, text="退出", command=root.destroy).pack(side="left")     # 退出按钮,靠左侧排列

root.mainloop()                      # 循环弹窗

在这里插入图片描述

7.3、添加图片 image_create()

from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('450x330+500+300')    # 宽450,高330,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 不准拉伸(宽,高)
root.title('这是title')             # 设置弹框名称


text = Text(root, width=57, height=23, bg="green")
text.pack()
text.insert(1.0, "这里显示\n默认文本")   # 列从0列开始,行从1行开始,1.0表示从第1列第0列插入(就是最左上角)
text.insert(2.2, "abc")                 # 1汉字和1字母都是占1列

def addImage():
    global photo 
    photo = PhotoImage(file="./test.gif")
    text.image_create(END, image=photo)
    
Button(root, text="添加图片", command=addImage).pack(side="left")   # side默认是竖直排列

Button(root, text="退出", command=root.destroy).pack(side="left")     # 退出按钮,靠左侧排列

root.mainloop()                      # 循环弹窗

在这里插入图片描述

7.4、添加组件

如:添加按钮

from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('400x200+500+300')    # 宽400,高200,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 不准拉伸(宽,高)
root.title('这是title')             # 设置弹框名称


text = Text(root, width=55, height=13, bg="green")
text.pack()
text.insert(1.0, "这里显示\n默认文本")   # 列从0列开始,行从1行开始,1.0表示从第1列第0列插入(就是最左上角)
text.insert(2.2, "abc")                 # 1汉字和1字母都是占1列

def addButton():
    Button(root, text="添加按钮", command=addButton).pack(side="left")
    
Button(root, text="添加按钮", command=addButton).pack(side="left")   # side默认是竖直排列

Button(root, text="退出", command=root.destroy).pack(side="left")     # 退出按钮,靠左侧排列

root.mainloop()                      # 循环弹窗

在这里插入图片描述

7.5、tag组件

from tkinter import *
import webbrowser

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('400x200+500+300')    # 宽400,高200,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 不准拉伸(宽,高)
root.title('这是title')             # 设置弹框名称


text = Text(root, width=55, height=13, bg="green")
text.pack()
text.insert(1.0, "这里显示\n默认文本")   # 列从0列开始,行从1行开始,1.0表示从第1列第0列插入(就是最左上角)

def webshow(event):         # tag_bind()会传入一个参数,因此这里需要一个event接收
    webbrowser.open("https://blog.csdn.net/qq_42888201?spm=1000.2115.3001.5343")

def tagControl():
    text.delete(1.0, END)               # 清空文本框内容
    text.insert(INSERT, "good good study,\nday day up!")
    
    text.tag_add("tag1", 1.5, 1.11)     # 添加标签,标签名:tag1 作用范围[1行5列, 1行11列)
    text.tag_config("tag1",             # 将tag1标签设为 背景色灰色,前景色白色
                    background="gray", foreground="white")
    
    text.tag_add("tag2", 2.1, END)
    text.tag_config("tag2", underline=True)
    text.tag_bind(tagName="tag2",       # tag2标签区域绑定 按钮事件,调用webshow
                  sequence="<Button-1>", func=webshow)
    
    
    
    
Button(root, text="tag标记控制", command=tagControl).pack(side="left")   # side默认是竖直排列

Button(root, text="退出", command=root.destroy).pack(side="left")     # 退出按钮,靠左侧排列

root.mainloop()                      # 循环弹窗

在这里插入图片描述

7.6、关于index

  • 就是insert函数的第一个参数:表示Text组件中文本的位置

例如:“行号.列号”,例如1.0表示第1行第0列

注意:
1、行号以1开始,列号则以0开始
2、text.tag_add(“tag1”, 1.1, 1.3)也可以写为
  text.tag_add(“tag1”, “1.1”, “1.3”)
  1.10必须写为"1.10"

from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('400x80+500+300')    # 宽400,高80,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 不准拉伸(宽,高)
root.title('这是title')             # 设置弹框名称


text = Text(root, width=40, height=4, bg="green")   # 宽40列字符,高12行字符
text.pack()
text.insert(1.0, "0123456789\n0123456789\n0123456789\n")   # 列从0列开始,行从1行开始,1.0表示从第1列第0列插入(就是最左上角)

text.tag_add("tag1", 1.1, 1.3)      # 包括1.1而不包括1.3,表示 [1行1列, 1行3列)
text.tag_config("tag1", background="black", foreground="white")
    
Button(root, text="退出", command=root.destroy).pack(side="left")     # 退出按钮,靠左侧排列
root.mainloop()                      # 循环弹窗

在这里插入图片描述

一些说明:

格式 说明 例子
行号.end 该行最后一个字符串的位置 text.tag_add(“tag1”, “1.10”, “1.end”)
INSERT 对应光标的位置 text.tag_add(“tag1”, “2.1”, INSERT)
CURRENT 对应与鼠标坐标最接近的位置。不过,如果你紧按鼠标任何一个按钮,会直接到你松开才相应。
END Text组件的文本缓冲区最后一个字符的下一个位置

其他详细的参考:https://www.cnblogs.com/pinpin/p/9960779.html

8、canvas(画布)

一个矩形区域,可以放入图像、图形、组件等。

在这里插入图片描述

from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('300x200+500+300')    # 宽300,高30,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 不准拉伸(宽,高)
root.title('这是title')             # 设置弹框名称

canvas = Canvas(root, width=280, height=150, bg="green")    # 创建一个画布
canvas.pack()

line = canvas.create_line(10, 10, 10, 50, 70, 50)   # 折线:(x, y):(10,10) (10,50) (70,50)连成折线
rect = canvas.create_rectangle(20, 80, 100, 130)    # 矩形:左上角(20,80),右下角:(100,130)
oval = canvas.create_oval(20, 80, 100, 130)         # 椭圆:外接矩形的左上角(20,80)、右下角(100,130)

global photo
photo = PhotoImage(file="./test.gif")
canvas.create_image(320, 170, image=photo)          # 图像中心位置(320, 170)

Button(root, text="退出", command=root.destroy).pack(side="left")     # 退出按钮,靠左侧排列

root.mainloop()                      # 循环弹窗
  • delete()
函数 说明
delete(id) 通过id来删除,id是canvas.create_something的返回值
delete(tag) 通过tag来删除,tag通过canvas.create_something(tag=tag)来指定
delete(“all”) 删除所有已绘制对象

9、OptionMenu、ttk.Combobox下拉选项框

9.1、OptionMenu

from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('400x150+500+300')    # 宽400,高150,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 是否拉伸(宽,高)
root.title('这是title')             # 设置弹框名称

v = StringVar(root)
v.set("选项1")            # 记录选项框的内容,会和选项框联动

# OptionMenu的初始化函数:__init__(self, master, variable, value, *values, **kwargs):
om = OptionMenu(root, v, "选项1", "选项2", "选项2333")
om["width"] = 30    # 宽度
om.pack()

Button(root, text="输出", command=lambda:print(v.get())).pack()

root.mainloop()                      # 循环弹窗

在这里插入图片描述

9.2、ttk.Combobox()

from tkinter import *
from tkinter.messagebox import *
from tkinter import ttk

root = Tk();root.title('这是title')
screenwidth, screenheight = root.winfo_screenwidth(), root.winfo_screenheight()
width, height = 400, 150
x, y = int((screenwidth-width)/2), int((screenheight-height)/2)     # 居中后 窗口左上角坐标
root.geometry('{}x{}+{}+{}'.format(width, height, x, y))

value = StringVar()
value.set('CCC')
valueList = ['AAA', 'BBB', 'CCC', 'DDD']
combobox = ttk.Combobox(master=root,  # 父容器
                        height=10,  # 高度,下拉显示的条目数量
                        width=20,  # 宽度
                        state='readonly',  # 设置状态 normal(可选可输入)、readonly(只可选)、 disabled
                        cursor='arrow',  # 鼠标移动时样式 arrow, circle, cross, plus...
                        font=('', 20),  # 字体
                        textvariable=value,  # 通过StringVar设置可改变的值
                        values=valueList,  # 设置下拉框的选项
                        )
print(combobox.keys())  # 可以查看支持的参数
combobox.pack()

def fun(event):
    print("执行{}的函数".format(value.get()))            # 绑定函数

combobox.bind("<<ComboboxSelected>>", fun)

root.mainloop()                      # 循环弹窗

在这里插入图片描述

10、Scale移动滑块

在这里插入图片描述

from tkinter import *

root = Tk();root.geometry('400x150+500+300');root.title('这是title')

L1 = Label(root, text="滑动滑块控制文本大小")

def ScaleFun(value):
    print("滑块值:\t", value)
    L1.config(font=("宋体", value))
    
# 初始值frim_10,最大值to50,滑块长度length250,相邻显示的2个值公差5,水平HORIZONTAL排列(默认竖直VERTICAL)
Scale(root, from_=10, to=50, length=250, tickinterval=5, orient=HORIZONTAL,
      command=ScaleFun).pack()  
L1.pack()

root.mainloop()                      # 循环弹窗

11、各种选择框、消息框

11.1、askcolor颜色选择框

s1 = askcolor(color=“green”, title=“请选择背景颜色”) # 默认颜色绿色
print(s1) # 输出:((0, 128, 0), ‘#008000’),第一个是(R, G, B)

在这里插入图片描述

from tkinter import *
from tkinter.colorchooser import *

root = Tk();root.geometry('400x150+500+300');root.title('这是title')

def colorSelect():
    s1 = askcolor(color="green", title="请选择背景颜色") # 默认颜色绿色
    print(s1)	# 输出:((0, 128, 0), '#008000')
    root.config(bg=s1[1])	# s1[1]就是'#008000'

Button(root, text="选择颜色", command=colorSelect).pack()

root.mainloop()                      # 循环弹窗

11.2、askopenfilename文件对话框

需要导入包:from tkinter.filedialog import *

函数名 对话框 说明
askopenfilename(**options)
askopenfilenames(**options)
文件对话框 返回打开的文件名
返回打开的文件名列表
askopenfile(**options)
askopenfiles(**options)
返回打开文件对象
返回打开文件对象的列表
askdirectory(**options) 目录对话框 返回目录名
asksaveasfile(**options) 保存对话框 返回保存的文件对象
asksaveasfilename(**options) 返回保存的文件名
  • options:
参数名 说明
defaultextension 保存文件,用户没有定义后缀时的默认后缀(默认值:.xxx)
filetypes=[(label1,pattern1),(label2,pattern2)] 文件显示过滤器
initaldir 文件窗口的初始目录
parent 父窗口
title 窗口标题
from tkinter import *
from tkinter.filedialog import *

root = Tk();root.geometry('400x150+500+300');root.title('这是title')

def fun():
    f = askopenfilename(title="这是标题", initialdir="D:/test",     # initialdir初始路径,注意 /,而\需要r"\"
                        filetypes=[("文档", "txt"), ("视频", "mp4")])
    print(f)

Button(root, text="选择文件", command=fun).pack()

root.mainloop()                      # 循环弹窗

在这里插入图片描述

  • 读取文件内容:
from tkinter import *
from tkinter.filedialog import *

root = Tk();root.geometry('400x150+500+300');root.title('这是title')

def fun():
    with askopenfile(title="这是标题", initialdir="D:/test",     # initialdir初始路径,注意 /,而\需要r"\"
                        filetypes=[("文档", "txt"), ("视频", "mp4")]) as f:    
        print(f.read())             # 如果是'utf-8'文本会失败,可以将文本另存为ANSI,或者使用open(file,encoding="utf-8")
        
        
Button(root, text="读取文件内容", command=fun).pack()

root.mainloop()                      # 循环弹窗

11.3、simpledialog 简单输入对话框

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

title:窗口标题
prompt:提示信息
命名参数kw:initialvalue(初始值)、minvalue(最小值)、maxvalue(最大值)

from tkinter.simpledialog import *

root = Tk();root.geometry('400x150+500+300');root.title('这是title')

def fun():
    a = askinteger(title="整数输入框", prompt="输入一个整数:", initialvalue=2333,
                   minvalue=1, maxvalue=10000)      # 确认:返回数字,若数字非法会弹窗报错  取消:返回None 
    print(a)
        
Button(root, text="输入整数", command=fun).pack()

root.mainloop()                      # 循环弹窗

在这里插入图片描述

11.4、通用消息框

在这里插入图片描述

函数名 说明 函数名 说明
askokcancel(title,message, **options) OK/Cancel对话框 askquestion(title,message, **options) 问题对话框
askretrycancel(title,message, **options) Retry/Cancel对话框 showerror(title,message, **options) 错误消息框
showinfo(title,message, **options) 消息框 showwarning(title,message, **options) 警告消息框
from tkinter import *
from tkinter.messagebox import *

root = Tk();root.geometry('400x150+500+300');root.title('这是title')

def fun():
    a1 = askokcancel(title="OK/Cancel对话框", message="这是框内信息\nhello world!")        # True, False
    a2 = askquestion(title="问题对话框", message="这是框内信息\nhello world!")             # 'yes', 'no'
    a3 = askretrycancel(title="Retry/Cancel对话框", message="这是框内信息\nhello world!")  # True, False
    showerror(title="错误消息框", message="这是框内信息\nhello world!")
    showinfo(title="消息框", message="这是框内信息\nhello world!")
    showwarning(title="警告消息框", message="这是框内信息\nhello world!")
    
    print((a1, a2, a3))
        
Button(root, text="弹窗", command=fun).pack()

root.mainloop()                      # 循环弹窗

12、Menu菜单栏

tearoff=0:
在这里插入图片描述

tearoff=1:在这里插入图片描述

from tkinter import * 
from tkinter.filedialog import askopenfilename
import time

root = Tk();root.geometry('400x150+500+300');root.title('这是title')

def fun():
    print("执行fun")

def createContextMenu(event):
    contextMenu.post(event.x_root, event.y_root)

# 主菜单
menubar = Menu(root)

# 创建子菜单
menu_1 = Menu(menubar, tearoff=0)   # 默认tearoff=1,可以使菜单独立一个窗口显示出来
menu_2 = Menu(menubar, tearoff=0)

# 将子菜单加入到主菜单栏
menubar.add_cascade(label="文件(F)", menu=menu_1) # 但是F不会真正生效
menubar.add_cascade(label="帮助(H)", menu=menu_2)

# 添加菜单项
menu_1.add_command(label="新建", accelerator="ctrl+n", command=fun)   # 快捷键不会真正生效
menu_1.add_separator()              # 添加分割线
menu_1.add_command(label="打开", accelerator="ctrl+o", command=fun)

root["menu"] = menubar      # root中加入menubar

# 创建上下文菜单(右键菜单)
contextMenu = Menu(root)
contextMenu.add_command(label="背景颜色", command=fun)
root.bind("<Button-3>", createContextMenu)

# 循环弹窗
root.mainloop()

13、frame容器

  • 就是放置其他组件的容器
  • 实测,当放置了其他组件后,原来设定长宽会失效,frame的大小适配他的子组件
from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('400x200+500+300')    # 宽400,高200,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 不准拉伸(宽,高)
root.title('这是title')             # 设置弹框名称


f1 = Frame(root,width=100,  height=50, highlightcolor="red", bg="blue")     # Frame是一个矩形区域,放置子组件
f1.pack()

f2 = Frame(root, width=100, height=50,bg="yellow")
f2.pack()

f3 = Frame(root, width=100, height=50,bg="green")   # 由于放置了部件,长宽适配组件
f3.pack()

# 当Frame上面放置了部件,那么frame原长宽值失效,而适配他的组件
Label(f3, text="L1_left", relief="solid").pack(side="left")
Label(f3, text="L2_bottom", relief="solid").pack(side="bottom")
Label(f3, text="L3_top", relief="solid").pack(side="top")

root.mainloop()                      # 循环弹窗

效果图如下,关于side="left"参考布局管理器条目pack()
在这里插入图片描述

14、布局管理器pack()、grid()、place()

顾名思义,就是整体布局的设置

14.1、表格布局grid()

用类似表格的结构组织组件,子组件的位置由(行, 列)的单元格来确定,可以跨行跨列。

  • grid()参数:
选项 说明 取值范围
row 行号 0,1,2,3,…
column 列号 0,1,2,3,…
rowspan 跨行,跨越的行数 正整数
columnspan 跨列,跨越的列数 正整数
padx, pady 组件之间的间隔,x、y方向,默认单位为像素 非负浮点数,默认0.0
ipadx, ipady 子组件之间的间隔,x、y方向,默认单位为像素 非负浮点数,默认0.0
sticky 组件紧贴所在单元格的某一角,东南西北(eswn)和四个角落 “n”, “s”, “w”, “e”, “nw”, “sw”, “se”, “ne”, “center”(默认)

在这里插入图片描述

from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('400x200+500+300')    # 宽400,高200,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 不准拉伸(宽,高)
root.title('这是title')             # 设置弹框名称



Button(root, text="(0, 0)").grid(row=0, column=0)   # 0行0列
Button(root, text="(0, 1)").grid(row=0, column=1)   # 0行1列
Button(root, text="(0, 3)").grid(row=0, column=3)   # 0行3列

Button(root, text="(1, 0)").grid(row=1, column=0)   # 1行0列
Button(root, text="(1, 1)").grid(row=1, column=1)   # 1行1列
Button(root, text="(1, 2)").grid(row=1, column=2)   # 1行2列
Button(root, text="(1, 5)").grid(row=1, column=5)   # 1行5列,但是1行3、4列没组件,自动向左移2列

Button(root, text="(2, 0)").grid(row=2, column=0, padx=15)   # 2行0列,组件之间的间隔拉大了15个像素

Entry(root, ).grid(row=3, column=1)                 # 3行1列,但是组件比较宽,是的整个组件拉宽了

Button(root, text="w(4, 1)").grid(row=4, column=1, sticky="w")   # 4行1列,组件紧邻单元格左侧
Button(root, text="w(5, 1)e").grid(row=5, column=1, sticky="we") # 5行1列,组件紧邻单元格左右两侧

root.mainloop()                      # 循环弹窗

14.2、pack()

  • 最简单的一种,按照水平、竖直方向自然排布,默认竖直方向。
可选项 描述 取值范围
side 停靠在父组件的哪一边上
若属性expand=“yes”,side属性失效
“top”(默认值), “bottom”, “left”, “right”
expand 布尔值
当expand="yes"时side选项失效,若fill=“both”,则填充父组件剩余空间
“yes”,自然数,“no”(默认值"no"或0)
fill 填充x、y方向上的空间。
 属性side=top\bottom时,填充x、方向
 (left\right填充y方向)
“x”、“y”、“both”、“none”(默认值)
padx, pady 组件之间的间隔,x、y方向,默认单位为像素 非负浮点数,默认0.0
ipadx, ipady 子组件之间的间隔,x、y方向,默认单位为像素 非负浮点数,默认0.0
before、after before:将本组件设定在另一组件之前进行pack(),作用效果就是先创建其他组件,再创建本组件
after:…之后…
已经pack后的组件
in_ 本组件作为另一组件的子组件 已经pack后的组件
anchor 对齐方式,左对齐"w",右对齐"w",顶对齐"n",底对齐"s" “n” “s” “w” “e” “nw” “sw” “se” “ne” “center”(默认)
  • 关于side选项示例代码:
from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('400x200+500+300')    # 宽400,高200,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 不准拉伸(宽,高)
root.title('这是title')             # 设置弹框名称


f1 = Frame(root,width=100,  height=50, highlightcolor="red", bg="blue")     # Frame是一个矩形区域,放置子组件
f1.pack()

f2 = Frame(root, width=100, height=50,bg="green")   # 由于放置了部件,长宽适配组件
f2.pack()

# 当Frame上面放置了部件,那么frame原长宽值失效,而适配他的组件
Label(f2, text="L1_left", relief="solid").pack(side="left")
Label(f2, text="L2_bottom", relief="solid").pack(side="bottom")
Label(f2, text="L3_top", relief="solid").pack(side="top")
Label(f2, text="L4_left", relief="solid").pack(side="left")
Label(f2, text="L5_top", relief="solid").pack(side="top")
Label(f2, text="L6_top", relief="solid").pack(side="top")


root.mainloop()                      # 循环弹窗

在这里插入图片描述

  • 关于fill选项,示例代码:
from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('400x100+500+300')    # 宽400,高100,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 不准拉伸(宽,高)
root.title('这是title')             # 设置弹框名称


f1 = Frame(root, width=100, height=50,bg="green")   # 由于放置了部件,长宽适配组件
f1.pack()

# 当Frame上面放置了部件,那么frame原长宽值失效,而适配他的组件
Label(f1, text="L1_left_none", relief="solid").pack(side="left")
Label(f1, text="L2_left_y", relief="solid").pack(side="left", fill="y")
Label(f1, text="L3_top_none", relief="solid").pack(side="top")
Label(f1, text="L4_top_x", relief="solid").pack(side="top", fill="x")
Label(f1, text="L4_left_none", relief="solid").pack(side="left")
Label(f1, text="L5_left_none", relief="solid").pack(side="left")


root.mainloop()                      # 循环弹窗

在这里插入图片描述

  • 关于expand
from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('400x100+500+300')    # 宽400,高100,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 不准拉伸(宽,高)
root.title('这是title')             # 设置弹框名称

Label(root, text="L1", bg="green").pack(side="left",fill="both", expand="yes")
Label(root, text="L2", bg="red").pack(side="left", fill="both", expand="yes")
Label(root, text="L3", bg="green").pack(side="left", fill="both", expand="yes")

root.mainloop()                      # 循环弹窗

在这里插入图片描述
依次注释掉L1, L2, L3的代码,expand=yes、no,如下图。当为yes时,只有L1就会占满整个root窗口(而不是靠在左侧left):
在这里插入图片描述

14.3、place()

  • 通过坐标精准控制组件位置
选项 说明 取值范围
relx, rely 组件左上角坐标(相对于父容器)
实际坐标是先计算relx\rely的值后再加上x\y的偏移值
0~1的浮点数
0:最左\上
0.5:中间
1:最右\下
x, y 组件左上角的绝对坐标(相对于窗口)
实际位置需要考虑relx、rely
非负整数,单位像素
width, height 组件的宽度、高度 计算凡是与x、y类似
relwidth, relheight 组件的宽度、高度(相对于父组件) 计算方式与relx、rely取值类似,相对于父组件的尺寸
anchor 对齐方式,左对齐"w",右对齐"w",顶对齐"n",底对齐"s" “n” “s” “w” “e” “nw” “sw” “se” “ne” “center”(默认)
from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('400x150+500+300')    # 宽400,高100,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(True, False)         # 是否拉伸(宽,高)
root.title('这是title')             # 设置弹框名称

Label(root, text="x,y=(30,30)", bg="yellow").place(x=30, y=30)
Label(root, text="relx,rely=(0.5,0.5)", bg="green").place(relx=0.5, rely=0.5)   # 拉伸root窗口,位置会跟随变化
Label(root, text="x,y=(30,30)\nrelx,rely=(0.5,0.5)", bg="gray").place(x=30, y=30, relx=0.5, rely=0.5)

root.mainloop()                      # 循环弹窗

在这里插入图片描述

15、事件处理

参考:http://www.manongjc.com/article/61145.html

  • 一个GUI应用整个生命周期都处在一个消息循环(event loop)中,它等待事件(Event)的发生(鼠标事件、键盘事件)。
  • 3个概念:
  • 事件(event):是指点击、按键等操作,在tkinter中,event是一个类,当某个事件发生时,生成一个event对象,不同类型的事件生成具有不同属性的event对象。
  • 事件处理(event handler):是指在捕获到事件后,程序自动执行的操作,是回调函数(recall function)。
  • 事件绑定(event binding):是当一个事件发生时程序能够做出响应。tkinter提供三种绑定方式:实例绑定bind(将某个事件处理绑定到某个组件上)、类绑定bind_class(将某个事件处理绑定到某类组件上)、应用绑定bind_all(将某个事件处理绑定到所有组件上)。

15.1、 将函数绑定控件 发生的事件

  • 组件对象的绑定

两种方法:
 1、组件名.bind(event事件, handler被触发的函数)
 2、command属性来执行事件,适合简单且不需要event对象

  • 组件类的绑定:组件名.bind_class(“Widget组件类型”, “event”, eventhanler)
      将该组件类的所有组件绑定事件。如 btn01.bind_class(“Button”, “<Button-1>”, myFun01)
from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('400x150+500+300')    # 宽400,高150,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 是否拉伸(宽,高)
root.title('这是title')             # 设置弹框名称

def Btn1_fun(event):              
    print("{}\t({},{})".format(event.widget["text"], event.x, event.y))

btn0 = Button(root, text="按钮1", command=Btn1_fun)
btn0.pack()
btn0.bind_class("Button", "<Button-1>", Btn1_fun)

Button(root, text="按钮2").pack()

root.mainloop()                      # 循环弹窗

点击按钮2时也会执行Btn1_fun():
在这里插入图片描述

  • 使用lambda表达式传递多个参数
from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('400x150+500+300')    # 宽400,高150,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 是否拉伸(宽,高)
root.title('这是title')             # 设置弹框名称

def Btn1_fun(a, b, c):              # 注意参数列表没有event
    print(a+b+c)

Button(root, text="按钮1", command=lambda:Btn1_fun(1, 2, 3)).pack()       # 点击按钮就执行 Btn1_fun()

root.mainloop()                      # 循环弹窗

在这里插入图片描述

15.2、鼠标、键盘事件、侦听窗口大小变化

语法:<modifier - type - dateil>

  • modifier:事件修饰符。如:Alt、Shit组合键和Double事件。
  • type:事件类型。如:按键(Key)、鼠标(Button/Motion/Enter/Leave/Relase)、Configure等。
  • detail:事件细节。如:鼠标左键(1)、鼠标中键(2)、鼠标右键(3)

注意:接受键盘事件,只有组件获取焦点才能接受键盘事件,用focus_set()获取焦点

  • modifier:
取值 说明 取值 说明
Alt 按下Alt键 Shift 按下Shift键
Control 按下Ctrl键 Any 任何类型的按键被按下,如<Any-KeyPress>表示按下任何键
Double 后续事件连续2次被触发,如<Double-1>表示双击左键 Triple 当后续事件连续3次触发
Lock 当打开大写字母
  • type:
    <Button-1>左键,<Button-2>中键,<Button-3>右键,<Button-4>滚轮上(liunx),<Button-5>滚轮下(liunx)

  • dateil部分是可选的,它通常是描述具体的键,(<Control-Shift-Key-H>,表示用户同时按下Ctrl+Shift+H)

  • 常用例子:

事件类型 事件格式 事件解释
鼠标事件 <Button-1>
<ButtonPress-1>
<1>
鼠标按下(1-左键,2-中键,3-右键)
<Double-Button-1> 鼠标双击(1-左键,2-中键,3-右键)
<B1-Motion> 鼠标拖动(1-左键,2-中键,3-右键)
<ButtonRelease-1> 鼠标按下之后释放(1-左键,2-中键,3-右键)
<Enter> 鼠标进入控件范围(widget),不是键盘按键
<Leave> 鼠标离开控件范围(widget)
<MouseWheel> 滚动滚轮
键盘事件 <Return>
<Cancel>
<space>
<Tab>
<Shift_L>
<Control_L>
<Alt_L>
<Home>
<Left>
<Up>
<Down>
<Right>
<Delete>
<F1>
<F2>
对应键盘按键
<KeyPress-a> 按下a键,a可以是其他字符(如1,2,b,c,大写字母A等)
<KeyRelease-a> 释放a键
<Control-a> 同时按下Ctrl和a
<Alt-KeyPress-a> 同时按下Alt和a,Alt可用Ctrl,Shift替换
<Double-KeyPress-a> 快速按两下a
组件事件 <Configure> 如果widget的大小发生改变,新的大小(width和height)会打包到event发往handler。
<Activate> 当组件从不可用变为可用
<Deactivate> 当组件从可用变为不可用
<Destroy> 当组件被销毁时
<Expose> 当组件从被遮挡状态变为暴露状态
<Map> 当组件由隐藏状态变为显示状态
<Unmap> 当组件由显示状态变为隐藏状态
<FocusIn> 当组件获得焦点时
<FocusOut> 当组件失去焦点时
<Property> 当组件属性发生改变时
<Visibility> 当组件变为可视状态时

参考:https://www.weixueyuan.net/a/574.html
<Key>:此事件在按下 ASCII 码为 48~90 时发生,即数字键、字母键及 +、~ 等符号。
<Control-Up>:此事件在按下 Ctrl+Up 组合键时发生。同理,可以使用类似的名称在 Alt、Shift 键加上 Up、Down、Left 与 Right 键。
其他按键,使用其按键名称。包括 <Return>、<Escape>、<F1>、<F2>、<F3>、<F4>、<F5>、<F6>、<F7>、<F8>、<F9>、<F13>、<F11>、<F12>、<Num_Lock>、<Scroll_Lock>、<Caps_Lock>、<Print>、<Insert>、<Delete>、<Pause>、<Prior>(Page Up)、<Next>(Page Down)、<BackSpace>、<Tab>、<Cancel>(Break)、<Control_L>(任何的 Ctr l键)、<Alt_L>(任何的Alt键)、<Shift_L>(任何的Shift键)、<End>、<Home>、<Up>、<Down>、<Left>、<Right>

  • 侦听窗口大小变化
from tkinter import *

root = Tk(); root.geometry('300x60+500+200'); root.title('这是title')

def getConfigure(event):
    print(event)
    print("{}\t{}\t{}\t{}".format(event.x, event.y, event.width, event.height))
    print("循环前窗口宽{}\t高{}".format(root.winfo_width(), root.winfo_height()))

root.bind('<Configure>', getConfigure)


root.mainloop()                 # mainloop()    :循环弹窗

# 输出:
<Configure event x=500 y=200 width=300 height=60>
500	200	300	60
循环前窗口宽30060

15.3、Event对象常用属性

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

在这里插入图片描述

from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('400x150+500+300')    # 宽400,高150,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 是否拉伸(宽,高)
root.title('这是title')             # 设置弹框名称

global last_x, last_y
last_x, last_y = 0, 0       # 记录鼠标位置

def draw(event):            # 左键按下-->画图
    global last_x, last_y
    event.widget.create_line(last_x, last_y, event.x, event.y)  # 画直线
    last_x, last_y = event.x, event.y
    print("组件:"+str(event.widget)+"\t鼠标位置:({},{})".format(event.x, event.y))
    
def moveMouse(event):       # 移动鼠标-->记录鼠标位置
    global last_x, last_y
    last_x ,last_y = event.x, event.y
    print("组件:"+str(event.widget)+"\t鼠标位置:({},{})".format(event.x, event.y))
    
def keyPress(event):        # 按下键盘-->按下delete画布清除
    print("组件:"+str(event.widget)+"\t按下:{}".format(event.keysym))
    if event.keysym == "Delete":
        c1.delete("all")

c1 = Canvas(root, width=350, height=100, bg="green")
c1.place(x=5, y=5)
c1.bind("<B1-Motion>", draw)        # 按住左键移动
c1.bind("<Motion>", moveMouse)      # 记录鼠标当前位置
c1.delete()

L1 = Label(c1, text="Key press event", bg="yellow")
L1.focus_set()                      # 键盘事件需要设置焦点
L1.place(x=10, y=5)
L1.bind("<KeyPress>", keyPress)     # 按下键盘的键

root.mainloop()                      # 循环弹窗
  • create_rectangle还有fill、outline等参数(实心、边框填充),详细可以百度找找

15.4、协议处理机制 protocol handlers

参考:https://www.jianshu.com/p/9c66c0090edb

  • 除了事件绑定,tkinter 还支持一种称为协议处理程序(protocol handlers)的机制。在这里,术语协议(protocol)是指应用程序和窗口管理器之间的交互。最常用的协议称为 WM_DELETE_WINDOW,用于定义当用户使用窗口管理器显式关闭窗口时发生的情况(上面 2.4 部分有示例代码)。用法:

widget.protocol(“WM_DELETE_WINDOW”, handler)
注意:部件必须是 root 或者 Toplevel 小部件;点击窗体右上叉X时,不会关闭窗口,而是调用handler函数

x、一些例子

x.1、编写UI:

from tkinter import *

def button1fun():
    data = entry.get().strip()
    print(data)
    pass

# 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root = Tk()

# 宽600,长200,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.geometry('600x200+500+300')

# 不准拉伸(宽,高)
root.resizable(False, False)

# 设置弹框名称
root.title('这是title')

# 设置一个文字Label,grid()是网格化布局,默认是从上往下,从左往右为0 1 2...
# 布局管理器pack/grid/place只可以使用一个,将button 显示到窗口上
Label(root,text="这是Label的文本" , font=('黑体',15)).grid()
# 也可以用Label(root,text="这是Label的文本" , font=('黑体',15)).pack()

# 输入框
entry = Entry(root)

# 设置输入框位置,上面Label是(0,0),若输入框在Label右边则grid()为(0, 1)
entry.grid(row=0,column=1)

# 按钮1,注意回调函数(callback)是没有括号的,反复调用,而button1fun()则只执行一次
button1 = Button(master=root, text='按钮 弹窗',width='15',command=button1fun)
button1.grid(row=1,column=0)

# 按钮绑定事件 & 弹窗
def tanChuang(e):   # e就是事件
    messagebox.showinfo("弹窗标题","这是弹窗的内容")
button1.bind("<Button-1>",tanChuang)

# 退出按钮 & 布局管理器
button2 = Button(master=root, text='退出',width='15',command=root.destroy)
button2.grid()    

# 循环弹窗
root.mainloop()

在这里插入图片描述

  • before、after:
from tkinter import *

root = Tk()                         # 实例化tk类,需要配合后面root.mainloop()才能循环显示弹框
root.geometry('400x100+500+300')    # 宽400,高100,边框距离屏幕最左端距离为500,与最上端距离为300(也可以用最右/下端用减号-)
root.resizable(False, False)        # 不准拉伸(宽,高)
root.title('这是title')             # 设置弹框名称

label1 = Label(root, text="L1")
label2 = Label(root, text="L2")
label3 = Label(root, text="L3")

label1.pack(side="left")
label2.pack(side="left", before=label1)     # 将label2放到label1前面
label3.pack(side="left", after=label2)      # 将label3放到label2后面
# 最终排列为 2->3->1

root.mainloop()                      # 循环弹窗

在这里插入图片描述

x.2、使用面向对象的方式

"""使用面向对象的方式"""
from tkinter import *
from tkinter import messagebox
class Application(Frame):   # 继承tkinter.Frame
    """一个经典的GUI程序的类的写法"""    

    def __init__(self, master=None):   # master=根窗口root
        super().__init__(master) # super()代表父类Frame的定义(而不是父类对象
        self.master = master
        self.pack()                     # 窗口管理器
        self.createWidget()
    
    def createWidget(self):
        """创建组件"""
        # 1、按钮
        self.btn01 = Button(self.master)        # Button(self)也可以运行,但若用place而不是pack则不会显示
        self.btn01["text"] = "点击送花"
        self.btn01["command"] = self.songhua
        self.btn01.pack()
        
        # 2、label显示图片
        global photo
        photo = PhotoImage(file="./test.gif")
        self.label1 = Label(self.master, image=photo)
        # 需将photo定义全局变量或者类变量(如下),否则在:mainloop循环中会销毁,不显示
        # self.photo = PhotoImage(file="./test.gif")
        # self.label1 = Label(self, image=self.photo)
        self.label1.pack()
        
        # 3、退出按钮
        self.btnQuit = Button(self.master, text="退出", command=self.master.destroy)
        self.btnQuit.pack()
        
    def songhua(self):
        messagebox.showinfo("送花", "送你99朵玫瑰花")
    
if __name__ == '__main__':
    root = Tk()
    root.geometry("400x300+200+300")    # 创建窗口,长x宽+距离屏幕左边+距离屏幕右侧
    root.title("一个经典的GUI程序类的测试")
    app = Application(master=root)
    app.mainloop()     # 循环

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python记8(tkinter 的相关文章

  • Python - 将宽字符字符串从二进制文件转换为 Python unicode 字符串

    这是漫长的一天 我有点困惑 我正在读取一个包含大量宽字符字符串的二进制文件 我想将它们转储为 Python unicode 字符串 为了解压非字符串数据 我使用 struct 模块 但我不知道如何对字符串执行相同的操作 例如 阅读 系列 一
  • python 中的代表

    我实现了这个简短的示例来尝试演示一个简单的委托模式 我的问题是 这看起来我已经理解了委托吗 class Handler def init self parent None self parent parent def Handle self
  • python 模拟第三方模块

    我正在尝试测试一些处理推文的类 我使用 Sixohsix twitter 来处理 Twitter API 我有一个类充当 Twitter 类的外观 我的想法是模拟实际的 Sixohsix 类 通过随机生成新推文或从数据库检索它们来模拟推文的
  • 如何使用 Plotly 中的直方图将所有离群值分入一个分箱?

    所以问题是 我可以在 Plotly 中绘制直方图 其中所有大于某个阈值的值都将被分组到一个箱中吗 所需的输出 但使用标准情节Histogram类我只能得到这个输出 import pandas as pd from plotly import
  • Argparse nargs="+" 正在吃位置参数

    这是我的解析器配置的一小部分 parser add argument infile help The file to be imported type argparse FileType r default sys stdin parser
  • 如何在 pytest 中将单元测试和集成测试分开

    根据维基百科 https en wikipedia org wiki Unit testing Description和各种articles https techbeacon com devops 6 best practices inte
  • 从零开始的 numpy 形状意味着什么

    好的 我发现数组的形状中可以包含 0 对于将 0 作为唯一维度的情况 这对我来说是有意义的 它是一个空数组 np zeros 0 但如果你有这样的情况 np zeros 0 100 让我很困惑 为什么这么定义呢 据我所知 这只是表达空数组的
  • 忽略 Mercurial hook 中的某些 Mercurial 命令

    我有一个像这样的善变钩子 hooks pretxncommit myhook python path to file myhook 代码如下所示 def myhook ui repo kwargs do some stuff 但在我的例子中
  • 使用 Python pandas 计算调整后的成本基础(股票买入/卖出的投资组合分析)

    我正在尝试对我的交易进行投资组合分析 并尝试计算调整后的成本基础价格 我几乎尝试了一切 但似乎没有任何效果 我能够计算调整后的数量 但无法获得调整后的购买价格有人可以帮忙吗 这是示例交易日志原始数据 import pandas as pd
  • 如何通过在 Python 3.x 上按键来启动和中断循环

    我有这段代码 当按下 P 键时会中断循环 但除非我按下非 P 键 否则循环不会工作 def main openGame while True purchase imageGrab if a sum gt 1200 fleaButton ti
  • 使用鼻子获取设置中当前测试的名称

    我目前正在使用鼻子编写一些功能测试 我正在测试的库操作目录结构 为了获得可重现的结果 我存储了一个测试目录结构的模板 并在执行测试之前创建该模板的副本 我在测试中执行此操作 setup功能 这确保了我在测试开始时始终具有明确定义的状态 现在
  • 如何解决使用 Spark 从 S3 重新分区大量数据时从内存中逐出缓存的表分区元数据的问题?

    在尝试从 S3 重新分区数据帧时 我收到一个一般错误 Caused by org apache spark SparkException Job aborted due to stage failure Task 33 in stage 1
  • 如何从Python中的字符串中提取变量名称和值

    我有一根绳子 data var1 id 12345 name John White python中有没有办法将var1提取为python变量 更具体地说 我对字典变量感兴趣 这样我就可以获得变量的值 id和name python 这是由提供
  • Seaborn Pairplot 图例不显示颜色

    我一直在学习如何在Python中使用seaborn和pairplot 这里的一切似乎都工作正常 但由于某种原因 图例不会显示相关的颜色 我无法找到解决方案 因此如果有人有任何建议 请告诉我 x sns pairplot stats2 hue
  • 将 matplotlib 颜色图集中在特定值上

    我正在使用 matplotlib 颜色图 seismic 绘制绘图 并且希望白色以 0 为中心 当我在不进行任何更改的情况下运行脚本时 白色从 0 下降到 10 我尝试设置 vmin 50 vmax 50 但在这种情况下我完全失去了白色 关
  • Pandas 根据 diff 列形成簇

    我正在尝试使用 Pandas 根据表示时间 以秒为单位 的列中的差异来消除数据框中的一些接近重复项 例如 import pandas as pd numpy as np df pd DataFrame 1200 1201 1233 1555
  • python Soap zeep模块获取结果

    我从 SOAP API 得到如下结果 client zeep Client wsdl self wsdl transport transport auth header lb E authenticate self login res cl
  • 默认情况下,Keras 自定义层参数是不可训练的吗?

    我在 Keras 中构建了一个简单的自定义层 并惊讶地发现参数默认情况下未设置为可训练 我可以通过显式设置可训练属性来使其工作 我无法通过查看文档或代码来解释为什么会这样 这是应该的样子还是我做错了什么导致默认情况下参数不可训练 代码 im
  • 当鼠标悬停在上面时,intellisense vscode 不显示参数或文档

    我正在尝试将整个工作流程从 Eclipse 和 Jupyter Notebook 迁移到 VS Code 我安装了 python 扩展 它应该带有 Intellisense 但它只是部分更糟糕 我在输入句点后收到建议 但当将鼠标悬停在其上方
  • Scrapy Spider不存储状态(持久状态)

    您好 有一个基本的蜘蛛 可以运行以获取给定域上的所有链接 我想确保它保持其状态 以便它可以从离开的位置恢复 我已按照给定的网址进行操作http doc scrapy org en latest topics jobs html http d

随机推荐

  • java基础语法之学习武林秘籍入门版(由助手完成)

    在这本武侠版本的 Java 入门教程中 我们将会以一个武侠世界为背景来学习 Java 语言的基础知识 我们会介绍如何安装和配置 Java 开发环境 然后通过实例来学习 Java 的基础语法 包括变量 数据类型 运算符 控制流 数组 方法和类
  • Python异常知识讲解

    合适 基础入门 前 这个是最近的一个任务 做好了 所以也放一篇到博客上吧 就是代码我用图片的形式放出来了 不过妨碍学习哈 也不是特别完善 1 理解异常的概念 2 掌握处理异常的几种方式 3 掌握raise和assert语句 会抛出自定义的异
  • ubuntu下修改yaffs2文件系统镜像文件

    原地址 http www tjworld net wiki Linux Kernel SimulateNandMtdDevice 对原博客的修改 将写mtd设备命令 sudo dd if system img of dev mtdblock
  • Qt之使用QPainter自绘实现窗口阴影边框

    一 简述 今天要说的是如何通过自绘的方式实现窗口的阴影边框 在之前的文章里Qt之使用QGraphicsDropShadowEffect添加窗口边框以及文字阴影效果 讲述到使用Qt的 QGraphicsDropShadowEffect类给窗口
  • Java的垃圾回收机制(GC)(无废话版)

    如果无产阶级不能发出自己的声音 他们就会被社会遗忘 Java垃圾回收机制 GC Java程序会主动释放内存空间 这是因为Java虚拟机有一套比较完善的垃圾回收机制又叫GC garbage collection 机制 1 什么是垃圾 简单来讲
  • 深度:从零编写一个微前端框架

    写在开头 手写框架体系文章 缺手写vue和微前端框架文章 今日补上微前端框架 觉得写得不错 记得点个关注 在看 转发更好 对源码有兴趣的 可以看我之前的系列手写源码文章 微前端框架是怎么导入加载子应用的 3000字精读 原创 带你从零看清N
  • Unity Recorder的使用讲解

    Unity Recorder的使用讲解 使用目的 插件下载 插件位置 窗口基本介绍 基本设置选项 录制列表 Animation Clip 参数讲解 Movie 电影模式 参数介绍 Source GameView Targeted Camer
  • APP+springboot订餐APP 毕业设计-附源码190711

    摘 要 随着现在网络的快速发展 网络的应用在各行各业当中它很快融入到了许多学校的眼球之中 他们利用网络来做这个职位推荐的网站 随之就产生了 订餐app 这样就让用户订餐app更加方便简单 对于本订餐app的设计来说 它主要是采用后台采用ja
  • /proc/sys/kernel/printk

    proc sys kernel printk 首先 printk有8个loglevel 定义在
  • telnet远程登录实验配置(Telnet认证有两种模式:AAA模式,密码模式。)

    目录 telnet远程登录 Telnet认证有两种模式 AAA模式 密码模式 password认证模式 AAA认证模式 三 FTP文件传输协议配置 telnet远程登录 Telnet认证有两种模式 AAA模式 密码模式 password认证
  • Node.js 高级篇(三):Mongoose 增删改查

    文章目录 一 mongoose 介绍 Mongoose 有两个特点 二 mongoose 的安装以及使用 2 1 安装 2 2 引入mongoose并连接数据库 2 3 定义Schema 2 4 创建数据模型 2 5 增 2 6 删 2 7
  • React性能分析工具 -React-Performace

    目录 介绍 用途 安装 插件安装 使用 注册观察者 1 安装微服务器
  • 避坑系列1 - 安装Ubuntu & Jenkins, 使用FinalShell

    2023年7月5日 我开始了实验室的工作 首先是要为主机安装Ubuntu 但仍然遇到了一些问题 我在想 今后会遇到许多错误 故障 在某些特定的情境下必然会遇到 比如 用rufus刷镜像时一定会遇到找不到设备的问题 我在网上找了一会才找到答案
  • 面试总结:html5的新特性(十大类)

    这里只以 根目录的方式来说明 详细的见如下连接 https www cnblogs com vicky1018 p 7705223 html 1 语义化标签 好处 1 使代码结构清晰 便于阅读2 便于SEO3 无障碍阅读4 便于后期的维护与
  • 下载多个ts文件,合并为一个mp4文件,并发送到微信

    1 使用internet download manager 来下载ts文件 2 使用tsMuxer来split ts文件 3 VLC media player convert ts to mp4 4 使用MP4Tools将两个ts文件合并
  • windows中的会话概念的总结

    转载请标明是引用于 http blog csdn net chenyujing1234 欢迎大家拍砖 一 参考 http blog csdn net zacklin article details 7579217 以前我一直不理解Windo
  • (三)无人机数据处理算法介绍——目标识别一

    无人机目标识别技术 1 几个相近的概念 图像分割 目标识别 模式识别 目标跟踪 图像分割 根据图像的像素统计特征来对图像进行分割 使得不同类的的图像分开 目标识别 范围广一点 所有的检测目标方法 都可以叫做目标识别 模式识别 当我们采用特定
  • c++ 独一无二的不可拷贝拷贝对象

    方法一 将类的拷贝构造函数和赋值函数只声明 不定义 并定义为 private class A private friend void copy one A const Uncopyable A operator const Uncopyab
  • 简单聊一聊 Spring 事务传播行为和事务隔离级别的那些事

    前言 Spring的事务 也就是数据库的事务操作 符合ACID标准 也具有标准的事务隔离级别 所以Spring的事务隔离级别和事务的传播行为是面试中经常考察的问题 下面简单做下总结 事务并发引发的问题 脏读 一个事务读取到了另一个事务修改但
  • Python记8(tkinter

    目录 1 参考 2 窗口 2 1 创建窗口 Tk 长宽geometry 屏幕宽高 拉伸窗口resizable 窗口名title 循环mainloop 获取窗口大小 2 2 窗口最大化 最小化 正常显示 state iconify attri