コピー/貼り付けでクラッシュしないプロキシを使用してtkinterテキストウィジェットが変更されたかどうかを追跡するにはどうすればよいですか?

スナックホール

この前の質問の次の解決策を使用して、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に精通していないので、これを調査し始める方法がわかりません。これはPython3.6.3にあります。

(また、このコードの元の作成者に直接連絡したはずですが、ここにはプライベートメッセージング機能がなく、新しいユーザーとしてコメントを残すことはできません。)

編集:私は今作業中のコードを持っていますが、解決策は実際に根本的な問題に対処するのではなく、ダクトテープでまとめられているように感じます。CustomTextクラスを次のように変更しました。

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"

"<<Paste>>"で終わる関数にバインドするreturn "break"ことで、ウィジェットがクラッシュの原因となっているものにイベントを渡さないようにすることができますが、変更イベントは引き続き期待どおりに発生します。面白いことに、return "break"行の前に独自の貼り付け関数をコーディングすることができ、最初からあるはずのように機能します。

明らかにWindowsの問題であることを除いて、この問題の原因はまだわかりません(チェックしてくれてありがとう、Bryan Oakley)。

イーサンフィールド

イベント"<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()

これは、解決策というよりはむしろ回避策です。これにより、私たちが知らない他のキーボードの組み合わせによる潜在的なクラッシュが発生する可能性があります。

より良い解決策を誰かが知らない限り、ここに私の答えを残しておきます。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

Related 関連記事

ホットタグ

アーカイブ