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("800×600"),窗口将以默认位置显示。

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

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

tkinter的布局管理器

布局管理器的选择建议

pack: 适用于简单的线性布局(垂直或水平)。

grid: 适用于需要复杂对齐和网格布局的场合。

place: 适合需要精准控制位置和大小的情况,但在窗口大小调整时可能不太灵活。

pack 布局管理器

pack 是最简单的布局管理器,用于将组件按顺序放置在窗口中。组件会依次沿着指定的方向(通常是顶部、底部、左侧或右侧)排列。

pack的基本用法与参数:
widget.pack(
    side='top',      # 停靠方向:'top', 'bottom', 'left', 'right'
    fill='both',     # 填充方式:'x', 'y', 'both', 'none'
    expand=True,     # 是否扩展
    padx=10,         # 外部水平填充
    pady=10,         # 外部垂直填充
    ipadx=5,         # 内部水平填充
    ipady=5,         # 内部垂直填充
    anchor='center'  # 锚点位置:'n','s','w','e','nw','ne','sw','se','center'
)

pack()方法主要参数的说明:
1.side: 控制组件的停靠方向
    't    p': 顶部(默认)
    'b    tt    m': 底部
    'left': 左侧
    'right': 右侧
2.fill: 控制组件的填充方式
    'x': 水平填充
    'y': 垂直填充
    'b    th': 水平和垂直都填充
    'n    ne': 不填充(默认)
3.expand: 是否扩展
    True: 组件会占据额外的可用空间
    False: 组件保持原有大小(默认)
4.padx/pady: 外部填充(像素)
    padx: 水平方向的外部填充
    pady: 垂直方向的外部填充
5.ipadx/ipady: 内部填充(像素)
    ipadx: 水平方向的内部填充
    ipady: 垂直方向的内部填充
6.anch    r: 组件在分配空间内的位置
    'n', 's', 'w', 'e': 上下左右
    'nw', 'ne', 'sw', 'se': 四个角
    'center': 中心(默认)
 

示例源码

import tkinter as tk

root = tk.Tk()
root.geometry('200x100')

button1 = tk.Button(root, text="Button 1")
button2 = tk.Button(root, text="Button 2")
button1.pack(side=tk.TOP, fill=tk.X)
button2.pack(side=tk.BOTTOM)

root.mainloop()

运行效果:

grid 布局管理器

grid 允许将组件放置在一个网格中。你可以指定组件在网格中的行和列位置,使得对齐操作更加灵活。

grid的基本用法与参数:
widget.grid(
    row=0,          # 行号
    column=0,       # 列号
    rowspan=1,      # 跨越的行数
    columnspan=1,   # 跨越的列数
    sticky='nsew',  # 粘性:'n','s','e','w','ns','ew','nsew'
    padx=10,        # 外部水平填充
    pady=10,        # 外部垂直填充
    ipadx=5,        # 内部水平填充
    ipady=5         # 内部垂直填充
)
示例源码

import tkinter as tk

root = tk.Tk()
root.geometry('200x100')

# 配置行列权重
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)

# grid布局示例
label1 = tk.Label(root, text="Name:")
label1.grid(row=0, column=0, padx=5, pady=5)

entry1 = tk.Entry(root)
entry1.grid(row=0, column=1, sticky='ew', padx=5, pady=5)

label2 = tk.Label(root, text="password:")
label2.grid(row=1, column=0, padx=5, pady=5)

entry2 = tk.Entry(root)
entry2.grid(row=1, column=1, sticky='ew', padx=5, pady=5)

root.mainloop()

运行效果:

place 布局管理器

place 允许你精确控制组件位置和大小。这种布局方式需要指定组件的位置(x、y坐标)以及大小(宽度和高度)。

Place的基本用法与参数:
widget.place(
    x=0,            # x坐标
    y=0,            # y坐标
    relx=0.5,       # 相对x位置(0-1)
    rely=0.5,       # 相对y位置(0-1)
    width=100,      # 绝对宽度
    height=100,     # 绝对高度
    relwidth=0.5,   # 相对宽度(0-1)
    relheight=0.5,  # 相对高度(0-1)
    anchor='nw'     # 锚点位置
)
示例源码:

import tkinter as tk

root = tk.Tk()
root.geometry('200x100')

# place布局示例
button1 = tk.Button(root, text="Center")
button1.place(relx=0.5, rely=0.5, anchor='center')

