Python青少年简明教程:tkinter库入门

Python青少年简明教程:tkinter库入门

tkinter是Python的标准GUI(图形用户界面)库。它提供了一种快速而简单的方法来创建GUI应用程序。tkinter是Python自带的,无需额外安装,随 Python 安装包一起提供。

在Python 3.x中,库名称是tkinter, 跨平台——在 Windows、macOS 和 Linux 上都可以使用,使得用 Tkinter 编写的程序可以在不同操作系统上运行。

tkinter基于事件驱动编程模型,它提供了一组小部件(如按钮、标签、文本框等)和几何管理器(如pack、grid、place)来组织用户界面,适合构建简单的桌面应用程序。

基本概念

窗口(Window):Tkinter应用程序的基本组件之一,表示一个包含菜单栏、工具栏、状态栏以及主体区域的窗口。窗口可以通过Tk()或Toplevel()方法创建,其中Tk()方法创建的是应用程序的主窗口,而Toplevel()方法创建的是一个独立的子窗口。

tkinter的窗口可以通过Tk()或Toplevel()方法创建,两者区别:

Tk() 用于创建应用程序的主窗口——用于创建应用程序的主界面。这是应用程序的根窗口。通常每个应用程序只有一个Tk()实例。关闭Tk()窗口会结束整个应用程序,所有Toplevel窗口也会销毁。Tk()包含主事件循环(mainloop())。

Toplevel()用于创建子窗口或额外的窗口——常用于创建对话框、额外的信息窗口或功能窗口。通常需要一个父窗口作为参数(通常是Tk()实例或另一个Toplevel()实例)。可以创建多个Toplevel()窗口。关闭Toplevel()窗口只会关闭该特定窗口,不会影响主窗口或其他Toplevel窗口。Toplevel()不包含自己的事件循环,依赖于Tk()的主事件循环。

示例:

# Tkinter中的Tk()和Toplevel()创建的窗口区别演示
import tkinter as tk

# 使用Tk()创建主窗口
root = tk.Tk()
root.title("主窗口 (Tk)")
root.geometry("300x200")

# 创建一个按钮来打开Toplevel窗口
def open_toplevel():
    # 使用Toplevel()创建子窗口
    top = tk.Toplevel(root)
    top.title("子窗口 (Toplevel)")
    top.geometry("250x150")
    tk.Label(top, text="这是一个Toplevel窗口").pack(pady=20)

tk.Button(root, text="打开Toplevel窗口", command=open_toplevel).pack(pady=50)

tk.Label(root, text="这是主Tk窗口").pack()

root.mainloop()

对 Tkinter 的支持分布在多个模块中。 大多数应用程序将需要主模块 tkinter(也称为tk)和tkinter.ttk,也成为 ttk(themed tk),后者从tkinter 8.5开始可用。ttk组件多于tkinter,界面也相对漂亮,所以使用时尽量选择ttk。按照以下方式导入,ttk中的widget(组件、小部件、控件)会默认替换掉tk的。

import tkinter as tk

from tkinter import ttk

大多数应用程序都需要同时使用这两个模块。一些常见的小部件在 tk 和 ttk 中都有实现,但 ttk 版本通常更为现代。

ttk(themed tk)是对基本 tkinter 的增强:

    提供了更多的组件;

    界面相对更现代和美观;

    支持主题,使应用程序在不同平台上具有一致的外观。

特别提示,tkinte文档中使用的widgets,在许多不同的翻译:组件、小部件、控件,一般译为小部件,相当于某些开发语言的Components(组件)、controls(控件)。这些术语可以互换使用,但在 tkinter 上下文中,“小部件”或“控件”可能更为常见。

ttk 和 tkinter (tk) 共有的和各自独有的小部件 (widgets)

一些常见的小部件在 tk 和 ttk 中都有实现,但 ttk 版本通常更为现代。

ttk 和 tkinter 都提供了以下基本小部件:

Button(按钮)

Label(标签)

Entry(输入框)

Frame(框架)

Checkbutton(复选框)

Radiobutton(单选按钮)

Scale(滑块)

Scrollbar(滚动条)

tkinter (tk) 独有的小部件:

Menu(菜单)

Canvas(画布)

Text(文本框)

Message(消息框):用于显示多行文本

Spinbox(数值调节框):允许用户从一系列值中选择

ttk 独有的小部件:

Combobox(组合框):结合了 Entry 和下拉列表

Notebook(笔记本):用于创建选项卡式界面

Progressbar(进度条):显示任务进度

