2017-11-08 9 views
3

가 나는 Tkinter의 텍스트 위젯이 수정되었는지 여부를 추적 할 this earlier question에서 다음과 같은 솔루션을 사용 : 그러나복사/붙여 넣기시 크래시가 발생하지 않는 프록시를 사용하여 tkinter 텍스트 위젯을 수정했는지 여부를 어떻게 추적합니까?

import tkinter as tk 


class CustomText(tk.Text): 
    def __init__(self, *args, **kwargs): 
     """A text widget that report on internal widget commands""" 
     tk.Text.__init__(self, *args, **kwargs) 

     # create a proxy for the underlying widget 
     self._orig = self._w + "_orig" 
     self.tk.call("rename", self._w, self._orig) 
     self.tk.createcommand(self._w, self._proxy) 

    def _proxy(self, command, *args): 
     cmd = (self._orig, command) + args 
     result = self.tk.call(cmd) 

     if command in ("insert", "delete", "replace"): 
      self.event_generate("<<TextModified>>") 

     return result 


root = tk.Tk() 
label = tk.Label(root, anchor="w") 
text = CustomText(root, width=40, height=4) 

label.pack(side="bottom", fill="x") 
text.pack(side="top", fill="both", expand=True) 


def onModification(event): 
    chars = len(event.widget.get("1.0", "end-1c")) 
    label.configure(text="%s chars" % chars) 


text.bind("<<TextModified>>", onModification) 

root.mainloop() 

, 내 자신의 코드에 통합 한 후, 난 둘 다 내 코드에서이 문제를 위의 베어 해결책을 발견 . 텍스트 위젯에 붙여 넣으려고하면 프로그램 전체가 중단됩니다. 터미널은 다음과 같은 오류 제공합니다. (위의 파일 경로에서 나는 식별 제거 정보하지만, 그렇지 않으면 그 콘솔에서 바로 복사 된)

Traceback (most recent call last): 
    File "Test.py", line 39, in <module> 
    root.mainloop() 
    File "AppData\Local\Programs\Python\Python36-32\lib\tkinter\__init__.py", line 1277, in mainloop 
    self.tk.mainloop(n) 
    File "Test.py", line 16, in _proxy 
    result = self.tk.call(cmd) 
_tkinter.TclError: text doesn't contain any characters tagged with "sel" 

을 테스트 조금 후

, 당신 밝혀 붙여 넣을 때 텍스트를 선택/강조 표시 한 경우 프로그램을 중단하지 않고 붙여 넣을 수 있습니다.

이 동작은 수정되지 않은 텍스트 위젯에서는 발생하지 않습니다. 텍스트를 선택하지 않고 붙여 넣을 수 있습니다.

내 질문은 어떻게 붙여 넣기가 충돌하지 않도록 위의 솔루션을 수정할 수 있습니까? Tcl/Tk에 익숙하지 않아이 문제를 어떻게 조사해야할지 모르겠습니다. 이것은 Python 3.6.3에 있습니다.

는 (내가 직접이 코드의 원래 저자에 문의 한 것이지만, 거기에는 비공개 메시지 기능은 여기에 없다 내가 새로운 사용자로 덧글을 남길 수 없습니다 밖으로는 변합니다.)

편집 : 내가 가진 이제 실제 코드를 해결하는 대신 솔루션이 덕트 테이프와 함께 유지되는 것처럼 느껴지지만 다음과 같이 나는되며 customText 클래스를 변경 :

