Python tkinter: кнопка «Удалить меню» - PullRequest
0 голосов
/ 22 ноября 2018

Я хочу удалить кнопку меню, когда нажимаю на нее правой кнопкой мыши.
Обычно это делается с помощью bind("Mouse3", deletefunction), НО мне нужен фактический экземпляр кнопки, чтобы связать его, и единственный способ добавить кнопку проверки.к меню, которое я знаю, это add_checkbutton() метод (и у меня нет доступа к экземпляру таким образом).Есть ли способ, которым я мог бы сделать это?

import tkinter as tk

root = tk.Tk()
menubar = tk.Menu(root)
view_menu = tk.Menu(menubar, tearoff=0)
view_menu.add_checkbutton(label="Right click on me to delete", onvalue=1, offvalue=False)
# I want to do something like this:
# c = Checkbutton(label="Right click on me to delete")
# c.bind("Mouse3", my_delete_function())
# view_menu.add(c)
menubar.add_cascade(label='View', menu=view_menu)
root.config(menu=menubar)
root.mainloop()

1 Ответ

0 голосов
/ 23 ноября 2018

Насколько я понимаю, ваш вопрос состоит из двух частей:

  1. Можно ли назначить пункт меню для манипуляции после?

  2. Может ли указанный элемент быть привязан к событию?


Первый ответ , вроде как.Хотя вы не можете точно назначить объект, вы можете ссылаться на него по индексу следующим образом:

view_menu.delete(0)

Поскольку вы сначала добавили checkbutton, он будет иметь индекс0. Вы можете либо отслеживать индексы, либо ссылаться на элемент по его label. См. Связанный ответ от Брайана Оукли .Например:

view_menu.delete(view_menu.index("Right click on me to delete"))

Метод .index() обнаружит index по элементу меню label, что может быть удобно, если у вас один и тот же ярлык более одного раза ...


Второй ответ , насколько я знаю, кажется, что нет никакого эффективного связывания для типичных событий, таких как щелчки мышью.Однако после некоторого поиска я наткнулся на довольно скрытую <<MenuSelect>> привязку , которая по крайней мере вызывает событие. Это само по себе бесполезно для вашего квеста , но вы можете объединить состояние события с аргументом checkbutton 'command, а также с логическим флагом для запуска событияпри нажатии:

# Add a BooleanVar for flagging:
delete_checkbutton = tk.BooleanVar()

# Add a binding to your view_menu 
view_menu.bind('<<MenuSelect>>', event_state)

# Define the callback function:
def event_state(e):
    if bool(e.state & 0x0400):  # watch for the Mouse Right click state
        # you might opt to use 0x0004 or 0x0001 instead
        # i.e. Ctrl+click or Shift+Click
        delete_checkbutton.set(True)
    else:  # If the state is not right click, reset the flag
        delete_checkbutton.set(False)

# Define a self_delete command for the checkbutton
def self_delete():
    if delete_checkbutton.get():
        view_menu.delete(view_menu.index("Right click on me to delete"))

# Add the command to your checkbutton
view_menu.add_checkbutton(label="Right click on me to delete", onvalue=lambda:print('hey'), offvalue=False, command=self_delete)

Примечание: На самом деле вам нужно будет удерживать щелчок правой кнопкой мыши и затем щелкнуть левой кнопкой мыши на checkbutton, чтобы удалить его.Очевидно, недостатком является то, что вы теперь активировали значение вкл / выкл, и вам может потребоваться дополнительная обработка для них.

Если правый + левый щелчок слишком неудобен, Ctrl / Shift - другое состояние мода, которое вы могли бырассмотрим.

Еще одно замечание: я сторонник ООП, когда дело доходит до tkinter, он делает доступные переменные и флаги намного проще, не беспокоясь о пространствах имен global и nonlocal.Здесь, поскольку delete_checkbutton установлено в пространстве имен global, я избегал использования ключевого слова global и обращался к нему через объект tk.BooleanVar().Однако, если бы вы использовали булево значение Python (например, flag = True), то оно не будет таким эффективным, если вы не укажете global flag в обеих функциях.Однако, если вы выбрали подход ООП, вы можете ссылаться на флаги напрямую через self.flag без двусмысленности.


Наконец , вот комплексные изменения, реализованные в вашем коде для выборки:1072 *

import tkinter as tk

def event_state(e):
    if bool(e.state & 0x0400):
        # you might opt to use 0x0004 or 0x0001 instead
        # i.e. Ctrl+click or Shift+Click
        delete_checkbutton.set(True)
    else:
        delete_checkbutton.set(False)

def self_delete():
    if delete_checkbutton.get():
        view_menu.delete(view_menu.index("Right click on me to delete"))

root = tk.Tk()
menubar = tk.Menu(root)
delete_checkbutton = tk.BooleanVar()
view_menu = tk.Menu(menubar, tearoff=0)
view_menu.add_command(label='dude', command=lambda: print('dude'))
view_menu.add_checkbutton(label="Right click on me to delete", onvalue=lambda:print('hey'), offvalue=False, command=self_delete)
menubar.add_cascade(label='View', menu=view_menu)
root.config(menu=menubar)
view_menu.bind('<<MenuSelect>>', event_state)
root.mainloop()

Все, что сказано , я считаю, что это не очень плавный пользовательский опыт и несколько сбивает с толку.Только постоянное удаление одного пункта меню в лучшем случае сомнительно, в сочетании с методом, который вы пытаетесь вызвать при удалении, чувствует себя еще более надуманным.Я бы посоветовал пересмотреть ваш UX-поток, чтобы подумать, как его упростить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...