第三节:控件与交互——Button、Label、Entry、Text实战

好,咱们直接进入正题。这一节我们要做一个最简单的登录界面。别小看它,登录框是几乎所有桌面应用和Web应用的标配。你想想看,你每天打开、邮箱、各种系统,第一眼看到的是什么?就是登录界面。

我个人习惯,学任何GUI框架,第一个实战项目就是登录界面。为什么?因为它涵盖了最核心的四个控件:Label(标签)、Entry(输入框)、Button(按钮)、Text(文本区域)。这四个控件用好了,你就能搞定80%的界面交互需求。

3.1 四个核心控件,各司其职

先简单过一遍这四个控件是干什么的。我当年刚学的时候,总把Label和Text搞混,后来踩了坑才明白——它们完全是两码事。

控件 作用 典型场景
Label 显示静态文本,用户不能修改 提示文字、标题、状态显示
Entry 单行文本输入框 用户名、密码、搜索框
Button 可点击的按钮,触发事件 登录、注册、取消、提交
Text 多行文本区域,可编辑 日志输出、留言板、协议展示

核心区别:Entry只能输入一行,Text可以输入多行。Label只能看不能改,Entry和Text既能看又能改。Button是唯一能触发动作的控件。

3.2 实战:手写一个登录界面

好,咱们直接上代码。我会带着你一步步写,每行代码我都会解释为什么这么写。

先创建一个Python文件,叫 login_demo.py。然后敲下面的代码:

import tkinter as tk
from tkinter import messagebox

# 创建主窗口
root = tk.Tk()
root.title("登录界面")
root.geometry("400x300")
root.resizable(False, False)  # 固定窗口大小,不让用户乱拉

# 用户名区域
tk.Label(root, text="用户名:", font=("微软雅黑", 12)).place(x=50, y=60)
entry_username = tk.Entry(root, font=("微软雅黑", 12), width=20)
entry_username.place(x=150, y=60)

# 密码区域
tk.Label(root, text="密  码:", font=("微软雅黑", 12)).place(x=50, y=110)
entry_password = tk.Entry(root, font=("微软雅黑", 12), width=20, show="*")
entry_password.place(x=150, y=110)

# 登录按钮
def login():
    username = entry_username.get()
    password = entry_password.get()
    if username == "admin" and password == "123456":
        messagebox.showinfo("登录成功", "欢迎回来,管理员!")
    else:
        messagebox.showerror("登录失败", "用户名或密码错误")

btn_login = tk.Button(root, text="登录", font=("微软雅黑", 12),
                      command=login, bg="#4CAF50", fg="white")
btn_login.place(x=150, y=170)

# 运行主循环
root.mainloop()

嗯,这里要注意几个细节。我一个个说。

3.3 代码拆解:每一行都有讲究

第一,窗口设置。

root.resizable(False, False) 这行很多人会忽略。我曾经做过一个项目,用户反馈说「你们的登录窗口怎么可以拉成一条线?」——就是因为没锁窗口大小。你想想看,登录界面就那么几个控件,让用户随意拉伸,界面会变得很难看。所以,登录窗口一定要固定大小。

第二,密码输入框的 show 参数。

show="*" 这个参数是Entry独有的。它会把输入的内容显示成星号。我见过新手用Label来显示密码输入,结果密码明文显示在屏幕上——这要是被旁边的人看到,那可就尴尬了。

第三,按钮的 command 参数。

这是事件驱动的核心。按钮被点击时,会调用 login() 函数。注意,这里写的是 command=login,不是 command=login()。多了括号,函数会在创建按钮时立即执行,而不是等点击时才执行。这个坑我踩过不止一次。

小技巧:如果你想让按钮点击时传递参数,可以用 lambda。比如 command=lambda: login("admin")。这是Python闭包的经典用法,面试也常考。

3.4 事件驱动:按钮点击背后发生了什么

好,现在我们来聊聊「事件驱动」这个概念。说白了,就是程序在等待用户操作。用户不点按钮,程序就什么都不做。用户一点,程序立刻响应。

为什么会这样?因为 root.mainloop() 这个函数开启了一个事件循环。它就像一个大管家,24小时盯着屏幕,一旦检测到鼠标点击、键盘输入,就立刻去执行对应的回调函数。

我画了一张图,帮你理解这个流程:

事件循环 mainloop() 用户操作 (点击按钮/输入文字) 事件分发 (找到对应的回调函数) 执行回调函数

