当父级更改时,GTK中的标签不会动态调整大小known bug/issue。这是其中一个非常讨厌的小细节,如果可能的话,我想破解它。
我在16 software处遵循了该方法,但根据免责声明,您无法将其调整为较小。所以我尝试了其中一条评论中提到的一个技巧(信号回调中的set_size_request
调用),但这会产生某种无限循环(试试看看)。
有没有人有其他想法?
(你不能在调用期间阻止信号,因为print
语句似乎表明,问题在函数离开后开始。)
代码如下。你可以看到我的意思,如果你运行它并尝试调整窗口大小然后更小。 (如果您想查看原始问题,请在“连接到大小分配信号”之后注释掉该行,运行它,然后将窗口调整得更大。)
Glade文件(“example.glade”):
<?xml version="1.0"?>
<glade-interface>
<!-- interface-requires gtk+ 2.16 -->
<!-- interface-naming-policy project-wide -->
<widget class="GtkWindow" id="window1">
<property name="visible">True</property>
<signal name="destroy" handler="on_destroy"/>
<child>
<widget class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="label" translatable="yes">In publishing and graphic design, lorem ipsum[p][1][2] is the name given to commonly used placeholder text (filler text) to demonstrate the graphic elements of a document or visual presentation, such as font, typography, and layout. The lorem ipsum text, which is typically a nonsensical list of semi-Latin words, is a hacked version of a Latin text by Cicero, with words/letters omitted and others inserted, but not proper Latin[1][2] (see below: History and discovery). The closest English translation would be "pain itself" (dolorem = pain, grief, misery, suffering; ipsum = itself).</property>
<property name="wrap">True</property>
</widget>
</child>
</widget>
</glade-interface>
Python代码:
#!/usr/bin/python
import pygtk
import gobject
import gtk.glade
def wrapped_label_hack(gtklabel, allocation):
print "In wrapped_label_hack"
gtklabel.set_size_request(allocation.width, -1)
# If you uncomment this, we get INFINITE LOOPING!
# gtklabel.set_size_request(-1, -1)
print "Leaving wrapped_label_hack"
class ExampleGTK:
def __init__(self, filename):
self.tree = gtk.glade.XML(filename, "window1", "Example")
self.id = "window1"
self.tree.signal_autoconnect(self)
# Connect to the size-allocate signal
self.get_widget("label1").connect("size-allocate", wrapped_label_hack)
def on_destroy(self, widget):
self.close()
def get_widget(self, id):
return self.tree.get_widget(id)
def close(self):
window = self.get_widget(self.id)
if window is not None:
window.destroy()
gtk.main_quit()
if __name__ == "__main__":
window = ExampleGTK("example.glade")
gtk.main()
答案 0 :(得分:4)
以下是killown解决方案的单行变体:
label.connect('size-allocate', lambda label, size: label.set_size_request(size.width - 1, -1))
以上将确保标签占用分配给它的宽度,以便自动换行。
不确定为什么宽度为“-1”,但它似乎无害!
答案 1 :(得分:3)
VMware的libview有一个名为WrapLabel的小部件应该可以做你想要的,但它是用C ++编写的。 Meld repository中提供了Python翻译(与busybox.py分开)。
答案 2 :(得分:3)
调整大小并动态包装标签的示例:
编辑:
import gtk
class DynamicLabel(gtk.Window):
def __init__(self):
gtk.Window.__init__(self)
self.set_title("Dynamic Label")
self.set_size_request(1, 1)
self.set_default_size(300,300)
self.set_position(gtk.WIN_POS_CENTER)
l = gtk.Label("Dynamic Label" * 10)
l.set_line_wrap(True)
l.connect("size-allocate", self.size_request)
vbox = gtk.VBox(False, 2)
vbox.pack_start(l, False, False, 0)
self.add(vbox)
self.connect("destroy", gtk.main_quit)
self.show_all()
def size_request(self, l, s ):
l.set_size_request(s.width -1, -1)
DynamicLabel()
gtk.main()
答案 3 :(得分:2)
你可以用它。不知道它最初来自哪里。创建标签,然后调用label_set_autowrap(label)
def label_set_autowrap(widget):
"Make labels automatically re-wrap if their containers are resized. Accepts label or container widgets."
# For this to work the label in the glade file must be set to wrap on words.
if isinstance(widget, gtk.Container):
children = widget.get_children()
for i in xrange(len(children)):
label_set_autowrap(children[i])
elif isinstance(widget, gtk.Label) and widget.get_line_wrap():
widget.connect_after("size-allocate", _label_size_allocate)
def _label_size_allocate(widget, allocation):
"Callback which re-allocates the size of a label."
layout = widget.get_layout()
lw_old, lh_old = layout.get_size()
# fixed width labels
if lw_old / pango.SCALE == allocation.width:
return
# set wrap width to the pango.Layout of the labels
layout.set_width(allocation.width * pango.SCALE)
lw, lh = layout.get_size() # lw is unused.
if lh_old != lh:
widget.set_size_request(-1, lh / pango.SCALE)
答案 4 :(得分:1)
在GTK 3中,这是使用height-for-width和width-to-height size请求自动完成的。
答案 5 :(得分:1)
我只是想分享一下我使用wraplabel.py如何使Kai的解决方案与PyGtk和Glade-3一起使用。
我不想修改Glade目录以获得Glade中的WrapLabel,我不确定这是否适用于PyGtk组件。然而,令我惊喜地发现,只需在调用 gtk.Bilder()之前将 WrapLabel 类放在python环境中,它就会将该类作为组件加载。< / p>
所以现在唯一的问题是将 WrapLabels 放入林间空地文件中。首先,我将要包装的所有标签的名称更改为 wlabel ### ,其中 ### 是一些数字。然后我使用sed表达式替换类,但由于我不想在构建系统中添加额外的处理,我最终在python中添加了以下内容:
import re
import gtk
from wraplabel import WrapLabel
. . .
# Filter glade
glade = open(filename, 'r').read()
glade = re.subn('class="GtkLabel" id="wlabel',
'class="WrapLabel" id="wlabel', glade)[0]
# Build GUI
builder = gtk.Builder()
builder.add_from_string(glade)
我确信有更优雅的方式来进行替换,但效果很好。但是,我发现我还有一个问题。当我用包装标签打开其中一个对话框时,一些文本不可见。然后,当我用鼠标调整窗口大小时,即使是一点点,一切都会卡入到位。一些标签在初始化时没有得到正确的尺寸。我用另一种解决方法解决了这个问题打开其中一个对话框时,我运行以下代码:
def open_dialog(self, dialog):
# Hack to make WrapLabel work
dims = dialog.get_size()
dialog.resize(dims[0] + 1, dims[1] + 1)
dialog.present()
dialog.resize(*dims)
这只是将大小设置为一个点太大,呈现窗口然后重置为正确的大小。这样, WrapLabels 会在对话框布局完成后获取调整大小的信号。
还有一个小故障。有时您打开对话框时可以看到文本卡入到位。否则,似乎有效。
注1)在 size-allocate 上调用 label.set_size_request(size.width - 1,-1)的所有变体都会导致GUI锁定。可能取决于父窗口小部件。
注2)另一种解决方案是使用TextView并禁用编辑,光标和灵敏度。但是,TextViews具有与背景不同的颜色,这在Gtk主题面前难以修复。此解决方案的另一个问题是TextViews捕获鼠标滚动事件。这使得鼠标在其中滚动一个带有这些TextView的框非常不稳定。我尝试了很多东西来解决鼠标滚动问题,但从未弄明白。否则使用TextViews确实有效。因此,如果文本标签不在滚动窗格内并且WrapLabel解决方案不适合您,则可以考虑这一点。
答案 6 :(得分:0)
我修改了其他答案中的代码,以获得一个表现更好的回调:
def on_label_size_allocate(self, label, allocation, *args):
""" Callback that re-allocates the size of a label to improve word wrap. """
layout = label.get_layout()
layout.set_width((allocation.width-20) * pango.SCALE)
_, lh = layout.get_pixel_size()
label.set_size_request(-1, lh+6)
通过反复试验获得-20和+6数字。从窗口小部件的某个地方获取它们会很好,但我找不到与窗口小部件有任何关系。这使得标签在生长和收缩时都可以很好地调整大小,并且不会切割线条。