Separator(分隔符):用于分隔其他小部件

Sizegrip(大小调整手柄):允许用户调整窗口大小

Treeview(树状视图):用于显示层次化数据

事件循环

tkinter 应用程序通常运行在一个事件循环中,等待用户交互并响应事件。tkinter 允许你通过绑定事件来响应用户交互。

tkinter 提供了几种布局管理器来控制 widgets 的位置和大小:

pack:按照上、下、左、右方向逐步排列widgets。

grid:使用网格系统布局 widgets。

place:精确控制 widgets 的位置和大小。

tkinter程序的基本结构

一个最简单的 tkinter 程序确实应该包含以下四个主要部分:

    导入 tkinter 模块

    创建主窗口(root 窗口)

    添加人机交互控件和相应的事件函数

启动主循环(mainloop)

以下是一个包含多个 widgets 和事件处理的简单较完整的示例:

import tkinter as tk
from tkinter import messagebox

# 事件处理函数
def on_button_click():
    messagebox.showinfo("Info", "Button clicked!")

# 创建主窗口
root = tk.Tk()
# 设置窗口大小为宽300像素,高200像素  
root.geometry("300x200")  
# 设置窗口标题
root.title("Tkinter Example")

# 创建标签
label = tk.Label(root, text="Hello, Tkinter!")
label.pack()

# 创建按钮,绑定事件处理函数
button = tk.Button(root, text="Click Me", command=on_button_click)
button.pack()

# 进入主事件循环
root.mainloop()

上面示例运行效果:

geometry方法用于设置窗口的大小和位置。它允许开发者定义窗口的宽度、高度以及在屏幕上的位置。以像素为单位。

geometry 方法的常规格式如下:

窗口.geometry("宽度x高度+偏移X+偏移Y")

其中 +偏移x+偏移y 部分是可选的。

注意事项

如果仅指定窗口大小,例如 窗口.geometry("800x600"),窗口将以默认位置显示。

如果仅指定位置,例如 窗口.geometry("+100+100"),窗口的大小将保持默认。

如果设置的大小超出了屏幕的可视范围,窗口可能会部分不可见。

对话框

tkinter提供了多种预定义的对话框子模块:

messagebox:显示消息或警告

filedialog:文件选择对话框

colorchooser:颜色选择对话框

messagebox、filedialog和colorchooser都tkinter 的子模块

messagebox 是 tkinter 的一个子模块,用于创建消息对话框。

    导入方式:from tkinter import messagebox

    主要功能:显示信息、警告或错误消息,以及获取简单的用户输入(如是/否选择)。

    常用函数:showinfo(), showwarning(), showerror(), askyesno() 等。

例如:
from tkinter import messagebox
messagebox.showinfo("信息", "这是一条信息")
result = messagebox.askyesno("确认", "您确定要继续吗?")

filedialog 是 tkinter 的另一个子模块,用于创建文件选择对话框。

    导入方式:from tkinter import filedialog

    主要功能:允许用户选择文件或目录。

    常用函数:askopenfilename(), asksaveasfilename(), askdirectory() 等。

例如:
from tkinter import filedialog
filename = filedialog.askopenfilename(title="选择文件", filetypes=(("文本文件", "*.txt"), ("所有文件", "*.*")))

colorchooser 是 tkinter 的子模块,用于创建颜色选择对话框。

    导入方式:from tkinter import colorchooser

    主要功能:允许用户选择颜色。

    主要函数:askcolor()

例如:
from tkinter import colorchooser
color = colorchooser.askcolor(title="选择颜色")
 

以下是一个综合使用这些子模块的简单较完整的示例:

import tkinter as tk
from tkinter import messagebox, filedialog, colorchooser

def show_message():
    messagebox.showinfo("信息", "这是一条信息")

def choose_file():
    filename = filedialog.askopenfilename(title="选择文件", filetypes=(("文本文件", "*.txt"), ("所有文件", "*.*")))
    if filename:
        messagebox.showinfo("文件选择", f"您选择的文件是:{filename}")

def choose_color():
    color = colorchooser.askcolor(title="选择颜色")
    if color[1]:  # color is None if dialog is cancelled
        messagebox.showinfo("颜色选择", f"您选择的颜色是:{color[1]}")

root = tk.Tk()
root.geometry("300x200") 
root.title("tkinter 对话框示例")

tk.Button(root, text="显示消息", command=show_message).pack(pady=5)
tk.Button(root, text="选择文件", command=choose_file).pack(pady=5)
tk.Button(root, text="选择颜色", command=choose_color).pack(pady=5)

root.mainloop()

运行效果:

Menu和MenuButton

Menu 和 MenuButton 都是 tkinter 提供的控件类。

Menu 是 tkinter 中用于创建菜单栏、下拉菜单和弹出菜单的类。

    用于创建各种类型的菜单,包括顶级菜单栏、下拉菜单和上下文菜单。

    可以包含命令、子菜单、复选框菜单项等。

通常用于创建应用程序的主菜单栏。

MenuButton 是 tkinter 中的一个控件类,用于创建一个带有相关联的下拉菜单的按钮。

    是一个结合了按钮和菜单功能的控件。

    点击 MenuButton 会显示一个下拉菜单。

    常用于工具栏或需要节省空间的界面设计。

示例:

import tkinter as tk

def do_command():
    print("Command executed!")

root = tk.Tk()
root.geometry("300x200") 
root.title("Menu 和 MenuButton 示例")

# 创建顶级菜单栏
menubar = tk.Menu(root)
root.config(menu=menubar)

# 创建 "File" 菜单
file_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="File", menu=file_menu)
file_menu.add_command(label="New", command=do_command)
file_menu.add_command(label="Open", command=do_command)
file_menu.add_separator()
file_menu.add_command(label="Exit", command=root.quit)

# 创建 MenuButton
mb = tk.Menubutton(root, text="Options", relief=tk.RAISED)
mb.pack(padx=10, pady=10)

# 为 MenuButton 创建菜单
mb_menu = tk.Menu(mb, tearoff=0)
mb["menu"] = mb_menu
mb_menu.add_command(label="Option 1", command=do_command)
mb_menu.add_command(label="Option 2", command=do_command)

root.mainloop()

运行效果:

Canvas(画布)小部件

canvas 是 tkinter 中的一个小部件,因其功能强大,常被单独讨论。

它是 tkinter 的一部分,不需要单独导入。

提供了一个绘图区域,可以在其中创建线条、形状、文本和图像等。

常用于创建自定义图形、图表或动画。

以下是一些常用的 Canvas 方法:

create_line(x1, y1, x2, y2, options):绘制一条从 (x1, y1) 到 (x2, y2) 的直线。

create_rectangle(x1, y1, x2, y2, options):绘制一个矩形。

create_oval(x1, y1, x2, y2, options):绘制一个椭圆。

create_text(x, y, text, options):在指定位置显示文本。

create_image(x, y, image, options):在指定位置显示图像。

delete(what):删除指定的图形项。

move(tagOrId, x, y):移动指定的图形项。

bind(sequence, func):绑定事件处理程序。

示例:

import tkinter as tk
from tkinter import PhotoImage

# 创建主窗口
root = tk.Tk()
root.title("Tkinter Canvas Example")

# 创建 Canvas 组件
canvas = tk.Canvas(root, width=400, height=300, bg="white")
canvas.pack()

# 绘制直线
canvas.create_line(10, 20, 200, 20, fill="blue", width=2)

# 绘制矩形
canvas.create_rectangle(50, 50, 150, 150, outline="black", fill="yellow", width=2)

# 绘制椭圆
canvas.create_oval(100, 100, 250, 200, outline="green", fill="red", width=2)

# 显示文本
canvas.create_text(200, 50, text="Hello Canvas", font=("Arial", 16))

# 加载图像并显示
try:
    img = PhotoImage(file="example.png")  # 确保你有一个名为 example.png 的图像文件
    canvas.create_image(300, 300, image=img, anchor="center")
except tk.TclError:
    print("Image file not found or cannot be loaded.")

# 定义事件处理程序
def on_click(event):
    print(f"Canvas clicked at ({event.x}, {event.y})")

# 绑定点击事件
canvas.bind("<Button-1>", on_click)

# 进入主事件循环
root.mainloop()

运行效果:

ttk(主题Tkinter小部件)

ttk(Themed Tkinter Widgets)是 tkinter 的一个扩展,提供了访问 Tk 主题小部件集的接口。ttk 提供了一组主题化的小部件,相比 Tkinter 的传统小部件,ttk 小部件具有更多的功能和更好的外观。

完整导入路径:from tkinter import ttk

提供了与 tkinter 相似但外观更现代的小部件。

ttk 小部件可以使用主题,使得应用程序在不同平台上具有一致的外观。

常用的 ttk 控件

ttk 提供了一些与 Tkinter 传统控件对应的改进版本:

ttk.Button:改进版的按钮控件。

