【问题标题】:Tkinter Resize text to contentsTkinter 将文本大小调整为内容
【发布时间】:2012-07-18 14:50:34
【问题描述】:

是否可以让 Tkinter 文本小部件调整大小以适应其内容?

ie:如果我放 1 行文字,它会缩小,但如果我放 5 行,它会变长

【问题讨论】:

    标签: python tkinter


    【解决方案1】:

    我能想到的唯一方法是每次用户在 Text 小部件中输入文本时计算宽度和高度,然后将小部件的大小设置为该值。但这里的限制是只有等宽字体才能正常工作,但无论如何:

    import Tkinter
    
    class TkExample(Tkinter.Frame):
       def __init__(self, parent):
          Tkinter.Frame.__init__(self, parent)
          self.init_ui()
    
       def init_ui(self):
          self.pack()
          text_box = Tkinter.Text(self)
          text_box.pack()
          text_box.bind("<Key>", self.update_size)
    
       def update_size(self, event):
          widget_width = 0
          widget_height = float(event.widget.index(Tkinter.END))
          for line in event.widget.get("1.0", Tkinter.END).split("\n"):
             if len(line) > widget_width:
                widget_width = len(line)+1
          event.widget.config(width=widget_width, height=widget_height)
    
    if __name__ == '__main__':
        root = Tkinter.Tk()
        TkExample(root)
        root.mainloop()
    

    【讨论】:

    • 是的,我就是这么想的。希望我在某个地方错过了一些方法。嗯,我会活下去的。
    • 您可以使用font_measure 获取可变宽度字体中文本行的实际宽度。此外,这会受到您的绑定在插入文本之前触发的事实的影响。您需要在 &lt;KeyRelease&gt; 上进行绑定或摆弄绑定标签,以便您的绑定在类绑定之后发生。
    • lines = event.widget.get("1.0", Tkinter.END).split("\n"); widget_height = max(imap(len, lines)+1
    • 标签呢?以我的经验,在Tkinter.Text 为我使用的默认单色字体中,这些字符与其他 8 个字符一样长(在 OS X 10.10 上)。
    【解决方案2】:

    编辑:短方法:

    text.pack(side="top", fill="both", expand=True, padx=0, pady=0)
    

    通过重复使用 sc0tt 的答案和 Bryan Oakley 的答案Get of number of lines of a Text tkinter widget,我们可以得到这个即用型代码(张贴在这里以供将来参考)也适用于 比例字体

    import Tkinter as Tk
    import tkFont
    
    class Texte(Tk.Text):
        def __init__(self, event=None, x=None, y=None, size=None, txt=None, *args, **kwargs):
            Tk.Text.__init__(self, master=root, *args, **kwargs)
            self.font = tkFont.Font(family="Helvetica Neue LT Com 55 Roman",size=35)
            self.place(x=10,y=10)
            self.insert(Tk.INSERT,' blah ')
            self.config(font=self.font)
            self.update_size(event=None)
            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):
            width=0
            lines=0
            for line in self.get("1.0", "end-1c").split("\n"):
                width=max(width,self.font.measure(line))
                lines += 1
            self.config(height=lines)
            self.place(width=width+10)
    
    root = Tk.Tk()
    root.geometry("500x500")
    Texte()
    root.mainloop()
    

    【讨论】:

    • 您从我对另一个问题的回答中复制了一半的代码。引用或链接到另一个问题会很好。无论如何,您可能想在回答中提到这仅适用于固定宽度的字体。您可以通过实际测量每行的宽度和高度来使其与比例字体一起使用。
    • 是的,当然,我现在就添加一个引文。顺便说一句,我没有在这里发帖表示赞成或类似的事情(我已经提到我重复使用了 sc0tt 接受的答案,所以我从一开始就声称我没有亲自发明任何东西)。如果有人以后需要重复使用,我在这里发布仅供参考。
    • 哦@BryanOakley,我没有注意到它只适用于固定宽度......真可惜。你知道如何让它适应成比例的字体
    • 使用self.font.measure(line) @BryanOakley,我可以测量宽度(以像素为单位),但self.config(width=..., ) 无法使用,对吧?
    • 可以获取字体,使用font_measure方法获取渲染一行文本所需的像素数量。或者,您可以使用文本小部件的dlineinfo 方法。这仅适用于可见线,但我认为在这种特定情况下这不是问题。获取每条线的尺寸,然后做一些数学运算。
    【解决方案3】:

    在 Google 搜索的顶部找到了该主题,因此,可能需要此主题的人会找到它。即使经过几个小时的搜索也找不到答案。所以这是我想出的 HACK。

    我想要一个弹出窗口,它可以正确地围绕文本小部件中任何未知但预先确定的文本,而不是用户输入。此外,Text 小部件需要在其文本内容周围正确地适应自身。

    tkinter.Label 效果很好,但它没有 tkinter.Text.tag_configuretkinter.Text.tag_bind,我需要用 tkinter 的富文本标签替换一些 HTML 标签。 tkinter.Text 有富文本标签,但不能很好地扩展,而tkinter.Label 可以很好地扩展,但没有富文本标签。此外,我只是讨厌滚动条和自动换行,除非真的需要它们。这正是我想要的。虽然,这只是这个论坛的一个非常简单的工作摘要。适用于任何字体。仅在 Ubuntu 13.10 (Linux) 中使用 Python 3.3 进行了测试。

    #!/usr/bin/env python3
    
    import tkinter as tk
    
    class MyFrame(tk.Frame):
        def __init__(self):
            tk.Frame.__init__(self)
    
            root = self.master
            root.title("My Window Title")
    
            # Pack Frame into root window and make it expand in "both" x and y
            self.pack(side="top", fill="both", expand=True, padx=10, pady=10)
            # Statistical weight of 1 = 100% for cell (0, 0) to expand 100%
            self.grid_columnconfigure(0, weight=1)
            self.grid_rowconfigure(0, weight=1)
    
            # The string text
            text = """Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed
    diam nonummy nibh euismod tincidunt ut laoreet dolore magna
    aliquam erat volutpat. Ut wisi enim ad minim veniam, quis
    nostrud exerci tation ullamcorper suscipit lobortis nisl ut
    aliquip ex ea commodo consequat. Duis autem vel eum iriure
    dolor in hendrerit in vulputate velit esse molestie consequat,
    vel illum dolore eu feugiat nulla facilisis at vero eros et
    accumsan et iusto odio dignissim qui blandit praesent luptatum
    zzril delenit augue duis dolore te feugait nulla facilisi. Nam
    liber tempor cum soluta nobis eleifend option congue nihil
    imperdiet doming id quod mazim placerat facer possim assum.
    Typi non habent claritatem insitam; est usus legentis in iis qui
    facit eorum claritatem. Investigationes demonstraverunt lectores
    legere me lius quod ii legunt saepius. Claritas est etiam
    processus dynamicus, qui sequitur mutationem consuetudium
    lectorum. Mirum est notare quam littera gothica, quam nunc
    putamus parum claram, anteposuerit litterarum formas
    humanitatis per seacula quarta decima et quinta decima. Eodem
    modo typi, qui nunc nobis videntur parum clari, fiant sollemnes
    in futurum."""
    
            # Add a tk.Text widget to Frame (self) and its configuration
            textwidget = tk.Text(self, wrap="none", font=("Comic Sans MS", 12),
                                 padx=10, pady=10)
            textwidget.grid(row=0, column=0, sticky="nesw")
            # Add the text to textwidget and disable editing
            textwidget.insert(tk.END, text)
            textwidget.config(state=tk.DISABLED)
    
            # Here is where the HACK begins
            def is_scroll(wh, lower, upper):
                nonlocal size
                size[wh][0] = upper < '1.0' or lower > '0.0'
                size[wh][1] += 20 * size[wh][0] # += 1 for accuracy but slower
            # Call the is_scroll function when textwidget scrolls
            textwidget.config(xscrollcommand=lambda *args: is_scroll('w', *args),
                              yscrollcommand=lambda *args: is_scroll('h', *args))
    
            # Add a tk.Button to the Frame (self) and its configuration
            tk.Button(self, text="OK", command=self.quit).grid(row=1, column=0,
                                                               sticky="we")
    
            # For reasons of magic, hide root window NOW before updating
            root.withdraw()
    
            # Initially, make root window a minimum of 50 x 50 just for kicks
            root.geometry('50x50')
            size = {'w': [False, 50], 'h': [False, 50]}
            # Update to trigger the is_scroll function
            root.update()
            while size['w'][0] or size['h'][0]:
                # If here, we need to update the size of the root window
                root.geometry('{}x{}'.format(size['w'][1], size['h'][1]))
                root.update()
    
            # Center root window on mouse pointer
            x, y = root.winfo_pointerxy()
            root.geometry('+{}+{}'.format(x-size['w'][1]//2, y-size['h'][1]//2))
    
            # Now reveal the root window in all its glory
            root.deiconify()
    
            # Print textwidget dimensions to the console
            print(textwidget.winfo_width(), textwidget.winfo_height())
    
    def main():
        """Show main window."""
        MyFrame().mainloop()
    
    if __name__ == '__main__':
        main()
    

    解释: 诀窍是不要费心尝试直接扩展或缩小文本小部件是徒劳的。答案有点违反直觉,因为一个人的第一个想法是直接进入那个 Text 小部件并对其做一些事情。相反,展开根(最外层)窗口(在本例中为self.master),只保留 Text 小部件。轻松愉快。

    将文本小部件 ("nesw") 粘贴到框架上,该小部件在根窗口中被打包为 100% 扩展。随着根窗口的展开,其中的 Frame 和 Text 小部件也会展开。但是,当您扩展根窗口时,请测试 Text 小部件的 xscrollcommandyscrollcommandlowerupper 边界是否消失(不再滚动)。这些命令将lowerupper 参数作为百分位数发送到滚动条所需的回调函数,通常是tkinter.Scrollbar.set。但是,我们使用这些命令是因为我们根本不想要滚动条或任何滚动。我们想要一个完美的配合。

    如果lowerupper 边界消失(下= 1.0),这意味着我们的文本小部件周围有一个完美匹配的窗口,它也完美匹配其文本内容。多田!

    添加了一个按钮,以证明即使添加了其他小部件,它仍然可以正常工作。删除一些文本,看看它是否仍然完美契合。

    【讨论】:

      【解决方案4】:

      基于 sc0tt 的帖子,如果您不使用换行符(例如,只使用固定宽度并将高度作为唯一的扩展变量),该辅助函数可以很好地工作:

      def update_height(event):
          text_height = (str(event.widget.index('1.end')) )
          text_int = int(re.search(".(\d+)", text_height).group(1))
          widget_height = int(int(text_int)/160) + 1
          event.widget.config(height=widget_height)
      

      【讨论】:

        猜你喜欢
        • 2017-12-29
        • 2022-01-15
        • 2013-07-10
        • 1970-01-01
        • 2017-03-13
        • 1970-01-01
        • 2020-01-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多