zqh0922 2024-01-16 20:32 采纳率: 0%
浏览 18
已结题

python tkinter toplevel窗体最小化问题

img

img

点击entry,弹出下拉框(toplevel窗体),但是当我最小化主窗体时,下拉框并没有跟随最小化而是留在原来的位置,请问怎样处理才能跟随主窗体最小化一起隐藏呢?

from tkinter import Frame, Listbox, Scrollbar, StringVar, Toplevel  # , Tk,Entry,
# from tkinter.constants import END, EW, HORIZONTAL, NS
import ttkbootstrap as ttk
from ttkbootstrap.constants import *

my_str = ['', '', '', '', '', '']
# global my_bool_hide
my_bool_hide = False  # 判断顶置窗口是否隐藏,默认隐藏


def singleton(cls, *args, **kwargs):
    instances = {}

    def _singleton():
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]

    return _singleton


@singleton
class ListBox(object):
    """ListBox Class"""

    def __init__(self):
        self.top_window = None

    def init(self, width):
        self.width = width

    def my_show(self, p_master, values, master, my_levels):
        self.p_master = p_master
        self.master = master
        self.values = values
        self.my_levels = my_levels
        if self.top_window:
            return

        x = self.master.winfo_rootx()
        y = self.master.winfo_rooty() + self.master.winfo_height()
        # self.top_window = Toplevel(self.master)
        self.top_window = Toplevel(self.master)   # winfo_toplevel
        # self.top_window.
        ####################
        # self.top_window.grab_set()
        # self.top_window.transient(self.master.master.master.master.master.master.master)
        ######################
        self.top_window.overrideredirect(1)
        self.top_window.geometry("+%d+%d" % (x, y))
        self.top_window.bind('<Configure>', self.on_change_geometry)
        self.top_window.bind_all("<Button-1>", self.on_gloabl_click)  # <ButtonRelease-1>
        # self.top_window.bind_all("<ButtonRelease-1>", self.on_gloabl_click)  # <ButtonRelease-1>
        # self.top_window.bind("<FocusOut>", self.on_focus_out)

        self.sb_y = Scrollbar(self.top_window)
        self.sb_x = Scrollbar(self.top_window, orient=HORIZONTAL)
        # self.sb_x.grid(row=1, column=0, sticky=EW)
        self.sb_x.pack(fill=X)
        self.list_box = Listbox(self.top_window,
                                xscrollcommand=self.sb_x.set,
                                yscrollcommand=self.sb_y.set,
                                width=self.width)
        for data in self.values:
            self.list_box.insert(END, data)
        if self.p_master.input_var.get() != '' and self.p_master.input_var.get() in self.values:
            index = self.values.index(self.p_master.input_var.get())
        else:
            index = 0
        self.list_box.select_set(index)
        self.list_box.bind("<ButtonRelease-1>", self.on_click_item)
        self.sb_x.config(command=self.list_box.xview)
        self.sb_y.config(command=self.list_box.yview)
        # self.sb_y.grid(row=0, column=1, sticky=NS)
        self.sb_y.pack(fill=Y, anchor=E, side='right')
        # self.sb_x.grid(row=1, column=0, sticky=EW)
        self.sb_x.pack(fill=X, anchor=N, side='bottom')
        # self.list_box.grid(row=0, column=0)
        self.list_box.pack(fill=BOTH, expand=1)
        global my_bool_hide
        my_bool_hide = True
        # print(master.winfo_children())

    def on_gloabl_click(self, event):
        if isinstance(event.widget, Listbox) or isinstance(
                event.widget, Scrollbar):
            pass
        else:
            self.hide()

    def hide(self):
        if self.top_window:
            # if self.p_master.input_var.get() == '' or self.p_master.input_var.get() not in self.values:
            #     self.p_master.input_var.set(self.list_box.get(0))
            self.p_master.entry.icursor(len(self.p_master.input_var.get()))
            self.top_window.destroy()
            self.top_window = None
            global my_bool_hide
            my_bool_hide = False
            # self.master.master.master.master.master.master.master.attributes("-disabled", 0)
            # print(my_bool_hide)

    def on_change_geometry(self, event):
        x = self.master.winfo_rootx()
        y = self.master.winfo_rooty() + self.master.winfo_height()
        self.top_window.wm_geometry("+%d+%d" % (x, y))

    def on_click_item(self, event):
        self.p_master.input_var.set(
            self.list_box.get(self.list_box.curselection()))

        global my_str
        if self.my_levels == 0:  # 第一个参数
            my_str[0] = self.p_master.input_var.get()
        elif self.my_levels == 1:  # 第二个参数
            my_str[1] = self.p_master.input_var.get()
        elif self.my_levels == 2:
            my_str[2] = self.p_master.input_var.get()
        elif self.my_levels == 3:
            my_str[3] = self.p_master.input_var.get()
        elif self.my_levels == 4:
            my_str[4] = self.p_master.input_var.get()
        elif self.my_levels == 5:
            my_str[5] = self.p_master.input_var.get()
        # #####################

        self.hide()

    def update_list(self):
        datas = []
        for value in self.values:
            if self.p_master.input_var.get() in value:
                datas.append(value)
        self.list_box.delete(0, END)
        if len(datas) == 0 and self.p_master.input_var.get() == '':
            datas = self.values
        elif len(datas) == 0 and self.p_master.input_var.get() != '' and self.p_master.input_var.get() not in self.values:
            # datas = self.values   # 2023年11月04日注释此行
            # datas.append(self.p_master.input_var.get())  # 2023年11月04日新增此行
            datas = []  # 2023年11月05日新增此行
        else:
            pass

        for data in datas:
            self.list_box.insert(END, data)


    def is_show(self):
        if self.top_window and self.top_window.state() == 'normal':
            return True
        else:
            return False


