5

I've got a Python app that uses a Gtk.Notebook widget to display different pages. Each of these pages contain a different set of widgets, and I've noticed that the 'tallest' widget in terms of vertical space defines the overall vertical size of the notebook.

But I'd actually like my app to resize the pages to not waste vertical space, and adapt, that is, get resized to the same vertical size as the widget they contain. This resize should happen when I select each page.

Test app showing undesired vertical space

Here's the sample code to generate this notebook (the example contains a widget per page for the sake of simplicity)

So in short, how can I dynamically resize notebook pages upon selecting them, so that their vertical space is adapted to be the same as their child widget?

2 Answers 2

3

I do not know a nice answer, but I have a work-around for you:

The basic idea is that you need a container widget as the parent widget in each page (do not place e.g. a label directly in the page), and you can hide/show everything except the container (If you hide the container as well, the page will disappear).

This solution should work for otherwise arbitrary widget hierarchies.

from gi.repository import Gtk

class NotebookWindow():
    def __init__(self):
        self.builder = Gtk.Builder()
        self.builder.add_from_file('notebook.ui')
        self.builder.get_object('window1').connect('delete-event',
            Gtk.main_quit)
        notebook = self.builder.get_object('notebook1')
        notebook.connect("switch-page", self.on_notebook1_switch_page)
        self.on_notebook1_switch_page(notebook, None,
                                      notebook.get_current_page())

    def on_notebook1_switch_page(self, widget, label, page):
        for p in range(widget.get_n_pages()):
            container = widget.get_nth_page(p)
            if not p == page:
                for c in container.get_children():
                    try:
                        c.hide_all()
                    except AttributeError:
                        c.hide()
            else:
                for c in container.get_children():
                    try:
                        c.show_all()
                    except AttributeError:
                        c.show()


if __name__ == '__main__':
    notebookwindow = NotebookWindow()
    Gtk.main()

In my original answer I recorded and re-instated the requested sizes. This does not work in general, because the requested size is only a minimal size. I would have to record a maximum size, in order for this to work, though.

8
  • That's exactly what I needed, thanks! I tested it to work on rev 2 of the example. However, when testing it with the real code it did not seem to work. I've tracked it down to be because there the widgets in the real app are not put directly inside the notebook page, but rather they are contained within a grid in each page. Rev 3 of the example illustrates this situation. May 31, 2012 at 10:37
  • I'll accept the answer, as it's a valid workaround for the question. I'm still stuck with my code with the grid, though. I'm unsure about opening a new question since it will be too localized, but in any case, any ideas why the latest example code with the grid is not doing the resize? Thanks! May 31, 2012 at 10:38
  • Hi, I'll think about it... But its always ok, when you wait a while before you accept an answer, maybe someone else knows something better. I think it would make more sense to un-accept my answer than to write a new one with a minor change.
    – xubuntix
    May 31, 2012 at 11:05
  • @DavidPlanella ok, added a fix for your more general problem. My guess is that you will soon wish there would be a toolkit with a more pythonic syntax. If thats the case, have a look at [kivy](kivy.org) :-)
    – xubuntix
    May 31, 2012 at 11:26
  • Excellent, thanks! Ok, I'll unaccept the answer for now as suggested, and if no other one comes up, I'll accept it again after testing your fix :) May 31, 2012 at 11:28
1

IF the actual notebook widget is not needed, but is merely a way to keep similar content together and provide a way to switch between them, then there might be better/simpler solutions. Here is one that was in the end used for Qreator:

the main idea is to use a container like a Gtk.Box (called page_box in the example below) and keep only one item visible. You also need a list with the content of each page, each packed into a single widget (e.g. a Gtk.Grid).

for page in page_list:
    self.ui.page_box.add(page.grid)

Here page_list is a simple list of page objects, where the page object has a grid property (the Gtk.Grid containing all the page content).

At last, you need to provide a way to switch between the contents, e.g. with a set of buttons, each calling a switch method with the corresponding page_id when clicked:

def switch_view(self, page_id):
    # hide all pages
    for child in self.ui.page_box.get_children():
        child.hide()
    # show the single page that is active
    self.ui.page_box.get_children()[page_id].show()

This is not a literal answer to the question, but it might solve the same problem.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .