windows 使用自动换行创建可调整大小的/多行 Tkinter/ttk 标签

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4011354/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 15:28:29  来源:igfitidea点击:

Create resizable/multiline Tkinter/ttk Labels with word wrap

pythonwindowstkinterttk

提问by Malcolm

Is it possible to create a multi-line label with word wrap that resizes in sync with the width of its parent? In other words the wordwrap behavior of Notepad as you change the width of the NotePad window.

是否可以创建一个自动换行的多行标签,其大小与父标签的宽度同步?换句话说,当您更改记事本窗口的宽度时,记事本的自动换行行为。

The use case is a dialog that needs to present a block of multi-line text (instructions) in its entirety without having the text clipped or resorting to scrollbars. The parent container will have enough vertical space to accomodate narrow widths.

用例是一个对话框,它需要完整地呈现多行文本(指令)块,而不需要剪切文本或求助于滚动条。父容器将有足够的垂直空间来容纳较窄的宽度。

I've been experimenting with Tkinter Label and Message widgets and the ttk Label widget without success. It seems that I need to hard code a pixel wraplength value vs. have these controls auto wordwrap when their text reaches the right edge of their containers. Certainly Tkinters geometry managers can help me auto-resize my labels and update their wraplength values accordingly?

我一直在尝试使用 Tkinter Label 和 Message 小部件以及 ttk Label 小部件,但没有成功。似乎我需要硬编码一个像素环绕长度值,而不是让这些控件在文本到达其容器的右边缘时自动换行。Tkinters 几何管理器当然可以帮助我自动调整标签大小并相应地更新它们的包裹长度值?

Should I be looking at the Text widget instead? If so, is it possible to hide the border of a Text widget so I can use it as a multi-line label with wordwrap?

我应该查看 Text 小部件吗?如果是这样,是否可以隐藏文本小部件的边框,以便我可以将其用作带有自动换行的多行标签?

Here's a prototype of how one might do what I described above. It was inspired by Bryan Oakley's tip to use the Text widget and the following post on Stackoverflow: In python's tkinter, how can I make a Label such that you can select the text with the mouse?

这是一个如何做我上面描述的事情的原型。它的灵感来自 Bryan Oakley 使用 Text 小部件的提示以及 Stackoverflow 上的以下帖子: 在 python 的 tkinter 中,我如何制作一个标签,以便您可以用鼠标选择文本?

from Tkinter import *
master = Tk()

text = """
If tkinter is 8.5 or above you'll want the selection background to appear like it does when the widget is activated. Comment this out for older versions of Tkinter.

This is even more text.

The final line of our auto-wrapping label that supports clipboard copy.
""".strip()

frameLabel = Frame( master, padx=20, pady=20 )
frameLabel.pack()
w = Text( frameLabel, wrap='word', font='Arial 12 italic' )
w.insert( 1.0, text )
w.pack()

# - have selection background appear like it does when the widget is activated (Tkinter 8.5+)
# - have label background color match its parent background color via .cget('bg')
# - set relief='flat' to hide Text control borders
# - set state='disabled' to block changes to text (while still allowing selection/clipboard copy)
w.configure( bg=master.cget('bg'), relief='flat', state='disabled' )

mainloop()

采纳答案by Bryan Oakley

No, there is no feature built-in to Tk to auto-word-wrap labels. However, it's doable by binding to the <Configure>event of the label and adjusting the wrap length then. This binding will fire every time the label widget is resized.

不,Tk 没有内置功能来自动换行标签。但是,它可以通过绑定到<Configure>标签的事件然后调整包装长度来实现。每次调整标签小部件的大小时都会触发此绑定。

The other option, as you suggest, is to use a text widget. It is possible to entirely turn off the border if you so desire. This has always been my choice when I want word-wrapped instructional text.

正如您所建议的,另一种选择是使用文本小部件。如果您愿意,可以完全关闭边界。当我想要自动换行的教学文本时,这一直是我的选择。

回答by RousseauAlexandre

Use Messagewidget:

使用Message小部件