class ComboBox(ttk.Entry):
    """ComboBox Class"""

    def __init__(self, values, width, master, my_string, my_levels, entryvar=None, entrywidth=None, entrystyle=None, state='normal'):
        self.master = master
        self.values = values
        self.my_string = my_string
        self.my_levels = my_levels
        # ########################
        # if entryvar is not None:
        #     self.input_var = entryvar
        # else:
        #     self.input_var = StringVar()

        entry_config = {}
        if entrywidth is not None:
            entry_config["width"] = entrywidth

        if entrystyle is not None:
            entry_config["style"] = entrystyle
        # ################################
        self.frame = Frame(self.master)
        self.frame.pack(fill=BOTH, expand=1)

        self.input_var = StringVar()
        # self.input_var.set(self.values[0])   #  测试
        # self.entry = Entry(self.frame, textvariable=self.input_var, width=width)
        self.entry = ttk.Entry(self.frame, textvariable=self.input_var, **entry_config,
                               state=state, width=width, bootstyle=SUCCESS)
        self.entry.pack()
        self.entry.bind('<KeyRelease>', self.on_update_list)
        self.entry.bind('<ButtonRelease-1>', self.on_entry_click)
        self.entry.bind('<Return>', self.on_enter)

        self.input_var.set(my_string)

        ListBox().init(width)

    def on_enter(self, event):
        if self.input_var.get() in self.values:
            pass
        # else:
            # self.input_var.set(self.values[0])
            # self.entry.icursor(len(self.input_var.get()))

    def on_entry_click(self, event):
        if ListBox().is_show():
            ListBox().hide()
        else:
            ListBox().my_show(self, self.values, self.entry, self.my_levels)

    def on_update_list(self, event):
        # ##########################
        global my_str
        if self.my_levels == 0:   # 第一个参数
            my_str[0] = self.input_var.get()
        elif self.my_levels == 1:  # 第二个参数
            my_str[1] = self.input_var.get()
        elif self.my_levels == 2:
            my_str[2] = self.input_var.get()
        elif self.my_levels == 3:
            my_str[3] = self.input_var.get()
        elif self.my_levels == 4:
            my_str[4] = self.input_var.get()
        elif self.my_levels == 5:
            my_str[5] = self.input_var.get()
        # print(my_str)
        if ListBox().is_show():
            ListBox().update_list()


def return_str():
    return my_str


def return_my_bool_hide():
    return my_bool_hide

    # print(ComboBox(ttk.Entry))



  • 写回答

16条回答 默认 最新

  • GISer Liu 2024-01-16 22:29
    关注
    获得0.60元问题酬金

    该回答引用自GPT-4,由博主GIS_Liu编写:

    根据你提供的问题描述,你想要在最小化主窗体时,让弹出的下拉框(通过 Toplevel 创建)也跟随主窗体一起最小化。这里有两个关键点需要实现:

    1. 检测主窗体的最小化动作。
    2. 当主窗体最小化时,同步隐藏 Toplevel 窗口。

    根据我的搜索结果,使用 iconify 方法可以实现窗口的最小化【9†source】。此外,你可以使用 withdraw 方法来隐藏 Toplevel 窗口【8†source】。

    以下是一个可能的解决方案:

    1. 绑定一个事件处理函数到主窗口的最小化事件。
    2. 在事件处理函数中,检测 Toplevel 窗口是否显示,如果显示,则调用 withdraw 方法隐藏它。

    这里是一个基于你的代码段的解决方案示例:

    import tkinter as tk
    from tkinter import Toplevel
    
    # 这里假设你的主窗口变量名为 root
    root = tk.Tk()
    
    def on_root_minimize(event):
        if toplevel_window.winfo_viewable():
            toplevel_window.withdraw()
    
    def on_root_restore(event):
        if not toplevel_window.winfo_viewable():
            toplevel_window.deiconify()
    
    # 这里假设你的下拉框 Toplevel 窗口变量名为 toplevel_window
    toplevel_window = Toplevel(root)
    toplevel_window.geometry("200x100")  # 设置下拉框的大小
    
    # 绑定最小化和恢复事件
    root.bind("<Unmap>", on_root_minimize)  # 当窗口最小化时触发
    root.bind("<Map>", on_root_restore)     # 当窗口恢复时触发
    
    # 其他的设置和事件绑定
    # ...
    
    root.mainloop()
    

    在这段代码中,<Unmap> 事件会在窗口从屏幕上消失时触发,这通常意味着窗口被最小化了。而 <Map> 事件则在窗口重新显现时触发,通常是从最小化恢复。我们利用这两个事件来同步 Toplevel 窗口的显示状态。

    如果你想要一个更具体的代码示例,你需要提供更完整的主窗体和 Toplevel 窗口创建的代码。上述代码段只是一个示例,并需要根据你的实际代码进行适配。

    如果该回答解决了您的问题,请采纳!如果没有,请详述问题所在!

    评论 编辑记录

报告相同问题?

问题事件

  • 系统已结题 1月24日
  • 赞助了问题酬金15元 1月16日
  • 创建了问题 1月16日

悬赏问题

  • ¥15 微信小程序 前端页面内容搜索
  • ¥15 cpu是如何判断当前指令已经执行完毕,然后去执行下条指令的
  • ¥15 C++Codeinject远线程注入
  • ¥15 安装visual studio2022时visualstudiosetup启动不了,闪退。问题代号0x0和0x1389
  • ¥30 java spring boot2.5.3版本websocket连不上
  • ¥15 angular js调外部链接查看pdf
  • ¥15 openFOAM DPMFoam
  • ¥15 将查询到的值,赋值到table指定行中
  • ¥50 docker容器内部启动shell脚本多命令
  • ¥15 请问python的selenium怎么设置referer