You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CustomTkinter中Entry点击显示ScrollableFrame及外部点击隐藏问题排查

问题分析与解决方案

核心问题点

  1. 事件绑定错误:原代码使用<<Button-1>>作为点击事件,这不是Tkinter标准鼠标点击事件,正确的左键点击事件应为<Button-1>
  2. 布局方式不当:用pack放置滚动框架会打乱现有网格布局,应使用place定位到Entry组件下方,保证显示位置合理
  3. 未实现外部点击隐藏:缺少主窗口点击事件监听,无法判断点击区域并自动隐藏框架
  4. 重复创建框架:每次点击Entry都会新建滚动框架,导致界面冗余

修改后的完整代码

import tkinter as tk
import customtkinter as ctk
from tkinter import ttk

def user_window():
    user_window = ctk.CTk()
    user_window.geometry("900x900")
    user_window.title("Sadiq And Antony's Airlines")

    search_ticket_frame = ctk.CTkFrame(user_window, corner_radius=15, width=500, height=250, fg_color="gray")
    search_ticket_frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER)

    # 标签与分隔线部分保留原逻辑
    from_label = ctk.CTkLabel(search_ticket_frame, text="From (Departure)", font=("Arial", 20))
    from_label.grid(row=0, column=0, padx=10, pady=20)

    sep1 = ttk.Separator(search_ticket_frame, orient="vertical")
    sep1.grid(row=0, column=1, sticky="ns", rowspan=2)

    to_label = ctk.CTkLabel(search_ticket_frame, text="To(Arrival)", font=("Arial", 20))
    to_label.grid(row=0, column=2, padx=10, pady=20)
    
    sep2 = ttk.Separator(search_ticket_frame, orient="vertical")
    sep2.grid(row=0, column=3, sticky="ns", rowspan=2)

    d_date = ctk.CTkLabel(search_ticket_frame, text="Departure Date", font=("Arial", 20))
    d_date.grid(row=0, column=4, padx=10, pady=20)

    sep3 = ttk.Separator(search_ticket_frame, orient="vertical")
    sep3.grid(row=0, column=5, sticky="ns", rowspan=2)

    a_date = ctk.CTkLabel(search_ticket_frame, text="Arrival Date", font=("Arial", 20))
    a_date.grid(row=0, column=6, padx=10, pady=20)

    sep4 = ttk.Separator(search_ticket_frame, orient="vertical")
    sep4.grid(row=0, column=7, sticky="ns", rowspan=2)

    n_pass = ctk.CTkLabel(search_ticket_frame, text="Travellers", font=("Arial", 20))
    n_pass.grid(row=0, column=8, padx=10, pady=20)

    sep5 = ttk.Separator(search_ticket_frame, orient="vertical")
    sep5.grid(row=0, column=9, sticky="ns", rowspan=2)

    class_label = ctk.CTkLabel(search_ticket_frame, text="Class", font=("Arial", 20))
    class_label.grid(row=0, column=10, padx=10, pady=20)

    # 全局变量存储滚动框架,方便后续销毁或隐藏
    country_frame = None

    def hide_country_frame(event):
        nonlocal country_frame
        # 判断点击位置是否在Entry或滚动框架外
        if country_frame and not s1.winfo_containing(event.x_root, event.y_root) and not country_frame.winfo_containing(event.x_root, event.y_root):
            country_frame.destroy()
            country_frame = None

    def display_countries(event):
        nonlocal country_frame
        # 如果已有框架,先销毁避免重复显示
        if country_frame:
            country_frame.destroy()
        # 获取Entry组件的屏幕坐标,定位滚动框架到Entry下方
        x = s1.winfo_rootx()
        y = s1.winfo_rooty() + s1.winfo_height()
        country_frame = ctk.CTkScrollableFrame(user_window, corner_radius=10, width=200, height=200)
        country_frame.place(x=x, y=y)

        countries = ["Country 1", "Country 2", "Country 3", "Country 4", "Country 5", "Country 6", "Country 7", "Country 8", "Country 9", "Country 10"]
        for country in countries:
            # 绑定单选按钮点击事件,选择后更新Entry内容并隐藏框架
            def select_country(country_name=country):
                s1.delete(0, tk.END)
                s1.insert(0, country_name)
                country_frame.destroy()
                nonlocal country_frame
                country_frame = None
            radio_btn = ctk.CTkRadioButton(country_frame, text=country, font=("Arial", 16), command=lambda c=country: select_country(c))
            radio_btn.pack(fill=tk.X, padx=5, pady=2)

    s1 = ctk.CTkEntry(search_ticket_frame, placeholder_text="Your Choice", font=("Arial",20), width=200)
    s1.grid(row=1, column=0, padx=30)
    # 绑定正确的鼠标左键点击事件
    s1.bind("<Button-1>", display_countries)
    # 给主窗口绑定点击事件,实现外部点击隐藏功能
    user_window.bind("<Button-1>", hide_country_frame)

    user_window.mainloop()

user_window()

关键修改说明

  • 修正事件绑定:将错误的<<Button-1>>改为Tkinter标准的<Button-1>事件
  • 精准定位框架:通过winfo_rootx()和winfo_rooty()获取Entry的屏幕坐标,用place将滚动框架放在Entry正下方,避免干扰原有布局
  • 外部点击隐藏:给主窗口绑定点击事件,通过winfo_containing()判断点击区域,若不在Entry或滚动框架内则销毁框架
  • 避免重复创建:用变量存储滚动框架实例,每次点击Entry前先销毁旧框架
  • 单选按钮交互优化:给每个单选按钮添加点击事件,选择后自动更新Entry内容并隐藏框架

内容的提问来源于stack exchange,提问作者Sadiq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 03:02:11