Python GTK: How to set up gtk.Notebook tab with custom widget -- page 2

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

Now, let's go over the code and see what happens.

From line 1 to 10, we import the required module to run the script and we define to global variables: window, the main window, and notebook, our customized gtk notebook.

Line 10, we define our class MyNotebook which inherit from gtk.Notebook.

Line 12 to 18, we initialized our Notebook. By setting the property "shows-tabs" to False, we make sure that a tab is not going to be visible to the user. We will set it to True later when the number of tabs will be greater than 1.

  1.   def __init__(self):
  2.     gtk.Notebook.__init__(self)
  3.     #set the tab properties
  4.     self.set_property('homogeneous', True)
  5.     #we do not show the tab if there is only one tab i total
  6.     self.set_property('show-tabs', False)

Line 19 to 41, this is the method that is going to be called when a new tab is created.
Up to line 25, we generate and append an image to the notebook.
Line 29-30, we make the tabs visible if there is more than 1.
35-41, we create our customized tab label widget, set it as a tab label and finally, give focus to the new tab.

  1.   def new_tab(self):
  2.     #we create a "Random" image to put in the tab
  3.     icons = [gtk.STOCK_ABOUT, gtk.STOCK_ADD, gtk.STOCK_APPLY, gtk.STOCK_BOLD]
  4.     image = gtk.Image()
  5.     nbpages = self.get_n_pages()
  6.     icon = icons[nbpages%len(icons)]
  7.     image.set_from_stock(icon, gtk.ICON_SIZE_DIALOG)
  8.     self.append_page(image)
  10.     #we want to show the tabs if there is more than 1
  11.     if nbpages + 1 > 1:
  12.       self.set_property('show-tabs', True)
  13.     #creation of a custom tab. the left image and
  14.     #the title are made of the stock icon name
  15.     #we pass the child of the tab so we can find the
  16.     #tab back upon closure
  17.     label = self.create_tab_label(icon, image)
  18.     label.show_all()
  20.     self.set_tab_label_packing(image, True, True, gtk.PACK_START)
  21.     self.set_tab_label(image, label)
  22.     image.show_all()
  23.     self.set_current_page(nbpages)

Line 43 to 59 is the method creating the tab label and connecting the close button to our close_tab.

Our tab is basically a gtk.HBox in which we pack:

  • An image on the left side which will match the content of the tab
  • The title of the tab
  • A close button on the right side
    • The close button is hooked to the signal clicked and pass the child of the tab as a user parameter so we can find the tab back and close it.

      1.   def create_tab_label(self, title, tab_child):
      2.     box = gtk.HBox()
      3.     icon = gtk.Image()
      4.     icon.set_from_stock(title, gtk.ICON_SIZE_MENU)
      5.     label = gtk.Label(title)
      6.     closebtn = gtk.Button()
      7.     #the close button is made of an empty button
      8.     #where we set an image
      9.     image = gtk.Image()
      10.     image.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
      11.     closebtn.connect("clicked", self.close_tab, tab_child)
      12.     closebtn.set_image(image)
      13.     closebtn.set_relief(gtk.RELIEF_NONE)
      14.     box.pack_start(icon, False, False)
      15.     box.pack_start(label, True, True)
      16.     box.pack_end(closebtn, False, False)
      17.     return box

      The last method (line 61-68) of our class MyNotebook is the callback invoked when a "clicked" signal is intercepted.

      By using the child of the tab, we can find the page number. Then, we remove the page and, if there is only one tab left, we hide the tab label to the user.

      1.   def close_tab(self, widget, child):
      2.     pagenum = self.page_num(child)
      4.     if pagenum != -1:
      5.       self.remove_page(pagenum)
      6.       child.destroy()
      7.       if self.get_n_pages() == 1:
      8.         self.set_property('show-tabs', False)

      the rest of the code, simply handle the closure of the top level window along with the initialization of the widget.

      hope this helped