python - 使用 Tkinter Text 索引表达式删除最后一行文本

标签 python tkinter widget

我有一个文本小部件,它在程序运行时显示信息。我想添加功能,允许我用新行覆盖文本小部件的最后一行。我的代码如下所示:

class TextRedirector(object):
   def __init__(self, text_widget):
      self.text_widget = text_widget
   def write(self, the_string):
      self.text_widget.configure(state="normal")
      self.text_widget.insert("end", the_string)
      self.text_widget.see(END)
      self.text_widget.configure(state="disabled")
   def overwrite(self, the_string):
      self.text_widget.configure(state="normal")
      self.text_widget.delete("end-1l linestart+1c", "end")
      self.text_widget.insert("end", the_string)
      self.text_widget.see(END)
      self.text_widget.configure(state="disabled")

How do I get the line and column of the end position of text in Tkinter? -- 我看过这篇文章,其中 Bryan Oakley 似乎用 textwidget.delete("end-1c linestart", "end") 回答了我的问题。 ,但是当我使用它时,文本会交替放置在最后一行的末尾和实际覆盖最后一行。也就是说,一半的时候起作用,一半的时候新文本拍在旧文本的末尾。我对文本小部件的索引表达式的理解(在 http://effbot.org/tkinterbook/text.htm 中简要介绍)是“end-1c linestart”的意思是“结束,后一个字符,行的开头”,所以我不明白为什么它会这样到一行文本的末尾,并且仅每隔一次。每一步的结果看起来都是这样的(每个部分都是整个文本小部件的更新版本,只有最后几行被修改):

!!!!! Settings Have Been Backed Up !!!!!

Computing coordinates...

Coordinates have been computed.

iteration: 1 / 42
-----

!!!!! Settings Have Been Backed Up !!!!!

Computing coordinates...

Coordinates have been computed.

iteration: 1 / 42iteration: 2 / 42
-----

!!!!! Settings Have Been Backed Up !!!!!

Computing coordinates...

Coordinates have been computed.
iteration: 3 / 42
-----

!!!!! Settings Have Been Backed Up !!!!!

Computing coordinates...

Coordinates have been computed.iteration: 4 / 42
-----

我尝试使用self.text_widget.delete("end-1l linestart+1c", "end") 。这几乎可行,但我最终得到

!!!!! Settings Have Been Backed Up !!!!!

Computing coordinates...

Coordinates have been computed.

iteration: 1 / 42
-----

!!!!! Settings Have Been Backed Up !!!!!

Computing coordinates...

Coordinates have been computed.

iteration: 1 / 42
iteration: 2 / 42
-----

!!!!! Settings Have Been Backed Up !!!!!

Computing coordinates...

Coordinates have been computed.

iteration: 1 / 42
iiteration: 3 / 42
-----

!!!!! Settings Have Been Backed Up !!!!!

Computing coordinates...

Coordinates have been computed.

iteration: 1 / 42
iiteration: 4 / 42

我已经尝试了一些其他的事情,尽我所能地使用这些索引表达式,但我还没有解决问题。我尝试在覆盖函数中添加 if 语句来处理可能位于小部件末尾的文本的不同情况,例如,如果它以空行或两个空行等结尾。我也没有成功。

为了充分披露,我可能会提到我正在使用此文本小部件作为命令行打印输出的替代品。因此,该类的名称为 TextRedirector。我认为这对当前的问题没有任何影响,但错误的假设可能是让我首先来到这里的原因......课后的行是这样的:

sys.stdout = TextRedirector(self.textbox)

self.textbox 是在定义类之前创建的文本小部件。

更新:我尝试保存上次插入文本之前的索引,并基于该索引构建一个字符串表达式以删除最后一行。结果仍然不完美。

class TextRedirector(object):
   def __init__(self, text_widget):
      self.text_widget = text_widget
      self.index_before_last_print = ""
   def write(self, the_string):
      self.index_before_last_print = self.text_widget.index("end")
      self.text_widget.configure(state="normal")
      self.text_widget.insert("end", the_string)
      self.text_widget.see(END)
      self.text_widget.configure(state="disabled")
   def overwrite(self, the_string):
      self.text_widget.configure(state="normal")
      self.text_widget.delete(self.index_before_last_print + "-1c linestart+1c", "end")
      self.index_before_last_print = self.text_widget.index("end")
      self.text_widget.insert("end", the_string)
      self.text_widget.see(END)
      self.text_widget.configure(state="disabled")

结果如下

!!!!! Settings Have Been Backed Up !!!!!

Computing coordinates...

Coordinates have been computed.

iteration: 1 / 42
-----

!!!!! Settings Have Been Backed Up !!!!!

Computing coordinates...

Coordinates have been computed.

iiteration: 2 / 42
-----

!!!!! Settings Have Been Backed Up !!!!!

Computing coordinates...

Coordinates have been computed.

iiteration: 3 / 42
-----

!!!!! Settings Have Been Backed Up !!!!!

Computing coordinates...

Coordinates have been computed.

iiteration: 4 / 42

最佳答案

更新:下面描述的行为记录在 Tcl/Tk 文档中,此处:https://www.tcl.tk/man/tcl8.6/TkCmd/text.htm 。具体来说,引用小部件中最后一个换行符之后位置的插入实际上发生在 pathName insert 文档中声明的该换行符之前; pathName delete 文档指出,不会给小部件留下最终换行符的删除操作将被静默修改以保留最终换行符。

原答案:

我遇到了同样的问题,并且找到了适合我的解决方案。太尔;博士: Tk 文本小部件在插入和插入时有一些令人费解的(对我而言)不规则之处 在末尾位置删除,但如果您总是附加新内容 前导(而不是尾随)换行符,它应该按照您的预期运行。 具体来说,text.delete("end-1l","end") 后跟 text.insert("end",u"\nContent") 将替换最后一行。

通过在 Wish(Tk shell)和 Python 2.7 中试验文本小部件, 我发现:

1) 新创建的文本小部件包含换行符。你不能轻易删除 它,如果你以某种方式设法做到这一点,该小部件将表现得非常好 此后很奇怪。