这张图很直观。事件循环一直在后台跑着,用户一操作,它就捕获事件、分发事件、执行回调。整个过程一气呵成,毫秒级完成。

3.5 进阶:用Text控件显示日志

登录成功或失败,光弹个消息框太单调了。我们加一个Text控件,把操作日志显示出来。这样用户能看到「刚才发生了什么」。

# 在登录按钮下方加一个文本区域
log_text = tk.Text(root, font=("微软雅黑", 10), width=40, height=6,
                   state="disabled")  # 初始状态不可编辑
log_text.place(x=50, y=220)

def login():
    username = entry_username.get()
    password = entry_password.get()
    
    # 启用Text控件,写入日志,再禁用
    log_text.config(state="normal")
    if username == "admin" and password == "123456":
        log_text.insert(tk.END, f"[{get_time()}] 登录成功\n")
        messagebox.showinfo("登录成功", "欢迎回来,管理员!")
    else:
        log_text.insert(tk.END, f"[{get_time()}] 登录失败:用户名或密码错误\n")
        messagebox.showerror("登录失败", "用户名或密码错误")
    log_text.config(state="disabled")
    log_text.see(tk.END)  # 自动滚动到底部

def get_time():
    from datetime import datetime
    return datetime.now().strftime("%H:%M:%S")

注意:Text控件默认是可编辑的。如果你只想用它显示日志,一定要设置 state="disabled"。写入日志时先改成 normal,写完后立刻改回 disabled。否则用户可以在日志区域乱打字,那画面太美我不敢看。

3.6 避坑指南:我踩过的那些坑

做这个登录界面,有几个坑我当年都踩过,分享给你,省得你重走弯路。

  • Entry的get()方法返回空字符串——最常见的问题。原因往往是你在窗口还没显示完就去取值。记住,一定要在事件回调里取值,不要在创建控件后立刻取值。
  • 密码显示为明文——忘了加 show="*"。我有个同事因为这个被客户投诉了,说「你们的密码框是透明的吗?」
  • 按钮点击没反应——检查 command 参数有没有写括号。写了括号,函数在创建时执行,返回值赋给command,而不是函数本身。
  • Text控件内容越写越多——如果不清理,日志会无限增长。建议加个限制,比如只保留最近100行。

3.7 完整代码整合

好,把上面所有代码整合到一起,就是一个完整的登录界面了。我建议你亲手敲一遍,不要复制粘贴。敲代码的过程,就是肌肉记忆形成的过程。

import tkinter as tk
from tkinter import messagebox
from datetime import datetime

root = tk.Tk()
root.title("登录界面")
root.geometry("400x350")
root.resizable(False, False)

# 用户名
tk.Label(root, text="用户名:", font=("微软雅黑", 12)).place(x=50, y=40)
entry_username = tk.Entry(root, font=("微软雅黑", 12), width=20)
entry_username.place(x=150, y=40)

# 密码
tk.Label(root, text="密  码:", font=("微软雅黑", 12)).place(x=50, y=90)
entry_password = tk.Entry(root, font=("微软雅黑", 12), width=20, show="*")
entry_password.place(x=150, y=90)

# 日志区域
log_text = tk.Text(root, font=("微软雅黑", 10), width=40, height=6, state="disabled")
log_text.place(x=50, y=200)

def get_time():
    return datetime.now().strftime("%H:%M:%S")

def login():
    username = entry_username.get()
    password = entry_password.get()
    log_text.config(state="normal")
    if username == "admin" and password == "123456":
        log_text.insert(tk.END, f"[{get_time()}] 登录成功\n")
        messagebox.showinfo("登录成功", "欢迎回来,管理员!")
    else:
        log_text.insert(tk.END, f"[{get_time()}] 登录失败:用户名或密码错误\n")
        messagebox.showerror("登录失败", "用户名或密码错误")
    log_text.config(state="disabled")
    log_text.see(tk.END)

# 登录按钮
btn_login = tk.Button(root, text="登录", font=("微软雅黑", 12),
                      command=login, bg="#4CAF50", fg="white")
btn_login.place(x=150, y=150)

root.mainloop()

运行这段代码,你会看到一个完整的登录界面。输入 admin 和 123456,点击登录,看看效果。

总结一下:这一节我们做了三件事——第一,学会了Label、Entry、Button、Text四个控件的用法;第二,理解了事件驱动的核心机制;第三,亲手写了一个带日志功能的登录界面。这些基础打牢了,后面做复杂界面就会轻松很多。

可可精品资料库