28

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

4

4 に答える 4

44

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

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

library/menu.tclTcl / Tkソース

::tk_popup-
この手順では、メニューがポップアップ表示され、トラバースするように設定されます
メニューとそのサブメニュー。

引数:
menu-ポップアップするメニューの名前。
x、y-メニューをポップアップするルート座標。  
entry-(x、y)を中心とするメニューエントリのインデックス。  
        省略または{}として指定した場合、メニューの  
        左上隅は(x、y)になります。  

tkinter/__init__.pyPythonソース

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.tclTcl / Tkソース

ダーウィン/アクアでは、左から右へのボタンは1,3,2です。  
Xサーバーとして最近のXQuartzを使用する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()

の使用は、effbotの例でgrab_release()観察されました。 その効果は、すべてのシステムで同じではない場合があります。

于 2012-08-17T23:29:34.333 に答える
6

需要を調整するために、上記の 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)
        self.num = 0

        # 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

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

バージョン 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()
于 2017-01-20T10:50:08.070 に答える
0

重要な警告:

(座標を含むイベント引数が「event」と呼ばれると仮定します): 「event.x_root」と「event.y_root」を引数として使用しない限り、tk_popup(...) を呼び出しても何も起こらないか、または表示されません。「event.x」と「event.y」を使用するという明白な方法を実行すると、座標の名前が「x」と「y」であり、「x_root」と「x_root」の言及がないにもかかわらず、機能しません。 「y_root」はその中のどこかに。

grab_release(..) に関しては、どこでも必要ありません。"tearoff=0" も必要ありません。1 に設定すると (デフォルト)、コンテキスト メニューに点線のエントリが追加されます。クリックすると、コンテキスト メニューが切り離され、ウィンドウ デコレータを備えた独自のトップレベル ウィンドウになります。teaoff=0 は、このエントリを非表示にします。さらに、メニューのマスターを特定のウィジェットまたはルートに設定するかどうかは問題ではありません。

于 2021-11-09T17:43:17.463 に答える