button2 = tk.Button(root, text="Top-Left")
button2.place(x=10, y=10)

root.mainloop()

运行效果:

为文本框添加滚动条

为此先简要介绍本例中用到的控件

Text 控件

Text 控件用于显示和编辑多行文本。它支持文本的格式化和多种功能,如插入、删除、查找等。你可以在 Text 控件中插入文本、图片以及其他控件。常用方法:

insert(index, text): 在指定位置插入文本。其中:index:这是插入点的位置。它可以是一个字符串,表示行号和字符位置的组合(如"1.0"表示第一行的第一个字符),也可以是一个特殊的索引,如"insert"(表示当前插入光标的位置),"end"(表示文本的末尾),或者通过其他方法(如index方法)计算得到的索引。chars:这是要插入的字符串。

delete(start, end): 删除指定范围内的文本。

get(start, end): 获取指定范围内的文本。

tag_config(tag, options): 设置标签样式,可以用于不同格式的文本。

Frame 控件

Frame 控件是一个容器,用于组织和分组其他控件。它可以帮助你布局复杂的界面,并使得管理控件更加灵活。

Scrollbar控件

Scrollbar 是 tkinter 提供的滚动条组件(widget),可以创建垂直(vertical)和水平(horizontal)滚动条。通常与其他可滚动的组件(如 Text, Listbox, Canvas, Treeview 等)配合使用,以查看不可见的部分,它允许用户通过拖动滑块或点击箭头来查看超出可视区域的内容。

源码如下:

import tkinter as tk  
  
root = tk.Tk()  
root.geometry('600x400')  
  
# 创建文本框  
text = tk.Text(root, height=17, width=53, font=("Arial", 14), wrap="none")  
  
# 创建垂直滚动条  
scrollbar_v = tk.Scrollbar(root, orient='vertical', command=text.yview)  
  
# 创建水平滚动条  
scrollbar_h = tk.Scrollbar(root, orient="horizontal", command=text.xview)  
  
# 将滚动条与文本小部件关联  
text['yscrollcommand'] = scrollbar_v.set  
text['xscrollcommand'] = scrollbar_h.set  
  
# 正确的布局顺序
scrollbar_h.pack(side=tk.BOTTOM, fill="x")  # 先放置底部的水平滚动条
text.pack(side=tk.LEFT, fill="both", expand=True)  # 然后是文本框
scrollbar_v.pack(side=tk.RIGHT, fill="y")  # 最后是垂直滚动条

# 插入文本到Text控件中
text.insert("end", "This is a new line.\n")  # 在文本末尾插入新行  
text.insert("insert", "Inserted at current cursor position. ")  # 在当前光标位置插入字符串
  
root.mainloop()

运行效果:

改进版,使用Frame作为容器(把相关的组件组织在一起)来管理布局通常是更好的做法。源码如下:

import tkinter as tk  
  
root = tk.Tk()  
root.geometry('600x400')  

# 创建一个框架来容纳文本框和滚动条
frame = tk.Frame(root)
frame.pack(fill='both', expand=True)
  
# 创建文本框  
text = tk.Text(frame, height=17, width=53, font=("Arial", 14), wrap="none")  
  
# 创建垂直滚动条  
scrollbar_v = tk.Scrollbar(frame, orient='vertical', command=text.yview)  
  
# 创建水平滚动条  
scrollbar_h = tk.Scrollbar(frame, orient="horizontal", command=text.xview)  
  
# 将滚动条与文本小部件关联  
text['yscrollcommand'] = scrollbar_v.set  
text['xscrollcommand'] = scrollbar_h.set  
  
# 使用grid布局管理器(更精确的控制)
scrollbar_v.grid(row=0, column=1, sticky='ns')
scrollbar_h.grid(row=1, column=0, sticky='ew')
text.grid(row=0, column=0, sticky='nsew')

# 配置grid权重,使文本框可以扩展
frame.grid_rowconfigure(0, weight=1)
frame.grid_columnconfigure(0, weight=1)

# 插入文本到Text控件中
text.insert("end", "This is a new line.\n")  # 在文本末尾插入新行  
text.insert("insert", "Inserted at current cursor position. ")  # 在当前光标位置插入字符串
  
root.mainloop()

运行效果:

对话框

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

作者:学习&实践爱好者

物联沃分享整理
物联沃-IOTWORD物联网 » Python青少年简明教程:tkinter库入门

发表回复