Python 如何让多个tk.text小部件调整到内容高度?

Python 如何让多个tk.text小部件调整到内容高度?,python,tkinter,Python,Tkinter,我正在Mac OS X 10.11.5上使用tcl/tk 8.5.9和python 3.5.1开发gui 我正在尝试创建一种tk.text小部件列表,这些小部件具有固定的宽度和高度,以便在内容发生更改时(由用户更改或以编程方式更改)适合它们的内容。这应该考虑真实的和包装的显示行 我用和的答案来解决这个问题。但是,调整到用户输入仅适用于上次创建的文本小部件。一旦添加了新的文本小部件,所有以前创建的文本小部件不再调整大小 我认为问题可能出在处理bindtag的行中的某个地方。作为tkinter、py

我正在Mac OS X 10.11.5上使用tcl/tk 8.5.9和python 3.5.1开发gui

我正在尝试创建一种tk.text小部件列表,这些小部件具有固定的宽度和高度,以便在内容发生更改时(由用户更改或以编程方式更改)适合它们的内容。这应该考虑真实的和包装的显示行

我用和的答案来解决这个问题。但是,调整到用户输入仅适用于上次创建的文本小部件。一旦添加了新的文本小部件,所有以前创建的文本小部件不再调整大小

我认为问题可能出在处理bindtag的行中的某个地方。作为tkinter、python的新手,以及编程方面的新手,我不确定自己是否正确理解bindtags

非常感谢您的帮助,以下是我的代码:

from tkinter import *

class ResizingText(Text):

def __init__(self, parent, *args, **kwargs):
    Text.__init__(self, master=parent, wrap='word', *args, **kwargs)

    # event binding on resize because text.count method for displaylines returns a wrong number when widget is instantiated
    self.bind('<Configure>', self.update_size)

    bindtags = list(self.bindtags())
    bindtags.insert(2, "custom")
    self.bindtags(tuple(bindtags))
    self.bind_class("custom", "<Key>", self.update_size)

def update_size(self, event):

    if self.winfo_width() > 1:
        self.unbind('<Configure>')

    displaylines = self.count("1.0", "end", "displaylines")
    self.config(height=displaylines)

root = Tk()

dynamic_text_1 = ResizingText(root, width=60)
dynamic_text_1.insert('1.0', "Longer text that is long enough to be wrapped into multiple display lines")
dynamic_text_1.grid(column=0, row=0)
# this text widget does not behave as expected:
# no resizing after user inputs a line break or a line long enough to be wrapped

dynamic_text_2 = ResizingText(root, width=60)
dynamic_text_2.insert('1.0', "Longer text that is long enough to be wrapped into multiple display lines")
dynamic_text_2.grid(column=0, row=1)
# this text widget behaves as expected

root.mainloop()
从tkinter导入*
类大小调整文本(文本):
定义初始化(自、父、*args、**kwargs):
Text.\uuuu init\uuuuu(self,master=parent,wrap='word',*args,**kwargs)
#调整大小时的事件绑定,因为当小部件实例化时,displaylines的text.count方法返回错误的数字
self.bind(“”,self.update_size)
bindtags=list(self.bindtags())
bindtags.插入(2,“自定义”)
self.bindtags(元组(bindtags))
self.bind_类(“自定义”、“自我更新”大小)
def更新_大小(自身、事件):
如果self.winfo_width()大于1:
自动解除绑定(“”)
displaylines=self.count(“1.0”、“结束”、“显示行”)
self.config(高度=显示行)
root=Tk()
动态文本1=调整文本大小(根,宽度=60)
动态文本\u 1.插入('1.0',“足够长的长文本,可以包装到多个显示行中”)
动态文本网格(列=0,行=0)
#此文本小部件的行为不符合预期:
#用户输入换行符或足够长的换行符后,不调整大小
动态文本2=调整文本大小(根,宽度=60)
动态文本2.插入('1.0',“足够长的长文本,可以包装成多个显示行”)
动态文本网格(列=0,行=1)
#此文本小部件的行为符合预期
root.mainloop()

我通过配置bindtags并在每次文本小部件获得焦点时重置关键事件上的事件绑定(FocusIn上的事件绑定)解决了这个问题

可能不是一个干净的解决方案,但似乎效果很好:

from tkinter import *

class ResizingText(Text):
    def __init__(self, parent, *args, **kwargs):
        Text.__init__(self, master=parent, wrap='word', *args, **kwargs)

        # event binding on resize because text.count method for displaylines returns a wrong number when widget is instantiated
        self.bind('<Configure>', self.update_size)
        self.configure_bindtags(event=None)

        # solution: additional binding that resets the binding for <Key> events whenever the text widget gets the focus
        self.bind('<FocusIn>', self.configure_bindtags)

    def configure_bindtags(self, event):
        bindtags = list(self.bindtags())
        bindtags.insert(2, "custom")
        self.bindtags(tuple(bindtags))
        self.bind_class("custom", "<Key>", self.update_size)

    def update_size(self, event):
        if self.winfo_width() > 1:
            self.unbind('<Configure>')

        displaylines = self.count("1.0", "end", "displaylines")
        self.config(height=displaylines)

root = Tk()

dynamic_text_1 = ResizingText(root, width=60)
dynamic_text_1.insert('1.0', "Longer text that is long enough to be wrapped into multiple display lines")
dynamic_text_1.grid(column=0, row=0)

dynamic_text_2 = ResizingText(root, width=60)
dynamic_text_2.insert('1.0', "Longer text that is long enough to be wrapped into multiple display lines")
dynamic_text_2.grid(column=0, row=1)

root.mainloop()
从tkinter导入*
类大小调整文本(文本):
定义初始化(自、父、*args、**kwargs):
Text.\uuuu init\uuuuu(self,master=parent,wrap='word',*args,**kwargs)
#调整大小时的事件绑定,因为当小部件实例化时,displaylines的text.count方法返回错误的数字
self.bind(“”,self.update_size)
self.configure\u bindtags(事件=无)
#解决方案:附加绑定,每当文本小部件获得焦点时重置事件的绑定
self.bind(“”,self.configure\u bindtags)
def配置标签(自我、事件):
bindtags=list(self.bindtags())
bindtags.插入(2,“自定义”)
self.bindtags(元组(bindtags))
self.bind_类(“自定义”、“自我更新”大小)
def更新_大小(自身、事件):
如果self.winfo_width()大于1:
自动解除绑定(“”)
displaylines=self.count(“1.0”、“结束”、“显示行”)
self.config(高度=显示行)
root=Tk()
动态文本1=调整文本大小(根,宽度=60)
动态文本\u 1.插入('1.0',“足够长的长文本,可以包装到多个显示行中”)
动态文本网格(列=0,行=0)
动态文本2=调整文本大小(根,宽度=60)
动态文本2.插入('1.0',“足够长的长文本,可以包装成多个显示行”)
动态文本网格(列=0,行=1)
root.mainloop()

我运行了您的程序,但无法重现您的问题,因为无论我插入的文本长度是多少,高度都会自动重新调整大小,以适应并包装文本。@BillalBEGUERADJ:感谢您的反馈,问题只涉及用户输入换行或换行时的大小调整。最后创建的文本小部件的行为符合我的要求。还有:我在Mac上。我更新了问题以澄清这些要点。