Python GTK: How to customize the size of a button in a notebook tab label

Articles may may have files attached at the end of the post

In the previous post, I showed how to customize your gtk.Notebook Tab Label by adding a close button to the tab.
Depending on the theme used by the user, the tab might get pretty big once a gtk.Button is added.

In this tutorial I will explain how to override the theme behaviour by creating a custom style for our widget.

Customized GTK Notebook Close ButtonCustomized GTK Notebook Close ButtonTo force the button to be of a certain size and to keep the button gtk.Image properly displayed, we need to edit the theme default style rc value.
In order to make the changes only applicable to our close button, we are going to create a custom style that we will inject in gtk using gtk.rc_parse_string.

the code sample below will create 5 tabs, the 1st and 4th one will have their name set to "tab-close-button", which will match our custom button style. When the style will be set, those tabs will be displayed properly with a margin of 1px around the image. While the other tabs will see their image squeezed as the size of the button and its paddings will prevent the image to get its proper size.

As you can see, the button is connected to the "style-set" signal. When this signal is caught, if we are in "apply-style" mode, the button will be forced to use size the size of the image + 2. If the theme style padding is too big, the image will be squeezed.
Only tabs with name "tab-close-button" will be displayed properly.

The script attached to this post can be run in 2 modes: without forcing the style and with style modification. the first one is ran:

$ ./gtk-notebook-with-custom-tab-button-size.py

While the second mode is ran with:

$ ./gtk-notebook-with-custom-tab-button-size.py apply-style

difference between tab sizedifference between tab sizeThe difference in the tab size with a default ubuntu theme is shown is the picture.

as you can see there is a slight difference in the tabs size between the 2 widgets. Depending on the theme used by the user, this can be a significant space saving.

Here is the code that will generate the widget shown in the image:

  1. #!/usr/bin/env python
  2. import gobject, gtk
  3. import sys
  4.  
  5. applystyle = False
  6. class NotebookTabLabel(gtk.HBox):
  7.  
  8.   def __init__(self, title, buttonname):
  9.     gtk.HBox.__init__(self, False, 4)
  10.     self._label = gtk.Label()
  11.     self.pack_start(self._label, True, True, 0)
  12.    
  13.     self._button = gtk.Button()
  14.     self._button.set_relief(gtk.RELIEF_NONE)
  15.     self._button.set_focus_on_click(False)
  16.    
  17.     if buttonname != "":
  18.       self._button.set_name(buttonname)
  19.     self._button.set_tooltip_text("Close Tab")
  20.          
  21.     icon = gtk.image_new_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
  22.     self._button.add(icon)
  23.     self.pack_start(self._button, False, False, 0)
  24.    
  25.     self.connect("style-set", self.on_style_set)
  26.    
  27.     self.show_all()
  28.  
  29.   def on_style_set(self, widget, prevstyle):
  30.     if applystyle:
  31.       x, y = gtk.icon_size_lookup_for_settings( self._button.get_settings(), gtk.ICON_SIZE_MENU)
  32.       self._button.set_size_request(x + 2,y + 2)
  33.    
  34.  
  35. if __name__ == "__main__":
  36.   win = gtk.Window()
  37.   win.set_default_size(500,300)
  38.   win.connect("delete-event", lambda widget, evt: gtk.main_quit())
  39.   win.connect("destroy", lambda widget: gtk.main_quit())
  40.   if len(sys.argv) > 1 and sys.argv[1] == "apply-style":
  41.     applystyle = True
  42.     gtk.rc_parse_string("""
  43.        style "tab-close-button-style" {
  44.              GtkWidget::focus-padding = 0
  45.              GtkWidget::focus-line-width = 0
  46.              xthickness = 0
  47.              ythickness = 0
  48.          }
  49.          widget "*.tab-close-button" style "tab-close-button-style"
  50.          """)
  51.   nt = gtk.Notebook()
  52.   buttonnames = ['tab-close-button', 'foobar', '']
  53.   for i in range(0,5):
  54.     buttonname = buttonnames[i%len(buttonnames)]
  55.     label = NotebookTabLabel("hello", buttonname)
  56.     page = gtk.Label("HELLO")
  57.     nt.append_page(page)
  58.     nt.set_tab_label(page, label)
  59.     nt.set_tab_label_packing(page, True, True,gtk.PACK_START)
  60.   win.add(nt)
  61.  
  62.   win.show_all()
  63.   gtk.main()

I did not cover the handling of the tab closure, you might want to check Python GTK: How to set up gtk.Notebook tab with custom widget for more details.

AttachmentSize
gtk-notebook-with-custom-tab-button-size.py.txt1.91 KB