2010-11-24 2 views
5

저는 파이썬 2.6.x와 TKinter가있는 Windows XP에서 작업하고 있습니다. 앱에서 텍스트 위젯을 사용하지만 표준 팝업 메뉴 (잘라 내기, 복사, 붙여 넣기, 삭제, 모두 선택)가 없습니다. 어떻게 보이게 만드나요?파이썬의 표준 컨텍스트 메뉴 마우스 오른쪽 버튼을 눌렀을 때 TKinter 텍스트 위젯

+0

상황에 맞는 메뉴를 마우스 오른쪽 버튼으로 클릭하면 해당 메뉴에 나타나는 내용이 널리 표준화되지 않습니다. 이를 지원하는 플랫폼에서는 텍스트 편집과 같은 특정 응용 프로그램에 대한 규칙이 많이 있습니다. 'tkinter' API는 플랫폼에 독립적입니다. 따라서이 기능을 원한다면, 구현 한 코드 나 원하는 것에 가까운 코드를 작성하거나 찾아야합니다. – martineau

답변

4

나는 this post 덕분에 길을 찾았습니다. 나는 약간의 수정을했다. 하단 부분에는 최소한 main이 있습니다.

from Tkinter import * 

def rClicker(e): 
    ''' right click context menu for all Tk Entry and Text widgets 
    ''' 

    try: 
     def rClick_Copy(e, apnd=0): 
      e.widget.event_generate('<Control-c>') 

     def rClick_Cut(e): 
      e.widget.event_generate('<Control-x>') 

     def rClick_Paste(e): 
      e.widget.event_generate('<Control-v>') 

     e.widget.focus() 

     nclst=[ 
       (' Cut', lambda e=e: rClick_Cut(e)), 
       (' Copy', lambda e=e: rClick_Copy(e)), 
       (' Paste', lambda e=e: rClick_Paste(e)), 
       ] 

     rmenu = Menu(None, tearoff=0, takefocus=0) 

     for (txt, cmd) in nclst: 
      rmenu.add_command(label=txt, command=cmd) 

     rmenu.tk_popup(e.x_root+40, e.y_root+10,entry="0") 

    except TclError: 
     print ' - rClick menu, something wrong' 
     pass 

    return "break" 


def rClickbinder(r): 

    try: 
     for b in [ 'Text', 'Entry', 'Listbox', 'Label']: # 
      r.bind_class(b, sequence='<Button-3>', 
         func=rClicker, add='') 
    except TclError: 
     print ' - rClickbinder, something wrong' 
     pass 


if __name__ == '__main__': 
    master = Tk() 
    ent = Entry(master, width=50) 
    ent.pack(anchor="w") 

    #bind context menu to a specific element 
    ent.bind('<Button-3>',rClicker, add='') 
    #or bind it to any Text/Entry/Listbox/Label element 
    #rClickbinder(master) 

    master.mainloop() 
+0

위의 예제에서 불필요하게 'rClickbinder'가 나타납니다. 또는'mainloop()'을 호출하기 전에'rClickbinder (master)'를 호출해야한다고 생각합니까? – scorpiodawg

+0

@scorpiodawg 네가 맞다. 나는 대답을 편집했다. rClickbinder는 나열된 유형의 모든 요소에 대해 상황에 맞는 메뉴를 사용하는 유용한 방법이기 때문에 거기에있다. – bluish

1

생각 나는 stackoverflow에 대한 몇 가지 코드 조각을 기반으로 내 솔루션을 공유 할 것입니다. 테스트 할 최소 응용 프로그램이 포함되어 있습니다.

편집 : 클래스 바인딩이 작동하지 않을 수 있습니다. 그 경우 정규 바인딩을 사용하고 select_all 함수에서 "break"를 반환해야합니다. 셀카의 코드와 푸른 빛이 도는 '<Control-c>', 내 textwidget 오른쪽 버튼으로

import Tkinter as tk 

if 1: # nice widgets 
    import ttk 
else: 
    ttk = tk 

class EntryPlus(ttk.Entry): 
    def __init__(self, *args, **kwargs): 
     ttk.Entry.__init__(self, *args, **kwargs) 
     _rc_menu_install(self) 
     # overwrite default class binding so we don't need to return "break" 
     self.bind_class("Entry", "<Control-a>", self.event_select_all) 
     self.bind("<Button-3><ButtonRelease-3>", self.show_menu) 

    def event_select_all(self, *args): 
     self.focus_force() 
     self.selection_range(0, tk.END) 

    def show_menu(self, e): 
     self.tk.call("tk_popup", self.menu, e.x_root, e.y_root) 

class TextPlus(tk.Text): 
    def __init__(self, *args, **kwargs): 
     tk.Text.__init__(self, *args, **kwargs) 
     _rc_menu_install(self) 
     # overwrite default class binding so we don't need to return "break" 
     self.bind_class("Text", "<Control-a>", self.event_select_all) 
     self.bind("<Button-3><ButtonRelease-3>", self.show_menu) 

    def event_select_all(self, *args): 
     self.focus_force()   
     self.tag_add("sel","1.0","end") 

    def show_menu(self, e): 
     self.tk.call("tk_popup", self.menu, e.x_root, e.y_root) 


def _rc_menu_install(w): 
    w.menu = tk.Menu(w, tearoff=0) 
    w.menu.add_command(label="Cut") 
    w.menu.add_command(label="Copy") 
    w.menu.add_command(label="Paste") 
    w.menu.add_separator() 
    w.menu.add_command(label="Select all")   

    w.menu.entryconfigure("Cut", command=lambda: w.focus_force() or w.event_generate("<<Cut>>")) 
    w.menu.entryconfigure("Copy", command=lambda: w.focus_force() or w.event_generate("<<Copy>>")) 
    w.menu.entryconfigure("Paste", command=lambda: w.focus_force() or w.event_generate("<<Paste>>")) 
    w.menu.entryconfigure("Select all", command=w.event_select_all)   


if __name__ == "__main__": 

    class SampleApp(tk.Tk): 
     def __init__(self, *args, **kwargs): 
      tk.Tk.__init__(self, *args, **kwargs) 

      self.entry = EntryPlus(self) 
      self.text = TextPlus(self) 

      self.entry.pack() 
      self.text.pack() 

      self.entry.insert(0, "copy paste") 
      self.text.insert(tk.INSERT, "copy paste") 

    app = SampleApp() 
    app.mainloop() 
+0

self.tk.call ("tk_popup", self.menu, e.x_root, e.y_root)은보다 읽기 쉬운 self.menu.tk_popup (e.x_root, e.y_root)으로 변환 될 수 있습니다. HTH –

1

감사했다. 저는 평판이 50 개는 아니지만 클릭 한 지점의 위치에 관계없이 올바른 버튼이 기능을 트리거한다는 문제가있었습니다. 텍스트 위젯을 클릭하면 이제 오른쪽 버튼의 팝업가 트리거됩니다

def show_menu(self, e): 
     if e.widget==self.text: 
      self.tk.call("tk_popup", self.menu, e.x_root, e.y_root) 

: 에 의해 그것을 알아 냈어.

관련 문제