ncrocfer
ncrocfer

Reputation: 2570

Create a custom widget with PyGObject

I am trying to create a custom widget with PyGObject. For example I want to create this CustomButton widget which adds an image and a label in a button (it's just for the example) :

#!/usr/bin/python
#-*- coding: utf-8 -*

from gi.repository import Gtk

class ImageButton(Gtk.Widget):

    def __init__(self, label, image):
        Gtk.Widget.__init__(self)

        self.hbox = Gtk.HBox()
        self.label = Gtk.Label(label)
        self.image = Gtk.Image.new_from_stock(image, Gtk.IconSize.MENU)

        self.hbox.pack_start(self.image, False, False, 3)
        self.hbox.pack_start(self.label, False, False, 3)

        self.button = Gtk.Button()
        self.button.add(self.hbox)

In another file or class, I can use it like that :

button = ImageButton("My label", Gtk.STOCK_HOME)

But when I want to use it, I am obliged to call the button attribute, like this :

# Connect the "clicked" event 
button.button.connect("clicked", on_clicked_button)

# Add the button in a container
window.add(button.button)

It works but it is not practical. How to create a custom widget working like any other widget please :

button = ImageButton("My label", Gtk.STOCK_HOME)
button.connect("clicked", on_clicked_button)
window.add(button)

Upvotes: 3

Views: 1445

Answers (1)

user3672754
user3672754

Reputation:

I think that your problem it is actually a problem about understanding classes more then inheritance. If you want your widget to act exactly as a button, it should be a button.

Take a look to the following example:

from gi.repository import Gtk

class ImageButton(Gtk.EventBox):

    def __init__(self, label):

        Gtk.EventBox.__init__(self)
        self.label = Gtk.Label(label)
        self.add(self.label)    


if __name__ == '__main__':
    def on_imagebutton_clicked(button, data=None):
        print("Button has been clicked!")

    window = Gtk.Window()
    button = ImageButton("My label")
    button.connect('button-press-event', on_imagebutton_clicked)
    window.add(button)
    window.show_all()
    Gtk.main()

Instead of saying that my class it is a Gtk.Widget, I said that it is a Gtk.EventBox and I started it like it. From now on ImageButton will have the same attributes and methods like an Gtk.EventBox.

*If I've made the same example by using Gtk.Button instead of a Gtk.EventBox you could call button.connect(.. instead of buton.connect.connect(.. as you want it in your question. The problem with this is that if ImageButton it is a Gtk.Button It is not any more possible of modifying it to do things that buttons don't do ( like adding containers and labels).

In a Few Words:

You can create a custom widget based in other widget, but only one widget will be at the top of the tree.

--> Parent  
---------> Child
---------> Child

So when you do self.method it will always look to:

1) Your parent methods (the one you copied by using Gtk.EventBox.__init__(self)

2) The methods you created.

Alternatively you can lie thanks to this:

from gi.repository import Gtk

class ImageButton(Gtk.EventBox):

    def __init__(self, label):

        Gtk.EventBox.__init__(self)
        self.label = Gtk.Label(label)
        self.add(self.label)    

    def set_text(self, text):
        self.label.set_text(text)

if __name__ == '__main__':
    def on_imagebutton_clicked(button, data=None):
        print("Button has been clicked!")

    window = Gtk.Window()
    button = ImageButton("My label")
    button.connect('button-press-event', on_imagebutton_clicked)
    button.set_text('New text!!')
    window.add(button)
    window.show_all()
    Gtk.main()

Note that I didn't had to call button.label.set_text(..) I hope it be clear enough!

Upvotes: 2

Related Questions