`Picture` inside `ListView` item has zero height until manually resized—how to automatically size to content?

Hi folks,

I’m working on a GTK4 app in Rust and I’m hitting a layout issue with Pictureinside a ListView item. The goal is to display dynamically generated preview images in a scrolling list and have each image:

  • Scale down to fit the width of the viewport (if needed)
  • Maintain its aspect ratio
  • Automatically size its container to fit its expected height

But what I’m seeing is:

  • Each picture has zero height unless I explicitly set it manually in code. Without calling set_size_request on the Box containing the Picture, the image doesn’t visibly render at all.

Here’s the relevant code from my SignalListItemFactory setup:

factory.connect_setup(|_, list_item| {
    let picture = gtk::Picture::new();
    picture.set_content_fit(gtk::ContentFit::Contain);
    picture.set_halign(gtk::Align::Center);
    picture.set_valign(gtk::Align::Start);
    picture.set_hexpand(true);
    picture.set_vexpand(true);

    let container = gtk::Box::new(gtk::Orientation::Vertical, 0);
    container.set_halign(gtk::Align::Center);
    container.set_valign(gtk::Align::Start);
    container.set_hexpand(true);
    container.set_vexpand(true);
    container.append(&picture);

    list_item.set_child(Some(&container));
});

And then during bind:

if let Some(texture) = page.texture() {
    picture.set_paintable(Some(&texture));

    // Without this, picture has zero height
    let height = texture.height();
    container.set_size_request(-1, height as i32);
}

I’d like the list item to automatically size itself vertically to match the loaded picture with no hardcoded height (as this doesn’t scale down in narrow viewports). I expected Picture or the container Box to request the correct size based on the image, but that doesn’t happen.

Questions:

  1. Is this the expected behavior for Picture inside a list item?
  2. What’s the correct way to size list items dynamically based on picture height?
  3. Should I be using a Frame, AspectFrame, or something else to let GTK size to the texture?

Any help is much appreciated!

Thanks!

Did you read the documentation? Specifically Gtk.Picture.
picture.set_can_shrink(false); should do the trick.

Thanks. Yes, setting picture.set_can_shrink(false); does force the picture to render at its actual size, which is perhaps an improvement, but that trades one problem for another: I want the images to scale down as necessary to fit the available width if they’re larger than it (the images are previews of full document pages, and if the window is made narrow by the user, I’d like them to scale down to fit the width). Is there any way way to force images to take the maximum available space?

OK, I misunderstood, how about
picture.set_content_fit(gtk::ContentFit::ScaleDown)?

Unfortunately, picture.set_content_fit(gtk::ContentFit::ScaleDown) doesn’t work at the same time as picture.set_can_shrink(false);, and without the latter, the picture ends up having zero height. I can manually set a height doing:

let height = texture.height();
picture.set_size_request(-1, height as i32);

But then this ends up having too much height when the image scales to fit the window width, and the picture gets letterboxed. Short of manually recalculating the height on resize (which I’ve found to be error-prone), I’m not sure what to do.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.