Создать собственный виджет с PyGObject

Я пытаюсь создать собственный виджет с PyGObject. Например я хочу создать это CustomButton виджет, который добавляет изображение и метку в кнопку (это только для примера):

#!/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)

В другом файле или классе я могу использовать его так:

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

Но когда я хочу использовать это, я обязан позвонить button атрибут, как это:

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

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

Это работает, но это не практично. Как создать собственный виджет, работающий как любой другой виджет, пожалуйста:

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

1 ответ

Я думаю, что ваша проблема - это проблема понимания классов, а не наследования. Если вы хотите, чтобы ваш виджет действовал как кнопка, это должна быть кнопка.

Посмотрите на следующий пример:

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()

Вместо того, чтобы говорить, что мой класс это Gtk.WidgetЯ сказал, что это Gtk.EventBox и я начал это так. Впредь ImageButton будет иметь такие же атрибуты и методы, как Gtk.EventBox,

* Если я сделал тот же пример, используя Gtk.Button вместо Gtk.EventBox ты можешь позвонить button.connect(.. вместо buton.connect.connect(.. как ты хочешь в своем вопросе. Проблема в том, что если ImageButton это Gtk.Button Больше невозможно изменить его так, чтобы он делал то, чего не делают кнопки (например, добавляя контейнеры и метки).

В нескольких словах:

Вы можете создать собственный виджет, основанный на другом виджете, но только один виджет будет в верхней части дерева.

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

Итак, когда вы делаете self.method это всегда будет выглядеть так:

1) Ваши родительские методы (тот, который вы скопировали с помощью Gtk.EventBox.__init__(self)

2) Методы, которые вы создали.

В качестве альтернативы вы можете лгать благодаря этому:

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()

Обратите внимание, что мне не пришлось звонить button.label.set_text(..) Я надеюсь, что это будет достаточно ясно!

Другие вопросы по тегам