web-dev-qa-db-ja.com

右クリックのコンテキストメニューを追加するtkinterアプリ?

私はいくつかの機能を追加する方法を見つけようとしてきたpython-tkinter guiアプリを持っています。アプリのリストボックス領域にあるアイテムを右クリックしてコンテキストメニューを表示する方法があるといいのですが。 tkinterはこれを達成できますか?私はgtkや他のGUIツールキットを調べたほうがいいでしょうか?

25
tijko

Men インスタンスを作成し、呼び出す関数を記述します
its post() または tk_popup() メソッド。

tkinterのドキュメント には、現在tk_popup()に関する情報はありません。
説明またはソースについて Tkドキュメント を参照してください:

_library/menu.tcl_ Tcl/Tkソース

 :: tk_popup-
この手順では、メニューをポップアップし、トラバース用に設定します
メニューとそのサブメニューを設定します。
 
引数: 
 menu-ポップアップするメニューの名前。
 x、y-メニューをポップアップするルート座標。 
 entry x、y)の中央に配置するメニューエントリのインデックス。 
省略されるか、{}として指定された場合、メニューの
左上隅は(x、y)になります。 

---(_tkinter/__init__.py_ Pythonソース

_def tk_popup(self, x, y, entry=""):
    """Post the menu at position X,Y with entry ENTRY."""
    self.tk.call('tk_popup', self._w, x, y, entry)
_

コンテキストメニュー呼び出し機能を右クリックと関連付けます。
the_widget_clicked_on.bind("<Button-3>", your_function)

ただし、右クリックに関連付けられている数は、すべてのプラットフォームで同じというわけではありません。

_library/tk.tcl_ Tcl/Tkソース

ダーウィン/アクアでは、左から右へのボタンは1、3、2です。 
最近のXQuartzをXサーバーとするDarwin/X11では、1、2、3です。 
他のXサーバーは異なる場合があります。

リストボックスにコンテキストメニューを追加する例を次に示します。

_import tkinter # Tkinter -> tkinter in Python 3

class FancyListbox(tkinter.Listbox):

    def __init__(self, parent, *args, **kwargs):
        tkinter.Listbox.__init__(self, parent, *args, **kwargs)

        self.popup_menu = tkinter.Menu(self, tearoff=0)
        self.popup_menu.add_command(label="Delete",
                                    command=self.delete_selected)
        self.popup_menu.add_command(label="Select All",
                                    command=self.select_all)

        self.bind("<Button-3>", self.popup) # Button-2 on Aqua

    def popup(self, event):
        try:
            self.popup_menu.tk_popup(event.x_root, event.y_root, 0)
        finally:
            self.popup_menu.grab_release()

    def delete_selected(self):
        for i in self.curselection()[::-1]:
            self.delete(i)

    def select_all(self):
        self.selection_set(0, 'end')


root = tkinter.Tk()
flb = FancyListbox(root, selectmode='multiple')
for n in range(10):
    flb.insert('end', n)
flb.pack()
root.mainloop()
_

grab_release()の使用は effbotの例 で確認されました。
その効果はすべてのシステムで同じであるとは限りません。

38
Honest Abe

上記のconextメニューコードにいくつかの変更を加えて需要を調整しました。

バージョン1:

import tkinter as tk
from tkinter import ttk

class Main(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        master.geometry('500x350')
        self.master = master
        self.tree = ttk.Treeview(self.master, height=15)
        self.tree.pack(fill='x')
        self.btn = tk.Button(master, text='click', command=self.clickbtn)
        self.btn.pack()
        self.aMenu = tk.Menu(master, tearoff=0)
        self.aMenu.add_command(label='Delete', command=self.delete)
        self.aMenu.add_command(label='Say Hello', command=self.hello)

        # attach popup to treeview widget
        self.tree.bind("<Button-3>", self.popup)

    def clickbtn(self):
        text = 'Hello ' + str(self.num)
        self.tree.insert('', 'end', text=text)
        self.num += 1

    def delete(self):
        print(self.tree.focus())
        if self.iid:
            self.tree.delete(self.iid)

    def hello(self):
        print ('hello!')

    def popup(self, event):
        self.iid = self.tree.identify_row(event.y)
        if self.iid:
            # mouse pointer over item
            self.tree.selection_set(self.iid)
            self.aMenu.post(event.x_root, event.y_root)            
        else:
            pass

バージョン2:

import tkinter as tk
from tkinter import ttk

class Main(tk.Frame):
    def __init__(self, master):
        master.geometry('500x350')
        self.master = master
        tk.Frame.__init__(self, master)
        self.tree = ttk.Treeview(self.master, height=15)
        self.tree.pack(fill='x')
        self.btn = tk.Button(master, text='click', command=self.clickbtn)
        self.btn.pack()
        self.rclick = RightClick(self.master)
        self.num = 0

        # attach popup to treeview widget
        self.tree.bind('<Button-3>', self.rclick.popup)
    def clickbtn(self):
        text = 'Hello ' + str(self.num)
        self.tree.insert('', 'end', text=text)
        self.num += 1

class RightClick:
    def __init__(self, master):

        # create a popup menu
        self.aMenu = tk.Menu(master, tearoff=0)
        self.aMenu.add_command(label='Delete', command=self.delete)
        self.aMenu.add_command(label='Say Hello', command=self.hello)

        self.tree_item = ''

    def delete(self):
        if self.tree_item:
            app.tree.delete(self.tree_item)

    def hello(self):
        print ('hello!')

    def popup(self, event):
        self.aMenu.post(event.x_root, event.y_root)
        self.tree_item = app.tree.focus()

root = tk.Tk()
app=Main(root)
root.mainloop()
4
bzimor