私はメニューバーを備えたグラフィカルユーザーインターフェイスを持っています。私は、ユーザーがそれらをクリックしたかのようにこれらのメニューをプログラムで開くことができるようにしたいと思います。python tkinterでメニューをプログラムで開く方法は?
私の最初の推測はinvoke
でしたが、目に見える効果はありません。 tk_popup
を使用してメニューを開くことができますが、私は座標を把握できません。 yposition
関数の戻り値が役に立ちません。 は不思議私もメニューバーの幅を取得することはできません - それは常に私がunderline
でキーイベントへのメニューボタンをバインドすることができます知っている1.
だと私はおそらくプログラム的なイベントを作成することができることが、私は本当にwouldn」それをやりたい
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)
を指していると仮定しています。それは私がtearoffをTrueに設定しても機能しますが、それは私が探しているものではありません。これは別のウィンドウのメニューを開きます(私の場合、画面の左上隅にあります - ウィンドウから離れています)、ウィンドウの右上にある閉じるボタンを明示的にクリックして閉じる必要があります。
tearoff = Trueの場合でも、mb.invoke(mb.menu_file)
は効果がありません( "invoke(1)"の印刷を除く)。
私はpostcascade
についていくつかの調査を行いましたが、私が探しているものとまったく同じように聞こえます。あなたがすでに指摘しているように、それは機能しません。 tcl documentationは、「pathNameがポストされていないと、現在ポストされているサブメニューのポストを取り消す以外は何の効果もありません」と言います。そして実際にm.config(menu=mb)
をmb.update(); mb.post(m.winfo_rootx(), m.winfo_rooty())
に置き換えればうまくいきます。 (この場合はtk_popup
の代わりにpost
を使用しています。この場合は開いたままにしておく必要があります)キーボードでサブメニューを制御できないため、まだ完全ではありません。しかし、とにかく、私はポップアップメニューではなく、メニューバーが必要です。
メニューを「偽造する」にはどのような欠点があるのでしょうか? effbotは「このウィジェットは可能な限りネイティブコードを使用しているので、ボタンや他のTkinterウィジェットを使ってメニューを偽造しないでください」と述べているので、私はそのことを考慮しませんでした。 (他方では、この記事ではpost
というメニューを開くことを提案しています。これはthis answerから学んだことがあります。tk_popup
が良い方法です。)その解決策は確かに望ましい柔軟性を提供します。私が現在目にしている欠点の1つは、マウスカーソルを次のメニューに移動してもメニューが開かないということです。しかし、それを処理することが可能でなければなりません。私が考慮する必要のある詳細はありますか?
理由:私は、ユーザーがキーボードショートカットを完全にカスタマイズできるようにしたいと思います。したがって、ユーザーが選択したイベントにバインドできる関数が必要です。
別の用途では、コマンドを見つける場所をユーザーに通知するだけでなく、正しいメニューを開いてそのコマンドを選択するヘルプ機能を実装している可能性があります。ユーザーが適切なメニューを探すよりも、それを見つけるのがずっと速くなります。
ありがとうございます。私の編集した質問を見てください。 – jakun
私はあなたのことをまったくやり遂げることはできないと思うので、私はあなたに偽の道を与えました。 AFAIKの唯一の欠点は、それが醜いと思うということです(なぜなら、それはOSがそれを描くのではなく、あなたのものであるからです)。しかし、それはキーボードのコントロールを含め、あなたが望むことをします。 – Novel
別の見方をすれば、代わりに 'ttk.Menubutton'を使うことができます。 – Novel