使用自动换行创建可调整大小/多行 Tkinter/ttk 标签
是否可以创建一个自动换行的多行标签,其大小与其父级的宽度同步?换句话说,当您更改记事本窗口的宽度时,记事本的自动换行行为。
该用例是一个对话框,需要完整地呈现多行文本块(指令),而无需剪切文本或诉诸滚动条。父容器将有足够的垂直空间来容纳较窄的宽度。
我一直在尝试 Tkinter Label 和 Message 小部件以及 ttk Label 小部件,但没有成功。看来我需要硬编码像素换行长度值,而不是让这些控件在文本到达容器的右边缘时自动换行。当然,Tkinter 几何管理器可以帮助我自动调整标签大小并相应地更新其包裹长度值?
我应该查看文本小部件吗?如果是这样,是否可以隐藏文本小部件的边框,以便我可以将其用作带有自动换行的多行标签?
这是一个如何执行我上面描述的操作的原型。它的灵感来自 Bryan Oakley 使用文本小部件的提示以及 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()
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()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
使用
消息
小部件:Use
Message
widget:不,Tk 没有内置自动换行标签的功能。但是,可以通过绑定到标签的
事件并调整环绕长度来实现。每次调整标签小部件的大小时都会触发此绑定。正如您所建议的,另一个选项是使用文本小部件。如果您愿意,可以完全关闭边界。当我想要自动换行的教学文本时,这一直是我的选择。
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.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.
这是代码:
Here is the code:
一些人建议的
tkinter.Message
小部件不使用TTK样式,这意味着它在TTK(主题)界面中看起来像垃圾。您可以手动应用从 TTK 主题到
tkinter.Message
的背景和前景色(通过实例化ttk.Style()
并请求活动主题的TLabel
前景和来自该样式对象的背景颜色),但这不值得......因为古老的Message
小部件比 TTK 的常规ttk.Label
具有零优势。tkinter.Message 小部件有一个“宽高比”属性,用于定义换行之前有多少像素。
而
ttk.Label
有一个wraplength=
属性,用于确定单词换行之前有多少像素。您还应该使用其anchor=
和justify=
属性来根据您的具体需求对其进行自定义。使用这些属性,您可以使标签的行为与旧的消息小部件一样。示例:
ttk.Label(root, text="foo",wrapplength=220,anchor=tkinter.NW, justify=tkinter.LEFT)
。创建一个样式精美的标签,在 220 像素宽后永久包裹其文本。至于自动更新包裹长度?好吧,您应该像人们所说的那样附加到
事件...但是,如果您有一个完全流畅的窗口(它会调整自身大小以适应所有内容),或者网格/框架它是流动的并且包含标签,那么您就无法以这种方式自动计算它,因为只要标签变得太宽,父窗口/容器本身就会扩展。这意味着标签将始终将自身大小调整为适合所有文本所需的最大宽度。因此,只有当标签本身对其增长宽度有一些限制时(通过其父容器是固定大小/最大大小,或者本身是固定大小/最大大小),才可以自动更新包裹长度。在这种情况下,当然,您可以使用configure来计算新的换行数,以确保文本始终换行...但是,t7ko的示例代码已损坏并且不再有效,仅供参考。The
tkinter.Message
widget suggested by some people does NOT use TTK styling, which means that it's gonna look like garbage inside a TTK (themed) interface.You could manually apply the background and foreground colors from your TTK theme to the
tkinter.Message
(by instantiatingttk.Style()
and requesting the active themes'TLabel
foreground and background colors from that style object), but it's not worth it... because the ancientMessage
widget has ZERO advantages over TTK's regularttk.Label
.The
tkinter.Message
widget has an "aspect ratio" property that defines how many pixels until it wraps.The
ttk.Label
instead has awraplength=
property which determines how many pixels until the words wrap. You should also use itsanchor=
andjustify=
properties to customize it to your exact desires. With these properties you can make your Label behave as the old Message widget did.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.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.