有没有办法创建第二个 window 像下拉菜单一样连接到父 window

Is there a way to create a second window that connects to the parent window like a dropdown menu

我正在努力使新信息显示在新 window 中,但我希望新 window 连接到父 window,甚至单击父级 window 时,新的 window 仍应显示为类似于下拉菜单的工作方式。我还计划稍后让一些新的 windows 有树视图。

from tkinter import *
win = Tk()
win.geometry("500x500+0+0")
def button_function ():
    win2 = Toplevel()
    label = Label(win2,text='dropdown', width=7)
    label.pack()
    win2.geometry(f"+{win.winfo_x()}+{win.winfo_y()+30}")
button = Button(win, command=lambda: button_function (), width=12)
button.pack()
win.mainloop()

好的,通过一些谷歌搜索,我发现了这个 post:

在那 post 中,他们展示了如何跟踪 window 何时移动。 通过获取该代码并进行一些小的更改,我们可以使用 dragging()stop_drag() 函数将顶层 window 移回相对于主 window 设置的位置].

也就是说这只适用于这种情况。你需要写一些更动态的东西来跟踪你想要的任何新的 windows 以便它们被正确放置并且最重要的是你可能希望在 class 中构建它所以你不必管理全局变量。

结合使用此跟踪功能并使用 lift() 提高 window,我们可以更接近您的要求。

那是说您可能希望删除根 window 顶部的工具栏以便更干净。我还将专注于使用字典或列表来跟踪打开和关闭 windows 及其位置,以使动态部分更容易。

import tkinter as tk


win = tk.Tk()
win.geometry("500x500+0+0")
win2 = None
drag_id = ''


def dragging(event):
    global drag_id
    if event.widget is win:
        if drag_id == '':
            print('start drag')
        else:
            win.after_cancel(drag_id)
            print('dragging')
        drag_id = win.after(100, stop_drag)
        if win2 is not None:
            win2.lift()
            win2.geometry(f"+{win.winfo_x()}+{win.winfo_y() + 30}")


def stop_drag():
    global drag_id, win2, win
    print('stop drag')
    drag_id = ''
    if win2 is not None:
        win2.lift()
        win2.geometry(f"+{win.winfo_x()}+{win.winfo_y() + 30}")



win.bind('<Configure>', dragging)


def button_function():
    global win2
    win2 = tk.Toplevel()
    label = tk.Label(win2, text='drop down', width=7)
    label.pack()
    win2.geometry(f"+{win.winfo_x()}+{win.winfo_y()+30}")


tk.Button(win, command=button_function, width=12).pack()

win.mainloop()

编辑:

好的,所以我花了一些时间将其写在 class 中,以便您了解如何完成。我还添加了一定程度的按钮动态构建并弹出 windows.

我们使用列表和 lambda 的组合来执行一些跟踪,最后我们完全按照您的要求进行。 如果您有任何问题,请告诉我。

import tkinter as tk


class Main(tk.Tk):
    def __init__(self):
        super().__init__()
        self.geometry('500x500')
        self.pop_up_list = []
        self.drag_id = ''
        self.button_notes = ['Some notes for new window', 'some other notes for new window', 'bacon that is all!']
        self.bind('<Configure>', self.dragging)
        for ndex, value in enumerate(self.button_notes):
            print(ndex)
            btn = tk.Button(self, text=f'Button {ndex+1}')
            btn.config(command=lambda b=btn, i=ndex: self.toggle_button_pop_ups(i, b))
            btn.grid(row=ndex, column=0, padx=5, pady=5)
            self.pop_up_list.append([value, 0, None, btn])

    def dragging(self, event):
        if event.widget is self:
            if self.drag_id == '':
                pass
            else:
                self.after_cancel(self.drag_id)
            self.drag_id = self.after(100, self.stop_drag)
            for p in self.pop_up_list:
                if p[1] == 1:
                    p[2].lift()
                    p[2].geometry(f"+{p[3].winfo_rootx() + 65}+{p[3].winfo_rooty()}")

    def stop_drag(self):
        self.drag_id = ''
        for p in self.pop_up_list:
            if p[1] == 1:
                p[2].lift()
                p[2].geometry(f"+{p[3].winfo_rootx() + 65}+{p[3].winfo_rooty()}")

    def toggle_button_pop_ups(self, ndex, btn):
        p = self.pop_up_list
        if p[ndex][1] == 0:
            p[ndex][1] = 1
            p[ndex][2] = tk.Toplevel(self)
            p[ndex][2].overrideredirect(1)
            tk.Label(p[ndex][2], text=self.pop_up_list[ndex][0]).pack()
            p[ndex][2].geometry(f"+{btn.winfo_rootx() + 65}+{btn.winfo_rooty()}")
        else:
            p[ndex][1] = 0
            p[ndex][2].destroy()
            p[ndex][2] = None


if __name__ == '__main__':
    Main().mainloop()