簡體   English   中英

Python-如何在Tkinter文本小部件中獲取光標位置

[英]Python - How To Get Cursor Position in Tkinter Text Widget

我想獲取Tkinter.Text插入點的光標位置(行和列),但針對以下特定情況。

問題:我的文本編輯器項目需要對Tkinter.Text自定義撤消/重做。 我為下面的“測試一”和“測試二”輸入了相同的字符串,但是由於Tkinter給出的KeyRelease事件處理程序中的列變量不一致,因此撤消操作不一致。 問題似乎是我輸入的速度太快而無法進行第二次測試,這會產生錯誤的列值。 你能幫我找到問題嗎?

減少錯誤的兩個測試過程:

測試一

    1. 緩慢鍵入此字符串:“一二三”
    1. 按F1查看每個單詞的撤消。
  • 結果:工作正常。 (對我來說至少。重點:緩慢鍵入。)

測試二

    1. 盡快輸入相同的字符串:“一二三”
    1. 按F1查看每個單詞的撤消。
  • 結果:獲取錯誤的列,並且無法正確撤消。 (如果您起初沒有看到錯誤,請重新啟動腳本並重復此步驟,有時快速鍵入有時效果很好。我通常最多嘗試3至4次就可以了。)

問題:這是Tkinter中的bug,還是我不了解Tkinter中的某些特定內容,這些內容會為我的撤消/重做記錄生成一致的列?

from Tkinter import *

class TextView(Text):

    def __init__(self, root):
        Text.__init__(self, root)

        self.history = History(self)
        self.bind("<KeyRelease>", self.keyRelease)

        # used to capture a char at a time in keyRelease.  If space char is pressed it creates a Word object and adds it to undo/redo history.
        self.word = ""

    def keyRelease(self, event):
        if event.keysym == "space":
            self.word += " "
            self.makeWordRecord()
        else:
            self.word += event.char

    def makeWordRecord(self, ):
        if len(self.word):
            index = self.index(INSERT)
            wordEvent = Word(index, self.word)
            self.history.addEvent(wordEvent)
            self.word = ""

    def undo(self, event):
        self.makeWordRecord()
        self.history.undo()

    def redo(self, event):
        self.history.redo()

class History(object):
    def __init__(self, text):
        self.text = text
        self.events = []
        self.index = -1

        # create blank document record, line one, column one, no text
        self.addEvent(Word("1.0", ""))

    def addEvent(self, event):
        if self.index +1 < len(self.events):
            self.events = self.events[:self.index +1]
        self.events.append(event)
        self.index +=1

    def undo(self):
        if self.index > 0:
            self.events[self.index].undo(self.text)
            self.index -=1

    def redo(self):
        if self.index +1  < len(self.events):
            self.index +=1
            self.events[self.index].redo(self.text)

class Word(object):
    def __init__(self, index, word):
        self.index = index
        self.word = word

    def undo(self, text):
        line = self.index.split(".")[0]
        column = int(self.index.split(".")[-1])
        startIndex = line + "." + str(column - len(self.word))
        endIndex = line + "." + str(int(column))
        text.delete(startIndex, endIndex)

    def redo(self, text):
        line = self.index.split(".")[0]
        column = int(self.index.split(".")[-1])
        startIndex = line + "." + str(column - len(self.word))
        text.insert(startIndex, self.word)

if __name__ == "__main__":
    root = Tk()
    root.geometry("400x200+0+0")

    textView = TextView(root)
    textView.pack()
    root.bind("<F1>", textView.undo)
    root.bind("<F2>", textView.redo)

    root.mainloop()

我終於弄清楚發生了什么事,並且與Tkinter無關,但與所有工具包無關。 我現在可以誠實地說,我可以在“最佳編程實踐”中添加以下內容:

不要通過綁定鍵釋放方法來處理鍵事件,而是使用按鍵方法來處理鍵

為什么?

這實際上不是編程問題,而是硬件問題。 當按下一個鍵時,物理鍵會下降。 有一個彈簧可以將鑰匙向上推。 如果那彈簧或鍵盤上的任何東西使鍵慢了200秒鍾,則即使每分鍾輸入60個單詞也可能導致按一種順序鍵入的鍵又以另一種順序返回。 發生這種情況的原因是,彈簧可能略厚,更硬,用得過重甚至是摩卡咖啡會引起更大的阻力。

大小寫也會受到影響。 必須同時按下Shift鍵和另一個鍵以獲得大寫字母。 但是,如果您在釋放鍵時處理鍵,則Shift鍵彈起的速度可能比您要大寫的字符鍵的彈起速度快,這將導致小寫字母的出現。 這也允許字符反轉。 如果在鍵入字符時檢查字符的位置,由於這個原因,您也會得到錯誤的位置。

堅持按鍵。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM