6

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?

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?

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?

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()
4

4 回答 4

3

使用Message小部件

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

于 2016-05-11T11:07:40.910 回答
2

这是代码:

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 )
于 2012-04-03T20:38:05.463 回答
2

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

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

于 2010-10-25T10:35:25.157 回答
2

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

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

tkinter.Message部件有一个“纵横比”属性,它定义了多少像素,直到它换行。

ttk.Label相反,它有一个属性wraplength=,它决定了单词换行之前有多少像素。您还应该使用它的anchor=justify=属性来自定义它以满足您的确切需求。使用这些属性,您可以使您的 Label 表现得像旧的 Message 小部件一样。

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

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

于 2019-10-14T18:32:25.033 回答