The Message widget is a variant of the Label, designed to display multiline messages. The message widget can wrap text, and adjust its width to maintain a given aspect ratio.

消息小部件是标签的变体,旨在显示多行消息。消息小部件可以包装文本,并调整其宽度以保持给定的纵横比。

回答by t7ko

Here is the code:

这是代码:

entry = Label(self, text=text,
    anchor=NW, justify=LEFT,
    relief=RIDGE, bd=2)
def y(event, entry=entry):
  # FIXME: make this a global method, to prevent function object creation
  # for every label.
  pad = 0
  pad += int(str(entry['bd']))
  pad += int(str(entry['padx']))
  pad *= 2
  entry.configure(wraplength = event.width - pad)
entry.bind("<Configure>", y )

回答by Mitch McMabers

The tkinter.Messagewidget suggested by some people does NOT use TTK styling, which means that it's gonna look like garbage inside a TTK (themed) interface.

tkinter.Message有些人建议的小部件不使用 TTK 样式,这意味着它在 TTK(主题)界面中看起来像垃圾。

You could manually apply the background and foreground colors from your TTK theme to the tkinter.Message(by instantiating ttk.Style()and requesting the active themes' TLabelforeground and background colors from that style object), but it's not worth it... because the ancient Messagewidget has ZERO advantages over TTK's regular ttk.Label.

您可以手动将 TTK 主题的背景和前景色应用到tkinter.Message(通过实例化ttk.Style()和请求TLabel来自该样式对象的活动主题的前景色和背景色),但这不值得......因为古老的Message小部件具有零优势TTK 的常规ttk.Label.

The tkinter.Messagewidget has an "aspect ratio" property that defines how many pixels until it wraps.

tkinter.Message插件有一个“纵横比”属性,它定义多少像素直到它包装。

The ttk.Labelinstead has a wraplength=property which determines how many pixels until the words wrap. You should also use its anchor=and justify=properties to customize it to your exact desires. With these properties you can make your Label behave as the old Message widget did.

ttk.Label不是有wraplength=它决定多少像素,直到自动换行属性。您还应该使用它的anchor=justify=属性来根据您的确切需求对其进行自定义。使用这些属性,您可以使您的 Label 表现得像旧的 Message 小部件一样。

Example:ttk.Label(root, text="foo", wraplength=220, anchor=tkinter.NW, justify=tkinter.LEFT). Creates a beautifully styled label which permanently wraps its text after 220 pixels wide.

例子:ttk.Label(root, text="foo", wraplength=220, anchor=tkinter.NW, justify=tkinter.LEFT)。创建样式精美的标签,在 220 像素宽后永久包装其文本。

As for automatically updating the wraplength? Well, you should attach to the <Configure>event as people have said... However, if you have a completely fluid window (which resizes itself to fit all content), or a grid/frame that is fluid and contains the label, then you can't automatically calculate it that way, because the parent WINDOW/CONTAINER itself will EXPAND whenever the label grows too wide. Which means that the label will always resize itself to the maximum width it would need to fit all text. So, updating wraplength automatically is only possible if the label itself has some constraints on how wide it can grow (either via its parent container being a fixed size/maxsize, or itself being a fixed size/maxsize). In that case, sure, you can use configure to calculate new wrapping numbers to make sure the text always wraps... However, the example code by t7ko is broken and not valid anymore, just fyi.

至于自动更新包裹长度?那么,你应该附加到<Configure>正如人们所说的事件......但是,如果您有一个完全流动的窗口(它会调整自身大小以适应所有内容),或者一个流动且包含标签的网格/框架,那么您无法以这种方式自动计算它,因为每当标签变得太宽时,父 WINDOW/CONTAINER 本身就会 EXPAND。这意味着标签将始终将自身调整为适合所有文本所需的最大宽度。因此,只有当标签本身对其可以增长的宽度有一些限制时(通过其父容器是固定大小/最大大小,或者本身是固定大小/最大大小),才能自动更新 wraplength。在这种情况下,当然,您可以使用 configure 来计算新的换行数以确保文本始终换行......但是,t7ko 的示例代码已损坏且不再有效,仅供参考。