Nor*_*tfi 8 python text tkinter offset
我想删除文本小部件的部分内容,仅使用字符偏移量(或字节,如果可能)。
我知道如何对线条、单词等进行操作。查看了很多文档:
这是一个例子:
import tkinter as tk
root = tk.Tk()
text = tk.Text(root)
txt = """Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Suspendisse enim lorem, aliquam quis quam sit amet, pharetra porta lectus.
Nam commodo imperdiet sapien, in maximus nibh vestibulum nec.
Quisque rutrum massa eget viverra viverra. Vivamus hendrerit ultricies nibh, ac tincidunt nibh eleifend a. Nulla in dolor consequat, fermentum quam quis, euismod dui.
Nam at gravida nisi. Cras ut varius odio, viverra molestie arcu.
Pellentesque scelerisque eros sit amet sollicitudin venenatis.
Proin fermentum vestibulum risus, quis suscipit velit rutrum id.
Phasellus nisl justo, bibendum non dictum vel, fermentum quis ipsum.
Nunc rutrum nulla quam, ac pretium felis dictum in. Sed ut vestibulum risus, suscipit tempus enim.
Nunc a imperdiet augue.
Nullam iaculis consectetur sodales.
Praesent neque turpis, accumsan ultricies diam in, fermentum semper nibh.
Nullam eget aliquet urna, at interdum odio. Nulla in mi elementum, finibus risus aliquam, sodales ante.
Aenean ut tristique urna, sit amet condimentum quam. Mauris ac mollis nisi.
Proin rhoncus, ex venenatis varius sollicitudin, urna nibh fringilla sapien, eu porttitor felis urna eu mi.
Aliquam aliquam metus non lobortis consequat.
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Aenean id orci dui."""
text.insert(tk.INSERT, txt)
def test_delete(event=None):
text.delete() # change this line here
text.pack(fill="both", expand=1)
text.pack_propagate(0)
text.bind('<Control-e>', test_delete)
root.mainloop()
Run Code Online (Sandbox Code Playgroud)
它在文本小部件内的变量内显示示例文本。我使用单键绑定来测试一些可能的方法,以对该文本片段执行我想要的操作。
我尝试了很多东西,包括文档和我自己的绝望:
text.delete(0.X)
: 其中 X 是任意数字。我想既然lines是1.0
,也许使用0.X只能对字符起作用。它只适用于单个字符,无论 X 是什么(即使是一个很大的数字)。text.delete(1.1, 1.3)
:这作用在同一行,因为我试图看看它是否会删除同一行上任意方向的 3 个字符。它删除 2 个字符而不是 3 个字符,方法是在第一行开头省略一个字符,然后删除之后的2 个字符。text.delete("end - 9c")
:只在最后(最后一行)起作用,省略从EOF开始的7个字符,然后删除后面的一个字符。text.delete(0.1, 0.2)
: 不做任何事情。其他0.X, 0.X
组合的结果相同。我试图实现的目标的示例:
使用上面的示例文本会花费太长的时间,因此让我们考虑一个较小的字符串,例如“hello world”。现在假设我们使用以 1 开头的索引(没关系,但让事情更容易解释),第一个字符是“h”,最后一个字符是“d”。所以说我使用诸如“2-7”之类的字符范围,那就是“ello w”。说我想做“1-8”?->“hello wo”,现在从末尾开始,“11-2”,“hello world”。
这基本上类似于f.tell() 和 f.seek() 所做的事情。我想做类似的事情,但仅使用文本小部件内部的内容,然后对这些字节/字符范围执行某些操作(在上面的示例中,我正在删除它们等)。
长话短说
您可以使用类似于f.tell()
给出起始索引的相对索引,然后添加或删除行或字符。例如,text.delete("1.0", "1.0+11c")
(“1.0”加 11 个字符)
文本小部件索引的规范文档位于 tcl/tk 手册页中名为Indices的部分中。
text.delete(0.X):其中 X 是任意数字。我想既然行数是 1.0,也许使用 0.X 只能对字符起作用。它只适用于单个字符,无论 X 是什么(即使是一个很大的数字)。
我不知道你所说的“因为线路是1.0”是什么意思。索引的第一部分是行号,第二部分是字符号。行从 1 开始计数,字符从 0 开始计数。因此,小部件的第一个字符是"1.0"
。第 2 行的第一个字符是"2.0"
等。
但是,是的,text.delete
使用单个索引只会删除一个字符。这就是定义的行为。
text.delete(1.1, 1.3):这在同一行上执行,因为我试图看看它是否会在同一行上的任何方向上删除 3 个字符。
删除方法被记录为从第一个索引删除到最后一个索引之前的字符:
“从文本中删除一系列字符。如果同时指定了index1和index2,则删除从index1给定的字符开始到index2之前的所有字符”
text.delete("end - 9c"):只在末尾(最后一行)起作用,并省略从EOF开始的7个字符,然后删除之后的单个字符。
是的。同样,给定的单个索引delete
将仅删除单个字符。
text.delete(0.1, 0.2):不执行任何操作。其他 0.X、0.X 组合的结果相同。
0.1
是无效索引。索引是一个字符串,而不是浮点数,第一个数字应该是 1 或更大。Tkinter 必须将该数字转换为大于或等于 1 的整数。因此, 和0.1
都0.2
转换为 Mean "1.0"
。正如我之前所说,该delete
方法在第二个索引之前停止,因此您要删除 character 之前的所有内容"1.0"
。
使用上面的示例文本会花费太长的时间,因此让我们考虑一个较小的字符串,例如“hello world”。现在假设我们使用以 1 开头的索引(没关系,但让事情更容易解释),第一个字符是“h”,最后一个字符是“d”。所以说我使用诸如“2-7”之类的字符范围,那就是“ello wo”。说我想做“1-8”?->“hello wo”,现在从末尾开始,“11-2”,“hello world”。
如果"hello world"
从字符位置开始"1.0"
,并且您想使用相对索引来删除范围字符,则可以使用类似text.delete("1.0", "1.0+11c")
(“1.0”加11个字符)的内容来删除它
Based on my own relentless testing and other answers here, I managed to get to a solution.
import tkinter as tk
from tkinter import messagebox # https://stackoverflow.com/a/29780454/12349101
root = tk.Tk()
main_text = tk.Text(root)
box_text = tk.Text(root, height=1, width=10)
box_text.pack()
txt = """hello world"""
len_txt = len(
txt) # get the total length of the text content. Can be replaced by `os.path.getsize` or other alternatives for files
main_text.insert(tk.INSERT, txt)
def offset():
inputValue = box_text.get("1.0",
"end-1c") # get the input of the text widget without newline (since it's added by default)
# focusing the other text widget, deleting and re-insert the original text so that the selection/tag is updated (no need to move the mouse to the other widget in this example)
main_text.focus()
main_text.delete("1.0", tk.END)
main_text.insert(tk.INSERT, txt)
to_do = inputValue.split("-")
if len(to_do) == 1: # if length is 1, it probably is a single offset for a single byte/char
to_do.append(to_do[0])
if not to_do[0].isdigit() or not to_do[1].isdigit(): # Only integers are supported
messagebox.showerror("error", "Only integers are supported")
return # trick to prevent the failing range to be executed
if int(to_do[0]) > len_txt or int(to_do[1]) > len_txt: # total length is the maximum range
messagebox.showerror("error",
"One of the integers in the range seems to be bigger than the total length")
return # trick to prevent the failing range to be executed
if to_do[0] == "0" or to_do[1] == "0": # since we don't use a 0 index, this isn't needed
messagebox.showerror("error", "Using zero in this range isn't useful")
return # trick to prevent the failing range to be executed
if int(to_do[0]) > int(to_do[1]): # This is to support reverse range offset, so 11-2 -> 2-11, etc
first = int(to_do[1]) - 1
first = str(first).split("-")[-1:][0]
second = (int(to_do[0]) - len_txt) - 1
second = str(second).split("-")[-1:][0]
else: # use the offset range normally
first = int(to_do[0]) - 1
first = str(first).split("-")[-1:][0]
second = (int(to_do[1]) - len_txt) - 1
second = str(second).split("-")[-1:][0]
print(first, second)
main_text.tag_add("sel", '1.0 + {}c'.format(first), 'end - {}c'.format(second))
buttonCommit = tk.Button(root, text="use offset",
command=offset)
buttonCommit.pack()
main_text.pack(fill="both", expand=1)
main_text.pack_propagate(0)
root.mainloop()
Run Code Online (Sandbox Code Playgroud)
Now the above works, as described in the "hello world" example in my post. It isn't a 1:1 clone/emulation of f.tell() or f.seek(), but I feel like it's close.
The above does not use text.delete
but instead select the text, so it's visually less confusing (at least to me).
It works with the following offset type:
11-2
-> 2-11
so the order does not matter2-11
, 1-8
, 8-10
...10
or 10-10
so it can support single char/byteNow the main thing I noticed, is that '1.0 + {}c', 'end - {}c'
where {}
is the range, works by omitting its given range.
If you were to use 1-3
as a range on the string hello world
it would select ello wor
. You could say it omitted h
and ld\n
, with the added newline by Tkinter (which we ignore in the code above unless it's part of the total length variable). The correct offset (or at least the one following the example I gave in the post above) would be 2-9
.
P.S: For this example, clicking on the button after entering the offsets range is needed.
归档时间: |
|
查看次数: |
603 次 |
最近记录: |