我有一個菜單欄的圖形用戶界面。我希望能夠以編程方式打開這些菜單,就好像用戶點擊了它們一樣。如何在python tkinter中以編程方式打開菜單?
我的第一個猜測是invoke
但沒有明顯的效果。 我知道我可以使用tk_popup
打開菜單,但我無法弄清楚座標。 yposition
函數的返回值看起來沒有幫助。 奇怪的是我甚至無法獲得菜單欄的寬度 - 它總是1.
我知道我可以一個菜單按鈕的按鍵事件綁定underline
和我大概可以編程創建這樣的事件,但我真的止跌」不想這樣做。
import Tkinter as tk
class MenuBar(tk.Menu):
def __init__(self, root):
tk.Menu.__init__(self, root)
self.root = root
self.menu_file = tk.Menu(m, tearoff=False)
self.menu_file.label = 'File'
self.menu_file.add_command(label='save')
self.menu_file.add_command(label='open')
self.menu_edit = tk.Menu(m, tearoff=False)
self.menu_edit.label = 'Edit'
self.menu_edit.add_command(label='add')
self.menu_edit.add_command(label='remove')
self.menus = (
self.menu_file,
self.menu_edit,
)
for menu in self.menus:
self.add_cascade(label=menu.label, menu=menu, underline=0)
def invoke(self, menu):
if menu in self.menus:
index = self.index(menu.label)
else:
index = menu
print("invoke({!r})".format(index))
tk.Menu.invoke(self, index)
def open_menu(self, menu):
x = self.root.winfo_rootx()
y = self.root.winfo_rooty()
print("yposition: {}".format(self.yposition(self.index(menu.label))))
print("mb.width : {}".format(self.winfo_width()))
print("mb.geometry: {}".format(self.winfo_geometry()))
print("tk_popup({x},{y})".format(x=x, y=y))
menu.tk_popup(x,y)
pass
m = tk.Tk()
mb = MenuBar(m)
m.config(menu=mb)
m.update()
m.bind('f', lambda e: mb.invoke(mb.menu_file))
m.bind('e', lambda e: mb.invoke(mb.menu_edit))
m.bind('<Control-f>', lambda e: mb.open_menu(mb.menu_file))
m.bind('<Control-e>', lambda e: mb.open_menu(mb.menu_edit))
m.mainloop()
在此先感謝。
編輯: 我假設你,喬納森,指的是mb.menu_file.invoke(0)
。如果我設置撕裂爲真,那是有效的,但是這不是我正在尋找的。因爲這會在某個地方的某個窗口中打開菜單(在我的情況下,在屏幕的左上角 - 遠離窗口),並且必須在窗口右上角的關閉按鈕上單擊鼠標右鍵才能關閉菜單。
即使可撕下=真mb.invoke(mb.menu_file)
具有仍然沒有影響(打印以外「調用(1)」)。
我已經做postcascade
一些研究,這聽起來完全像我所期待的。除此之外 - 正如你已經指出的那樣 - 它不起作用。 tcl documentation對此表示:「如果未張貼pathName,則該命令除了取消任何當前張貼的子菜單之外沒有任何作用」。事實上,如果我用mb.update(); mb.post(m.winfo_rootx(), m.winfo_rooty())
代替m.config(menu=mb)
它就行。 (我在這裏使用的是post
而不是tk_popup
,因爲在這種情況下,它應該保持打開。)它仍然不完美,因爲我無法用鍵盤控制子菜單;但是,無論如何,我想要一個菜單欄,而不是一個菜單。
你知道它有什麼缺點來「僞造」菜單嗎?我不考慮這樣做,因爲effbot指出「由於這個小部件儘可能使用本機代碼,因此不應該嘗試使用按鈕和其他Tkinter小部件來僞造菜單。」 (在另一方面這篇文章還建議與post
打開菜單,這是我從this answer學會了不是最好的辦法 - tk_popup
是更好的。)這種解決方案肯定會提供所需的靈活性。我目前看到的一個缺點是,當將鼠標光標移動到菜單未打開的下一個菜單時。但應該可以處理這個問題。我需要考慮更多細節嗎?
至於爲什麼:我希望用戶能夠完全自定義的快捷鍵。因此我需要一個可以綁定到用戶選擇的事件的函數。
另一個用例可能被實施的幫助功能,它不僅告訴用戶在哪裏可以找到一個命令,但打開正確的菜單,並選擇命令。這會讓用戶更快地找到它,而不是自己搜索正確的菜單。
謝謝。請看我編輯的問題。 – jakun
我不認爲有可能做到完全一樣,這就是爲什麼我給你假的方式。 AFAIK唯一的缺點是它看起來更醜陋(因爲它不是OS繪製它),你必須自己處理所有東西。但它能做到你想要的,包括鍵盤控制。 – Novel
對於不同的外觀,您可以使用'ttk.Menubutton'代替。 – Novel