>>> import Tkinter as tk
>>> root = tk.Frame()
>>> t = tk.Text(root)
>>> t.grid()
>>> root.grid()
>>> t.get('1.0','end')
u'\n'
>>> t.delete('1.0','end')
>>> t.get('1.0','end')
u'\n'

这真是一个惊喜! “从头开始删除所有内容”的哪一部分 到最后”你不明白吗,Tk?

2) “末尾”处的插入实际上是插入到最后一个换行符之前。这 似乎与 Tk 文档相冲突,这表明 “结束”位置是指紧接着之后的字符位置 小部件中的最后一个换行符。

>>> t.insert('end',u"\nA line")
>>> t.get('1.0',"end')
u'\nA line\n'

虽然我们想在最后插入,但插入实际上发生了 最后一个换行符之前。

>>> t.insert('end',u"\nLine 2") 
>>> t.get('1.0','end')
u'\nA line\nLine 2\n'

而且这种行为似乎是一致的。如果我们尝试删除一行怎么办?出色地 以“直观”的方式做到这一点:从“end”备份一行并从 那里“结束”:

>>> t.delete('end-1l','end')
>>> t.get('1.0','end')
u'\nA line\n'

我们回到了之前的状态,这是个好消息!另一个插入 将插入的行放在预期的位置:

>>> t.insert('end',u"\nA new line")
>>> t.get('1.0','end')
u'\nA line\nA new line\n'

但是,只有当我们使用前导换行符添加行时,这才按预期工作。 如果我们使用尾随换行符添加它们,文本将被附加到 上一行,并且附加的尾随换行符被添加到 小部件:

>>> t.insert('end',u"Trailing newline\n")
>>> t.get('1.0','end')
u'\nA line\nA new lineTrailing newline\n\n'

如果您相信 Tk 文档,这不是您所期望的 - 您 期望在“末尾”插入会将您的测试插入之后 最后的换行符。但可惜的是,你错了。

以下完整的测试程序显示一个文本小部件,以及一个 输入字段和两个按钮,其中一个按钮将输入字段中的一行添加到 小部件,另一个覆盖小部件的最后一行 输入字段文本。 addLine() 和replaceLastLine() 函数实现 以直接的方式表现这些行为。开头的空行 这个小部件是一个小烦恼,你可以通过这样做来解决 t.delete("1.0","1.0+1c"),但仅在将一些文本插入小部件之后

import Tkinter as tk
root = tk.Frame()
t = tk.Text(root)
t.grid(row=0,column=0,columnspan=3)
root.grid()

def addLine():
  msg = lineField.get()
  t.insert("end",u"\n{}".format(msg))

def replaceLastLine():
  msg = lineField.get()
  t.delete("end-1l","end")
  t.insert("end",u"\n{}".format(msg))

lineField = tk.Entry(root)
lineField.grid(row=1,column=0)

addBtn = tk.Button(root,text="Add line",command=addLine)
addBtn.grid(row=1,column=1)

replBtn = tk.Button(root,text="Replace line",command=replaceLastLine)
replBtn.grid(row=1,column=2)

tk.mainloop()

关于python - 使用 Tkinter Text 索引表达式删除最后一行文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43561558/

相关文章:

ios - 将 "App Groups"权限添加到 Today 扩展小组件的 App ID

javascript - 当用户浏览到另一个页面(同一站点)时,模态音频播放器会继续流式传输而不会中断

python - Django-rest-framework 在没有相关字段的情况下序列化多个查询

python - 从 tk Canvas 保存对象

python - AEoid 与 Python 2.7 多线程兼容吗?

python - tkinter "scrolledtext"复制粘贴不能可靠地工作

python - 编辑新 Toplevel 窗口的内容

android - 如何在我的 Android Widget 类中构建我的 onReceive 方法来切换 ImageView 的图像?

python - 扩大 Pandas 数据框,类似于 Pivot 或 Stack/Unstack

python - Keras:在新实验中重复使用经过训练的权重