【问题标题】:Python - How To Get Cursor Position in Tkinter Text WidgetPython - 如何在 Tkinter 文本小部件中获取光标位置
【发布时间】:2014-09-11 22:44:05
【问题描述】:

我想获取一个Tkinter.Text的插入点的光标位置(行列),但是针对下面的具体情况。

问题:我的文本编辑器项目需要为 Tkinter.Text 自定义撤消/重做。我为下面的测试一和测试二输入了相同的字符串,但是由于 Tkinter 给出的 KeyRelease 事件处理程序中的列变量不一致,撤消操作不一致。问题似乎是我输入得太快而无法进行第二次测试,这会产生错误的列值。你能帮我找出问题吗?

重现错误的两个测试过程:

测试一个

    1. 慢慢输入这个字符串:'一二三'
    1. 按 F1 可查看撤消的每个单词。
  • 结果:工作正常。 (至少对我来说。重点:慢慢打字。)

测试二

    1. 尽可能快地键入相同的字符串:'一二三'
    1. 按 F1 可查看撤消的每个单词。
  • 结果:获取错误的列并且无法正确撤消。 (如果您一开始没有看到错误,请重新启动脚本并重复此步骤,它有时可以在快速输入时正常工作。我通常最多尝试 3 到 4 次。)

问题:这是 Tkinter 中的错误,还是我不了解 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()

【问题讨论】:

  • 到目前为止,您做了哪些故障排除?你有没有例如输入prints 看看记录了什么?看了history的内容?
  • 我发现了问题。我刚刚学会了永远不要在任何工具包的密钥发布中处理关键事件。请参阅我的答案以了解原因。

标签: python python-2.7 tkinter


【解决方案1】:

我终于弄清楚发生了什么,与 Tkinter 无关,而是所有工具包。我现在可以诚实地说,我可以在最佳编程实践中添加一些东西:

不要通过绑定按键释放方法处理按键事件,而是使用按键方法处理按键

为什么?

这不是真正的编程问题,而是硬件问题。当一个键被按下时,物理键会下降。有一个弹簧将钥匙向上推。如果那个弹簧或键盘上的任何东西导致一个键甚至慢了 200 分之一秒,那么每分钟输入 60 个单词可能会导致按一个顺序键入的键以另一个顺序返回。发生这种情况的原因可能是弹簧稍厚、较硬、过度使用,甚至粘摩卡咖啡会导致更大的阻力。

大小写也会受到影响。必须同时按下 shift 键和另一个键以获得大写字母。但是,如果您在释放键时处理键,则 shift 键的弹出速度可能比您大写的字符键更快,这将导致小写。这也允许字符被反转。如果您在输入字符时检查其位置,也可能因此而得到错误的位置。

坚持按键。

【讨论】:

    猜你喜欢
    • 2023-01-11
    • 2015-07-12
    • 2011-03-14
    • 2014-03-18
    • 1970-01-01
    • 1970-01-01
    • 2019-05-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多