使用PyGObject创建自定义小部件

3 投票
1 回答
1364 浏览
提问于 2025-04-18 09:39

我正在尝试用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 个回答

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)    


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(..),希望这样能让你明白!

撰写回答