Anonymous
У меня возникли проблемы с попыткой понять, как отобразить меню там, где находится его родительский элемент, с помощью T
Сообщение
Anonymous » 11 янв 2026, 07:16
Может ли кто-нибудь помочь мне понять, как сделать так, чтобы виджет меню появлялся там, где расположена кнопка?
Я работаю над приложением, которое загружает видео из Интернета с помощью yt-dlp (я не поощряю пиратство, просто хочу прояснить это). Каждая загрузка внутри списка имеет кнопку, открывающую меню. Однако каждый раз, когда я нажимаю эту кнопку, меню открывается в верхнем левом углу экрана, а не там, где находится кнопка.
Код: Выделить всё
from tkinter import *
from tkinter import ttk
from swiperdl.utils.gui import get_icon, load_image_tkinter
class DownloadItem(ttk.Frame):
"""Class for a displayed download item"""
def __init__(self, master=None, title: str = "", dl_path: str = "", url: str = "", status: str = "", progress: dict = None) -> None:
super().__init__(master)
self.title = StringVar()
self.title.set(title)
self.window_coords: dict = {
"x": 0,
"y": 0
}
self.dl_path = dl_path
self.url = url
self.status = status
self.status_text = StringVar()
self.progress_bytes = IntVar()
self.progress_bytes.set(progress.get("bytes", 0))
self.progress_total = progress.get("total", 100)
self.setup_widgets()
def setup_widgets(self) -> None:
self.title_display = ttk.Label(self, textvariable=self.title)
self.status_display = ttk.Label(self, textvariable=self.status_text)
self.progress_bar = ttk.Progressbar(self, orient="horizontal", length=200, mode="determinate", variable=self.progress_bytes, maximum=self.progress_total)
self.info_button = ttk.Button(self, text="...", command=self.open_info_menu)
self.title_display.pack(side="left", anchor="center", padx=50)
self.status_display.pack(side="left", anchor="center", padx=50)
self.progress_bar.pack(side="left", anchor="center", padx=50)
self.info_button.pack(side="right", anchor="center", padx=50)
self.info_menu = Menu(self.info_button)
self.info_menu.add_command(label="Open with associated application")
self.info_menu.add_command(label="Open download link")
self.info_menu.add_command(label="View output")
self.info_menu.add_command(label="Cancel download")
self.info_menu.add_command(label="Remove from list")
def open_info_menu(self) -> None:
self.info_menu.tk_popup(self.window_coords["x"], self.window_coords["y"])
class MainWindow(Tk):
"""Class for the main window GUI."""
def __init__(self) -> None:
super().__init__()
# Basic window settings
self.title("SwiperDL")
self.icon = load_image_tkinter(get_icon("swiperdl"))
self.wm_iconphoto(True, self.icon)
self.geometry("1480x800")
self.protocol("WM_DELETE_WINDOW", self.close)
# A list of predefined formats to choose from.
self.formats = [
...
]
# A list of downloads to be displayed.
# Just a sample, I won't use this in production.
self.downloads = [
{
"title": "Me at the zoo.mp4",
"dl_path": "/home//Me at the zoo.mp4",
"status": "downloading",
"url": "https://www.youtube.com/watch?v=jNQXAC9IVRw",
"progress": {
"bytes": 0,
"total": 100
}
}
]
self.detect_clipboard = StringVar() # Configuration for automatic clipboard detection.
self.selected_format = StringVar() # Holds the selected format to download using the backend.
self.selected_format.set(self.formats[0])
# Start creating the widgets
self.create_menu()
self.create_widgets()
def create_widgets(self) -> None:
self.main_frame = ttk.Frame(self)
self.main_frame.pack(anchor="center", side="top", expand=True, fill="both")
self.toolbar = ttk.Frame(self.main_frame)
self.toolbar.pack(side="top", anchor="n", fill="x", ipady=20)
self.toolbar_left_spacer = ttk.Frame(self.toolbar, height=1)
self.toolbar_left_spacer.pack(side="left", anchor="w", expand=True, fill="y")
self.url_bar = ttk.Frame(self.toolbar, height=125)
self.clipboard_toggle_icon = load_image_tkinter(get_icon("clipboard_enabled"))
self.clipboard_toggle = ttk.Button(self.url_bar, text="Toggle Clipboard", image=self.clipboard_toggle_icon)
self.clipboard_toggle.pack(side="left", anchor="w")
self.default_text = StringVar()
self.default_text.set("Enter URL or search query here")
self.url_field = ttk.Entry(self.url_bar, textvariable=self.default_text)
self.url_field.pack(side="right", anchor="e", fill="x", padx=50, ipadx=86)
self.url_bar.pack(side="left", anchor="center", expand=False, ipadx=10)
self.basic_config_frame = ttk.Frame(self.toolbar, height=125)
self.basic_config_frame.pack(side="left", anchor="e")
self.format_selection_box = ttk.Combobox(self.basic_config_frame, textvariable=self.selected_format, value=self.formats)
self.format_selection_box.pack(side="left", anchor="w", padx=25)
self.cookies_icon = load_image_tkinter(get_icon("cookies"))
self.cookies_from_browser_toggle = ttk.Button(self.basic_config_frame, text="Use browser cookies", image=self.cookies_icon)
self.cookies_from_browser_toggle.pack(side="left", anchor="e")
self.metadata_icon = load_image_tkinter(get_icon("metadata_enabled"))
self.extract_metadata_toggle = ttk.Button(self.basic_config_frame, text="Extract metadata", image=self.metadata_icon)
self.extract_metadata_toggle.pack(side="left", anchor="e")
self.settings_icon = load_image_tkinter(get_icon("settings"))
self.toolbar_settings_shortcut = ttk.Button(self.basic_config_frame, text="Open settings", image=self.settings_icon)
self.toolbar_settings_shortcut.pack(side="left", anchor="e")
self.toolbar_right_spacer = ttk.Frame(self.toolbar, height=1)
self.toolbar_right_spacer.pack(side="right", anchor="e", expand=True, fill="y")
self.toolbar_separator = ttk.Separator(self.main_frame, orient="horizontal")
self.toolbar_separator.pack(side="top", anchor="n", fill="x")
self.centre_frame = ttk.Frame(self.main_frame)
self.centre_frame.pack(side="top", anchor="center", expand=True, fill="both")
self.download_view_frame = ttk.Frame(self.centre_frame)
self.download_view_frame.pack(side="top", anchor="center", expand=True, fill="both")
for dl in self.downloads:
self.download = DownloadItem(self.download_view_frame, dl.get("title", ""), dl.get("dl_path", ""), dl.get("url", ""), dl.get("status", ""), dl.get("progress", {"bytes": 0, "total": 0}))
self.download.pack(side="top", anchor="n", fill="x")
def create_menu(self) -> None:
# This is to make sure the menu stays in place.
self.option_add("*tearOff", FALSE)
self.menubar = Menu()
self['menu'] = self.menubar
# Menu for doing stuff with the program
self.appmenu = Menu(self.menubar)
self.appmenu.add_command(label="Add download")
self.appmenu.add_checkbutton(label="Clipboard detection", variable=self.detect_clipboard,
onvalue=1, offvalue=0)
self.appmenu.add_separator()
self.appmenu.add_command(label="Open settings")
self.appmenu.add_separator()
self.appmenu.add_command(label="Quit", command=self.close)
self.menubar.add_cascade(label="SwiperDL", menu=self.appmenu)
# Menu for getting information about the program
self.aboutmenu = Menu(self.menubar)
self.aboutmenu.add_command(label="About SwiperDL")
self.aboutmenu.add_separator()
self.aboutmenu.add_command(label="Support")
self.aboutmenu.add_command(label="Website")
self.aboutmenu.add_command(label="GitHub")
self.aboutmenu.add_command(label="PyPI.org")
self.menubar.add_cascade(label="About", menu=self.aboutmenu)
def open(self) -> None:
self.mainloop()
def close(self) -> None:
self.destroy()
Если бы кто-нибудь мог дать мне какой-нибудь совет, я был бы очень признателен!
Спасибо
Подробнее здесь:
https://stackoverflow.com/questions/798 ... re-its-par
1768104999
Anonymous
Может ли кто-нибудь помочь мне понять, как сделать так, чтобы виджет меню появлялся там, где расположена кнопка? Я работаю над приложением, которое загружает видео из Интернета с помощью yt-dlp (я не поощряю пиратство, просто хочу прояснить это). Каждая загрузка внутри списка имеет кнопку, открывающую меню. Однако каждый раз, когда я нажимаю эту кнопку, меню открывается в верхнем левом углу экрана, а не там, где находится кнопка. [code]from tkinter import * from tkinter import ttk from swiperdl.utils.gui import get_icon, load_image_tkinter class DownloadItem(ttk.Frame): """Class for a displayed download item""" def __init__(self, master=None, title: str = "", dl_path: str = "", url: str = "", status: str = "", progress: dict = None) -> None: super().__init__(master) self.title = StringVar() self.title.set(title) self.window_coords: dict = { "x": 0, "y": 0 } self.dl_path = dl_path self.url = url self.status = status self.status_text = StringVar() self.progress_bytes = IntVar() self.progress_bytes.set(progress.get("bytes", 0)) self.progress_total = progress.get("total", 100) self.setup_widgets() def setup_widgets(self) -> None: self.title_display = ttk.Label(self, textvariable=self.title) self.status_display = ttk.Label(self, textvariable=self.status_text) self.progress_bar = ttk.Progressbar(self, orient="horizontal", length=200, mode="determinate", variable=self.progress_bytes, maximum=self.progress_total) self.info_button = ttk.Button(self, text="...", command=self.open_info_menu) self.title_display.pack(side="left", anchor="center", padx=50) self.status_display.pack(side="left", anchor="center", padx=50) self.progress_bar.pack(side="left", anchor="center", padx=50) self.info_button.pack(side="right", anchor="center", padx=50) self.info_menu = Menu(self.info_button) self.info_menu.add_command(label="Open with associated application") self.info_menu.add_command(label="Open download link") self.info_menu.add_command(label="View output") self.info_menu.add_command(label="Cancel download") self.info_menu.add_command(label="Remove from list") def open_info_menu(self) -> None: self.info_menu.tk_popup(self.window_coords["x"], self.window_coords["y"]) class MainWindow(Tk): """Class for the main window GUI.""" def __init__(self) -> None: super().__init__() # Basic window settings self.title("SwiperDL") self.icon = load_image_tkinter(get_icon("swiperdl")) self.wm_iconphoto(True, self.icon) self.geometry("1480x800") self.protocol("WM_DELETE_WINDOW", self.close) # A list of predefined formats to choose from. self.formats = [ ... ] # A list of downloads to be displayed. # Just a sample, I won't use this in production. self.downloads = [ { "title": "Me at the zoo.mp4", "dl_path": "/home//Me at the zoo.mp4", "status": "downloading", "url": "https://www.youtube.com/watch?v=jNQXAC9IVRw", "progress": { "bytes": 0, "total": 100 } } ] self.detect_clipboard = StringVar() # Configuration for automatic clipboard detection. self.selected_format = StringVar() # Holds the selected format to download using the backend. self.selected_format.set(self.formats[0]) # Start creating the widgets self.create_menu() self.create_widgets() def create_widgets(self) -> None: self.main_frame = ttk.Frame(self) self.main_frame.pack(anchor="center", side="top", expand=True, fill="both") self.toolbar = ttk.Frame(self.main_frame) self.toolbar.pack(side="top", anchor="n", fill="x", ipady=20) self.toolbar_left_spacer = ttk.Frame(self.toolbar, height=1) self.toolbar_left_spacer.pack(side="left", anchor="w", expand=True, fill="y") self.url_bar = ttk.Frame(self.toolbar, height=125) self.clipboard_toggle_icon = load_image_tkinter(get_icon("clipboard_enabled")) self.clipboard_toggle = ttk.Button(self.url_bar, text="Toggle Clipboard", image=self.clipboard_toggle_icon) self.clipboard_toggle.pack(side="left", anchor="w") self.default_text = StringVar() self.default_text.set("Enter URL or search query here") self.url_field = ttk.Entry(self.url_bar, textvariable=self.default_text) self.url_field.pack(side="right", anchor="e", fill="x", padx=50, ipadx=86) self.url_bar.pack(side="left", anchor="center", expand=False, ipadx=10) self.basic_config_frame = ttk.Frame(self.toolbar, height=125) self.basic_config_frame.pack(side="left", anchor="e") self.format_selection_box = ttk.Combobox(self.basic_config_frame, textvariable=self.selected_format, value=self.formats) self.format_selection_box.pack(side="left", anchor="w", padx=25) self.cookies_icon = load_image_tkinter(get_icon("cookies")) self.cookies_from_browser_toggle = ttk.Button(self.basic_config_frame, text="Use browser cookies", image=self.cookies_icon) self.cookies_from_browser_toggle.pack(side="left", anchor="e") self.metadata_icon = load_image_tkinter(get_icon("metadata_enabled")) self.extract_metadata_toggle = ttk.Button(self.basic_config_frame, text="Extract metadata", image=self.metadata_icon) self.extract_metadata_toggle.pack(side="left", anchor="e") self.settings_icon = load_image_tkinter(get_icon("settings")) self.toolbar_settings_shortcut = ttk.Button(self.basic_config_frame, text="Open settings", image=self.settings_icon) self.toolbar_settings_shortcut.pack(side="left", anchor="e") self.toolbar_right_spacer = ttk.Frame(self.toolbar, height=1) self.toolbar_right_spacer.pack(side="right", anchor="e", expand=True, fill="y") self.toolbar_separator = ttk.Separator(self.main_frame, orient="horizontal") self.toolbar_separator.pack(side="top", anchor="n", fill="x") self.centre_frame = ttk.Frame(self.main_frame) self.centre_frame.pack(side="top", anchor="center", expand=True, fill="both") self.download_view_frame = ttk.Frame(self.centre_frame) self.download_view_frame.pack(side="top", anchor="center", expand=True, fill="both") for dl in self.downloads: self.download = DownloadItem(self.download_view_frame, dl.get("title", ""), dl.get("dl_path", ""), dl.get("url", ""), dl.get("status", ""), dl.get("progress", {"bytes": 0, "total": 0})) self.download.pack(side="top", anchor="n", fill="x") def create_menu(self) -> None: # This is to make sure the menu stays in place. self.option_add("*tearOff", FALSE) self.menubar = Menu() self['menu'] = self.menubar # Menu for doing stuff with the program self.appmenu = Menu(self.menubar) self.appmenu.add_command(label="Add download") self.appmenu.add_checkbutton(label="Clipboard detection", variable=self.detect_clipboard, onvalue=1, offvalue=0) self.appmenu.add_separator() self.appmenu.add_command(label="Open settings") self.appmenu.add_separator() self.appmenu.add_command(label="Quit", command=self.close) self.menubar.add_cascade(label="SwiperDL", menu=self.appmenu) # Menu for getting information about the program self.aboutmenu = Menu(self.menubar) self.aboutmenu.add_command(label="About SwiperDL") self.aboutmenu.add_separator() self.aboutmenu.add_command(label="Support") self.aboutmenu.add_command(label="Website") self.aboutmenu.add_command(label="GitHub") self.aboutmenu.add_command(label="PyPI.org") self.menubar.add_cascade(label="About", menu=self.aboutmenu) def open(self) -> None: self.mainloop() def close(self) -> None: self.destroy() [/code] Если бы кто-нибудь мог дать мне какой-нибудь совет, я был бы очень признателен! :) Спасибо Подробнее здесь: [url]https://stackoverflow.com/questions/79865310/im-having-trouble-trying-to-figure-out-how-to-make-a-menu-appear-where-its-par[/url]