当用户调整窗口大小时,GtkIconView不会自动填充空间以适应图标。

在Ubuntu成就项目中,我们遇到了一些不寻常的错误。 我们有一个包含GtkNotebook和GtkIconView的窗口,一个在一个页面上,另一个在另一个页面上。
当用户调整窗口大小时,图标视图不会自动填充空间(它们保持原始列布局),但是如果用户更改GtkNotebook页面,从而刷新图标视图,则会按预期占用空间。如何在调整窗口大小时自动使用空间?
更令人担忧的是,当窗口出现时,我们可以将其调整为较小 - 看起来好像图标视图阻止我们调整大小,然后为图标创建可滚动区域。
代码看起来像这样。驱动图标视图的ListStores:
    self.trophystore = Gtk.ListStore(str, GdkPixbuf.Pixbuf, bool, bool, str, str) # title, icon accomplished, locked, app, accomplishment
    self.trophystore.set_sort_column_id(COL_TITLE, Gtk.SortType.ASCENDING)
    self.trophy_icon.set_model(self.trophystore)

    self.oppstore = Gtk.ListStore(str, GdkPixbuf.Pixbuf, bool, bool, str, str) # title, icon, accomplished, locked, app, accomplishment
    self.oppstore.set_sort_column_id(COL_TITLE, Gtk.SortType.ASCENDING)
    self.opp_icon.set_model(self.oppstore)

    self.trophy_icon.set_text_column(COL_TITLE)
    self.trophy_icon.set_pixbuf_column(COL_PIXBUF)

    self.opp_icon.set_text_column(COL_TITLE)
    self.opp_icon.set_pixbuf_column(COL_PIXBUF)

除此之外,我们并不真的对IconViews进行深入研究,我们只是向ListStores添加内容以更新视图。
项目的代码在这里 - 有人能推荐一下我们如何解决这两个问题吗?

只是一个解释:当用户更改笔记本页面时,应用程序代码会清除底层模型并重新添加所有项目,这似乎是导致GtkIconView刷新并使用空白空间的原因。 - Rafał Cieślak
3个回答

好的,既然我们已经找到了解决方法,我会在这里描述解决方案,以防其他人也遇到这个问题。

诀窍是将 GtkIconView 放置在 GtkScrolledWindow 中,并将其 hscrollbar_policy 设置为 "always"。然后,必须使用 check-resize 信号来在用户调整窗口大小时做出反应(注意必须检查大小是否发生了变化,因为信号也会在拖动窗口等情况下发出)。

当大小发生变化时,GtkIconView 使用的模型必须被清除并重新创建,这样可以触发 GtkIconView 正确地重新分配新获得的空间(或缩小)。此外,由于 GtkIconView 使用与 GtkScrolledWindow 相同的空间,水平滚动条永远不会被看到。


这真是非常有帮助,感谢你的答案!我在 lp:qreator 受到了影响,而你的修复使得主要图标视图中的图标列数能够在调整大小时动态变化。 - David Planella

当尺寸发生变化时,您还可以将列设置为0,然后再设置为-1。这样图标就不会被取消选择了。
iconview.set_columns(0)
iconview.set_columns(-1)

(这应该是在@rafalcieslak's answer的基础上进行的。)

为什么除了rafalcieslak的回答之外还需要这个?如果您更改列数,将会重新布局;无论如何重新建模都是没有意义的。 - cscarney

我对这个问题的首选解决方案是一个非常小的Gtk.IconView子类。
class FluidIconView (Gtk.IconView):
    def __init__ (self):
        Gtk.IconView.__init__ (self)
        self.connect ("size-allocate", FluidIconView.on_size_allocate)

    def do_get_preferred_width (self):
        return (0,0)

    def on_size_allocate (self, allocation):
        [self.set_columns (m) for m in [1,self.get_columns ()]]

get_preferred_width的重写允许视图任意变窄。size-allocate回调通过将列数设置为1然后恢复,强制重新布局。