【问题标题】:Making multiple selections in tkinter在 tkinter 中进行多项选择
【发布时间】:2021-05-28 13:08:19
【问题描述】:

有没有办法在 tkinter 中进行多项选择?

代码如下:

from tkinter import *

root = Tk()

text = Text(root , width = 65 , height = 20 , font = "consolas 14")
text.pack()

text.insert('1.0' , "This is the first line.\nThis is the second line.\nThis is the third line.")

mainloop()

在这里,我希望能够从任何我想要的地方选择多个文本。

这是一个解释我的意思的图片(GIF):

有没有办法在 tkinter 中实现这一点?

如果有人能帮助我,那就太好了。

【问题讨论】:

  • 你可以使用text.tag_add(SEL, index)

标签: python tkinter selection


【解决方案1】:

简答:将每个 Text 小部件的 exportselection 属性设置为 False

Tkinter 让您可以使用 Text 小部件以及 Entry 和 Listbox 小部件的 exportselection 配置选项来控制此行为。将其设置为 False 可防止将选择导出到 X 选择,从而允许该小部件在其他小部件获得焦点时保留其选择。

例如:

import tkinter as tk
...
text1 = tk.Text(..., exportselection=False)
text2 = tk.Text(..., exportselection=False)

您可以在这里找到更多信息:http://tcl.tk/man/tcl8.5/TkCmd/options.htm#M-exportselection

【讨论】:

    【解决方案2】:

    我做了一个简短的演示,使用Control 键可以选择多个文本。检查这个:

    import tkinter as tk
    
    
    class SelectableText(tk.Text):
    
        def __init__(self, master, **kwarg):
            super().__init__(master, **kwarg)
            self.down_ind = ''
            self.up_ind = ''
            self.bind("<Control-Button-1>", self.mouse_down)
            self.bind("<B1-Motion>", self.mouse_drag)
            self.bind("<ButtonRelease-1>", self.mouse_up)
            self.bind("<BackSpace>", self.delete_)
    
        def mouse_down(self, event):
            self.down_ind = self.index(f"@{event.x},{event.y}")
    
        def mouse_drag(self, event):
            self.up_ind = self.index(f"@{event.x},{event.y}")
            if self.down_ind and self.down_ind != self.up_ind:
                self.tag_add(tk.SEL, self.down_ind, self.up_ind)
                self.tag_add(tk.SEL, self.up_ind, self.down_ind)
    
        def mouse_up(self, event):
            self.down_ind = ''
            self.up_ind = ''
    
        def delete_(self, event):
            selected = self.tag_ranges(tk.SEL)
            if len(selected) > 2:
                not_deleting = ''
                for i in range(1, len(selected) - 1):
                    if i % 2 == 0:
                        not_deleting += self.get(selected[i-1].string, selected[i].string)
                self.delete(selected[0].string, selected[-1].string)
                self.insert(selected[0].string, not_deleting)
                return "break"
    
    
    root = tk.Tk()
    
    text = SelectableText(root, width=50, height=10)
    text.grid()
    text.insert('end', "This is the first line.\nThis is the second line.\nThis is the third line.")
    
    root.mainloop()
    
    

    所以我试图用Text.delete(index1, index2) 删除每个选择,但是当删除一行中的第一个选择时,索引会发生变化,导致后续delete 删除索引未被选中(或超出特定行的范围.

    我不得不用另一种方法解决 - 首先从第一个选择到最后一个选择删除,就像默认情况下BackSpace 所做的那样,然后将每个未选择的部分放回中间。 Text.tag_ranges 为您提供以这种方式选择的范围列表:

    [start1, end1, start2, end2, ...]
    

    其中每个条目都是带有string 属性(索引)的&lt;textindex object&gt;。因此,您可以将end1start2 之间、end2start3 之间的文本提取到最后,并将它们存储到一个变量(not_deleting)中,这样您就可以将它们重新插入到文本中.

    应该有更好更整洁的解决方案,但现在就是这样......希望它有所帮助。

    【讨论】:

    • 您好,谢谢您的回答。这就像我预期的那样工作,但是当我尝试删除所选文本时,它也会删除未选中的文本。有什么办法可以避免吗?
    • @Lenovo360 我添加了一个删除功能。现在它应该与删除一起使用。但是如果你想做其他的事情,比如复制,你需要定义另一个函数来覆盖默认的。
    • @quioxuan zhang:文本小部件不会删除所有选定的项目。当我做出 5 个选择并按下 BackSpace 键时,只有 3 个选择被删除。有没有办法解决这个问题?
    • @Lenovo360 现在应该没问题了。我稍微改变了逻辑。
    • @Lenovo360 我试着解释一下。如果有任何不清楚的地方,请告诉我。
    【解决方案3】:

    对于张巧轩提出的delete_方法,我建议像这样循环使用Text.tag_nextrange方法:

    def delete_sel(self):        
    while 1:
        result = self.tag_nextrange(tk.SEL, 1.0)           
        if result :
            self.delete(result[0] , result[1])
        else :
            break
    

    对于那些想要添加缺失功能的人:

    • 改变滑动方向时的选择修正

    • 考虑到双击

    看这里:French site

    【讨论】:

      猜你喜欢
      • 2018-11-22
      • 2022-06-11
      • 1970-01-01
      • 2020-06-23
      • 1970-01-01
      • 1970-01-01
      • 2017-06-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多