ttk.Label:改进版的标签控件。

ttk.Entry:改进版的单行文本输入控件。

ttk.Text:改进版的多行文本输入控件。

ttk.Checkbutton:改进版的复选框控件。

ttk.Radiobutton:改进版的单选按钮控件。

ttk.Combobox:下拉组合框控件。

ttk.Treeview:树状视图控件。

ttk.Notebook:选项卡控件。

以下是一个使用 ttk 控件的简单示例,展示了如何创建和使用 ttk 控件:

import tkinter as tk
from tkinter import ttk

# 创建主窗口
root = tk.Tk()
root.geometry("300x200") 
root.title("TTK Widgets Example")

# 创建 ttk 样式
style = ttk.Style()
style.configure("TButton", padding=6, relief="flat", background="#ccc")

# 创建 ttk 按钮
button = ttk.Button(root, text="Click Me")
button.pack(pady=10)

# 创建 ttk 标签
label = ttk.Label(root, text="Hello, TTK!")
label.pack(pady=10)

# 创建 ttk 组合框
combo = ttk.Combobox(root, values=["Option 1", "Option 2", "Option 3"])
combo.pack(pady=10)

# 进入主事件循环
root.mainloop()

运行效果:

下面给使用tkinter库创建的小游戏:简单的弹球游戏,在画布上生成一个蓝色的小球随机运动,小球碰到边缘会反弹,底部有一红色的挡板,玩家可以使用左右方向键控制它,挡板接到小球时会反弹,玩家得分1分,小球落到球拍下方扣1分。源码如下:

import tkinter as tk
import random

# 初始化Tkinter窗口
window = tk.Tk()
window.title("弹球游戏")

# 创建画布
canvas_width = 800
canvas_height = 600
canvas = tk.Canvas(window, width=canvas_width, height=canvas_height, bg="white")
canvas.pack()

# 球体参数
ball_radius = 20
ball_x = random.randint(ball_radius, canvas_width - ball_radius)
ball_y = random.randint(ball_radius, canvas_height - ball_radius)
ball_dx = random.randint(2, 8)
ball_dy = random.randint(2, 8)
ball = canvas.create_oval(ball_x - ball_radius, ball_y - ball_radius,
                         ball_x + ball_radius, ball_y + ball_radius, fill="blue")

# 挡板参数
paddle_width = 100
paddle_height = 20
paddle_x = canvas_width // 2 - paddle_width // 2
paddle_y = canvas_height - paddle_height - 10
paddle = canvas.create_rectangle(paddle_x, paddle_y,
                                 paddle_x + paddle_width, paddle_y + paddle_height, fill="red")

# 玩家得分
score = 0

# 移动球体的函数
def move_ball():
    global ball_x, ball_y, ball_dx, ball_dy, score
    
    # 更新球体位置
    ball_x += ball_dx
    ball_y += ball_dy
    
    # 检测边缘碰撞
    if ball_x <= ball_radius or ball_x >= canvas_width - ball_radius:
        ball_dx *= -1
    if ball_y <= ball_radius or ball_y >= canvas_height - ball_radius:
        ball_dy *= -1
    
    # 检测挡板碰撞
    paddle_coords = canvas.coords(paddle)
    if ball_y + ball_radius >= paddle_coords[1] and \
       ball_x >= paddle_coords[0] and ball_x <= paddle_coords[2]:
        ball_dy *= -1
        score += 1
        canvas.itemconfig(score_text, text=f"Score: {score}")
    elif ball_y + ball_radius >= canvas_height:
        score -= 1
        canvas.itemconfig(score_text, text=f"Score: {score}")
    
    # 更新球体位置
    canvas.coords(ball, ball_x - ball_radius, ball_y - ball_radius,
                  ball_x + ball_radius, ball_y + ball_radius)
    
    # 调用下一帧
    window.after(30, move_ball)

# 控制挡板的函数
def move_paddle(event):
    global paddle_x
    
    if event.keysym == "Left" and paddle_x > 0:
        paddle_x -= 10
    elif event.keysym == "Right" and paddle_x < canvas_width - paddle_width:
        paddle_x += 10
    
    canvas.coords(paddle, paddle_x, paddle_y,
                  paddle_x + paddle_width, paddle_y + paddle_height)

# 创建分数显示
score_text = canvas.create_text(50, 20, anchor="nw", text="Score: 0")

# 绑定左右键事件
window.bind("<Left>", move_paddle)
window.bind("<Right>", move_paddle)

# 开始游戏循环
move_ball()

