Shrink window in GTK+ dynamically when content shrinks?
Asked Answered
A

2

9

I have a window in a Vala application and an image inside it. This image is changed sometimes by img.set_from_pixbuf(imgdata); and so it's size changes as well. It's embedded in a Gtk.Box.

box = new Gtk.Box(Orientation.VERTICAL,5);
...
box.pack_end(img,false,false);

So if there was a big image before and I replace it with a smaller one, the window remains ridiculously big and I have not found a method to dynamically shrink it to the space required. I have tried with window.set_default_size(box.width_request,box.height_request) but it always returns -1.

So any ideas how to resize the window? Thanks!

Arsonist answered 17/1, 2012 at 23:27 Comment(1)
This is a real problem. I constantly run into this (e.g. an item removed from a Gtk::ListBox leaves the window to large).Epicardium
C
4

If I am not mistaken the automatic resizing of windows only only happens when elements are too large to be drawn. Additionally the set_default_size method only matters when first drawing the window and unless I am wrong is never used again. I would suggest using the resize method to set the window size. (link)

window.resize(box.width_request, box.height_request);

One thing you need to remember when using resize if you can't resize it smaller than the request_size if you run into that issue use the set_request_size method.

Consulate answered 13/3, 2012 at 20:20 Comment(3)
There are several typos here: the actual method names/signatures (which should be equivalent across bindings) are get_size_request(out width, out height) and set_size_request(width, height). Besides, get_size_request is only meaningful for dimensions whose request has previously been explicitly set; else they're -1. If no explicit request was made, but the user still wants an appropriate size for the widget, they should use get_preferred_height/_width/_size instead. This would then allow resizing the window smaller than the preferred dimensions (which is e.g. useful if it's scrollable)Fastidious
The link is broken.Perambulate
In addition, GTK4 removes Window.resize(), leaving only Window.set_default_size(), which it seems, as mentioned, sometimes only works before the window is shown and thereafter is ignored... weirdly it seems Wayland lets it work at any time while X.org does not, whereas usually the converse is true... Sigh, another feature just lost to time.Fastidious
E
5

I have fought with this issue myself and while the accepted answer is correct, I though I could give a more "complete" answer, with working code.

Reproducing the problem

The following code (In C++, sorry) reproduces your issue:

#include <array>

#include <gtkmm.h>

class ResizableWindow : public Gtk::Window
{

public:

    ResizableWindow()
    : m_toggle{"Toggle"}
    , m_currentImageIndex{0}
    {
        m_files[0] = "small.png";
        m_files[1] = "large.png";
    
        // Setup window layout:
        m_layout.attach(*Gtk::manage(new Gtk::Image(m_files[m_currentImageIndex])), 0, 0, 1, 1);
        m_layout.attach(m_toggle, 0, 1, 1, 1);
        add(m_layout);
        
        // Set up signal handlers:
        m_toggle.signal_clicked().connect([this](){OnToggle();});
    }

private:

    void OnToggle()
    {
        // Switch image file:
        if(m_currentImageIndex == 0)
        {
            m_currentImageIndex = 1;
        }
        else
        {
            m_currentImageIndex = 0;
        }
        
        // Load new image.
        Gtk::Widget* child = m_layout.get_child_at(0, 0);
        Gtk::Image* currentImage = dynamic_cast<Gtk::Image*>(child);
        
        currentImage->set(m_files[m_currentImageIndex]);
    }

    Gtk::Grid m_layout;
    
    Gtk::Button m_toggle;
    
    std::array<std::string, 2> m_files;
    size_t m_currentImageIndex;
};

int main (int argc, char* argv[])
{
    auto app = Gtk::Application::create(argc, argv, "so.question.q8903140");
    
    ResizableWindow w;
    w.show_all();

    return app->run(w);
}

The Toggle button changes the underlying images. Both are the same image, but with different sizes. Notice that, As you already mentionned, when toggling for the first time (small --> large), the window resizes appropriately. However, when toggling a second time (large --> small), the image is resized, but not the window, leaving extra space around the image:

enter image description here

Weird, I know...

Solution

To solve the issue, one needs to call the resize method. So the Toggle handler would become:

void OnToggle()
{
    if(m_currentImageIndex == 0)
    {
        m_currentImageIndex = 1;
    }
    else
    {
        m_currentImageIndex = 0;
    }
    
    Gtk::Widget* child = m_layout.get_child_at(0, 0);
    Gtk::Image* currentImage = dynamic_cast<Gtk::Image*>(child);
    
    currentImage->set(m_files[m_currentImageIndex]);
    
    // Resize window:
    resize(1, 1);
}

Note that resize was called with dimensions 1x1 (smallest possible dimensions). Gtkmm will resize the window following geometry constraints automatically from there.

Epicardium answered 19/10, 2020 at 16:27 Comment(0)
C
4

If I am not mistaken the automatic resizing of windows only only happens when elements are too large to be drawn. Additionally the set_default_size method only matters when first drawing the window and unless I am wrong is never used again. I would suggest using the resize method to set the window size. (link)

window.resize(box.width_request, box.height_request);

One thing you need to remember when using resize if you can't resize it smaller than the request_size if you run into that issue use the set_request_size method.

Consulate answered 13/3, 2012 at 20:20 Comment(3)
There are several typos here: the actual method names/signatures (which should be equivalent across bindings) are get_size_request(out width, out height) and set_size_request(width, height). Besides, get_size_request is only meaningful for dimensions whose request has previously been explicitly set; else they're -1. If no explicit request was made, but the user still wants an appropriate size for the widget, they should use get_preferred_height/_width/_size instead. This would then allow resizing the window smaller than the preferred dimensions (which is e.g. useful if it's scrollable)Fastidious
The link is broken.Perambulate
In addition, GTK4 removes Window.resize(), leaving only Window.set_default_size(), which it seems, as mentioned, sometimes only works before the window is shown and thereafter is ignored... weirdly it seems Wayland lets it work at any time while X.org does not, whereas usually the converse is true... Sigh, another feature just lost to time.Fastidious

© 2022 - 2024 — McMap. All rights reserved.