return "break"로 끝나는 함수에 "<<Paste>>"를 결합함으로써
class CustomText(tk.Text): 
    def __init__(self, *args, **kwargs): 
     """A text widget that report on internal widget commands""" 
     tk.Text.__init__(self, *args, **kwargs) 

     # create a proxy for the underlying widget 
     self._orig = self._w + "_orig" 
     self.tk.call("rename", self._w, self._orig) 
     self.tk.createcommand(self._w, self._proxy) 
     self.bind("<<Paste>>", self.Paste) 

    def _proxy(self, command, *args): 
     cmd = (self._orig, command) + args 
     result = self.tk.call(cmd) 

     if command in ("insert", "delete", "replace"): 
      self.event_generate("<<TextModified>>") 

     return result 

    def Paste(self, event): 
     tagranges = self.tag_ranges("sel") 
     if tagranges: 
      selectionstart = self.index(tk.SEL_FIRST) 
      selectionend = self.index(tk.SEL_LAST) 
      self.delete(selectionstart, selectionend) 
      self.mark_set(tk.INSERT, selectionstart) 
     self.insert(tk.INSERT, root.clipboard_get()) 
     self.see(tk.INSERT) 
     return "break" 

, 내가 사고의 원인이 무엇에 따라 이벤트를 통과 위젯을 중지 할 수 있으며, 수정 이벤트는 여전히 화재 예상했다. 즐겁게, 나는 return "break" 선 앞에 내 자신의 붙여 넣기 기능을 코딩 할 수 있으며 처음부터 가지고 있어야한다고 생각하는대로 기능합니다.

Windows 문제 (Bryan Oakley를 확인해 주셔서 감사합니다)를 제외하고는이 문제의 원인을 알 수 없습니다.

+1

코드가 제대로 작동합니다. 텍스트 위젯에 있거나 텍스트 위젯에서 선택한 것과 상관없이 충돌이 발생하지 않습니다. 불행히도 테스트 할 창문 기계가 없습니다. –

+0

처음에는 OS 의존적 인 문제를 넘어서서 어떤 문제가 발생했는지 아직 알지 못했지만 솔직한 솔루션으로 편집했습니다. 봐 주셔서 감사합니다! – Marelo

+1

파이썬 3.6의 Windows 10에서 복제 할 수 있습니다. –

답변

0

"<Control-v>""<Control-c>" 이벤트에 바인드 할 수 있습니다.

즉, 사용자가 두 가지 중 하나를 사용하는 경우 다르게 처리하도록 특수 조건을 설정할 수 있습니다.

from tkinter import * 

root = Tk() 

text = Text(root) 
text.pack() 

def callback(*args): 
    print(True) 

text.bind("<Control-v>", callback) 

root.mainloop() 

이 우리가 모르는 다른 키보드 조합에서 잠재적 인 충돌 개방을 단풍이, 해결 방법이 아닌 솔루션의 더 많은 것이다.

아무도 더 좋은 해결책을 알지 못하면 내 대답을 남겨 둘 것입니다.

+0

불행히도, 작동하지 않았습니다. 단지 충돌과 함께 발생하는 콜백을 추가합니다. 예를 들어'text.bind ("", 람다 이벤트 : print ("Paste intercepted"))'는 "Paste intercepted"를 충돌 직전에 콘솔에 출력합니다. 나는 또한''<>''이벤트로 이것을 시도했는데, 같은 결과를 보였다. – Marelo

+1

미안하지만, 나 자신을 분명히하지 않았다. 이러한 이벤트가 발생했을 때 사용자 정의 이벤트 호출을 막는 방법을 어떻게 든 통합해야합니다. 이것이 바로 내 솔루션이 해결책이 아닌 해결책입니다. –

+0

해커 일 뿐이며 실제로 버그를 처리하지는 않지만 작동 코드로 안내하기 때문에이 대답을 받아 들일 것입니다. '' '''을'return "break"로 끝나는 콜백에 바인드하면 이벤트가 커스터마이징 된 위젯을 지나쳐 전파되지 않습니다. 그런 다음 돌아 오기 전에 자신 만의 붙여 넣기 기능을 코딩하여 전체적으로 작동하도록 시뮬레이션 할 수 있습니다 ... 누군가가 더 나은 대답을 내놓으면 나는 행복 할 것입니다. – Marelo