# 进入主循环
window.mainloop()

下面改用使用类(面向对象编程)实现,源码如下

import tkinter as tk
import random

class BouncingBallGame:
    def __init__(self, root):
        self.root = root
        self.root.title("弹球游戏")

        # 创建画布
        self.canvas_width = 800
        self.canvas_height = 600
        self.canvas = tk.Canvas(root, width=self.canvas_width, height=self.canvas_height, bg="white")
        self.canvas.pack()

        # 球体参数
        self.ball_radius = 20
        self.ball_x = random.randint(self.ball_radius, self.canvas_width - self.ball_radius)
        self.ball_y = random.randint(self.ball_radius, self.canvas_height - self.ball_radius)
        self.ball_dx = random.randint(2, 8)
        self.ball_dy = random.randint(2, 8)
        self.ball = self.canvas.create_oval(self.ball_x - self.ball_radius, self.ball_y - self.ball_radius,
                                             self.ball_x + self.ball_radius, self.ball_y + self.ball_radius, fill="blue")

        # 挡板参数
        self.paddle_width = 100
        self.paddle_height = 20
        self.paddle_x = self.canvas_width // 2 - self.paddle_width // 2
        self.paddle_y = self.canvas_height - self.paddle_height - 10
        self.paddle = self.canvas.create_rectangle(self.paddle_x, self.paddle_y,
                                                   self.paddle_x + self.paddle_width, self.paddle_y + self.paddle_height, fill="red")

        # 玩家得分
        self.score = 0
        self.score_text = self.canvas.create_text(50, 20, anchor="nw", text="Score: 0")

        # 绑定左右键事件
        self.root.bind("<Left>", self.move_paddle)
        self.root.bind("<Right>", self.move_paddle)

        # 启动游戏循环
        self.move_ball()

    def move_ball(self):
        # 更新球体位置
        self.ball_x += self.ball_dx
        self.ball_y += self.ball_dy

        # 检测边缘碰撞
        if self.ball_x <= self.ball_radius or self.ball_x >= self.canvas_width - self.ball_radius:
            self.ball_dx *= -1
        if self.ball_y <= self.ball_radius or self.ball_y >= self.canvas_height - self.ball_radius:
            self.ball_dy *= -1

        # 检测挡板碰撞
        paddle_coords = self.canvas.coords(self.paddle)
        if self.ball_y + self.ball_radius >= paddle_coords[1] and \
           self.ball_x >= paddle_coords[0] and self.ball_x <= paddle_coords[2]:
            self.ball_dy *= -1
            self.score += 1
            self.canvas.itemconfig(self.score_text, text=f"Score: {self.score}")
        elif self.ball_y + self.ball_radius >= self.canvas_height:
            self.score -= 1
            self.canvas.itemconfig(self.score_text, text=f"Score: {self.score}")

        # 更新球体位置
        self.canvas.coords(self.ball, self.ball_x - self.ball_radius, self.ball_y - self.ball_radius,
                           self.ball_x + self.ball_radius, self.ball_y + self.ball_radius)

        # 调用下一帧
        self.root.after(30, self.move_ball)

    def move_paddle(self, event):
        if event.keysym == "Left" and self.paddle_x > 0:
            self.paddle_x -= 10
        elif event.keysym == "Right" and self.paddle_x < self.canvas_width - self.paddle_width:
            self.paddle_x += 10

        self.canvas.coords(self.paddle, self.paddle_x, self.paddle_y,
                           self.paddle_x + self.paddle_width, self.paddle_y + self.paddle_height)

if __name__ == "__main__":
    root = tk.Tk()
    game = BouncingBallGame(root)
    root.mainloop()

附录

Python 官方文档中的 Tkinter 参考 https://docs.python.org/zh-cn/3/library/tkinter.html

Python 的Tkinter包系列之一:窗口初步https://blog.csdn.net/cnds123/article/details/127227651

Python 的Tkinter包系列之二:菜单 https://blog.csdn.net/cnds123/article/details/127319885

Python 的Tkinter包系列之三:Canvas (画布)https://blog.csdn.net/cnds123/article/details/127344534

Python 的Tkinter包系列之四:对话框https://blog.csdn.net/cnds123/article/details/127392512

Python 的Tkinter包系列之五:事件https://blog.csdn.net/cnds123/article/details/127411016

Python 的Tkinter包系列之六:好例子https://blog.csdn.net/cnds123/article/details/127487982

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

学习&实践爱好者

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

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

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

打赏作者

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

抵扣说明:

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

余额充值