使用 PyGObject 自定义 Gtk.Container

4

我正在尝试使用PyGObject实现自定义的Gtk.Container。但是我遇到了一些问题,甚至不知道这是否是错误,还是我的实现有误。以下是我的测试代码片段:

from gi.repository import Gtk, Gdk
import sys

class TestContainer(Gtk.Container):
    __gtype_name__ = "TestContainer"

    def __init__(self, *args, **kwargs):
        self.children = []
        super().__init__()

    def do_add(self, widget):
        self.children.append(widget)
        widget.set_parent(self)

    def do_remove(self, widget):
        self.children.remove(widget)
        widget.unparent()
                    
    def do_child_type(self):
        print("do_child_type()")
        return(Gtk.Widget.get_type())

    def do_forall(self, include_internals, callback, *callback_parameters):
        print("do_forall() self = %x" % id(self))
        if not callback is None:
            for widget in self.children:
                callback(widget, *callback_parameters)

    def do_get_request_mode(self):
        print("do_get_request_mode()")
        return(Gtk.SizeRequestMode.CONSTANT_SIZE)

    def do_get_preferred_height(self):
        print("do_get_preferred_height()")
        result = (50, 50)
        return(result)

    def do_get_preferred_width(self):
        print("do_get_preferred_width()")
        min_width = 0
        nat_width = 0

        for widget in self.children:
            child_min_width, child_nat_width = widget.get_preferred_width()
            min_width = min_width + child_min_width
            nat_width = nat_width + child_nat_width

        return(min_width, nat_width)

    def do_size_allocate(self, allocation):
        print("do_size_allocate()")
        child_allocation = Gdk.Rectangle()

        self.set_allocation(allocation)

        if self.get_has_window():
            if self.get_realized():
                self.get_window().move_resize(allocation.x, allocation.y, allocation.width, allocation.height)

        for widget in self.children:
            if widget.get_visible():
                min_size, nat_size = widget.get_preferred_size()

                child_allocation.x = 0
                child_allocation.y = 0

                if not widget.get_has_window():
                    child_allocation.x = child_allocation.x + allocation.x
                    child_allocation.y = child_allocation.x + allocation.x

                child_allocation.width = min_size.width
                child_allocation.height = min_size.height

                widget.size_allocate(child_allocation)

    def do_realize(self):
        print("do_realize()")
        allocation = self.get_allocation()
        
        attr = Gdk.WindowAttr()
        attr.window_type = Gdk.WindowType.CHILD
        attr.x = allocation.x
        attr.y = allocation.y
        attr.width = allocation.width
        attr.height = allocation.height
        attr.visual = self.get_visual()
        attr.event_mask = self.get_events() | Gdk.EventMask.EXPOSURE_MASK
        
        WAT = Gdk.WindowAttributesType
        mask = WAT.X | WAT.Y | WAT.VISUAL
        
        window = Gdk.Window(self.get_parent_window(), attr, mask);
        window.set_decorations(0)
        self.set_window(window)
        self.register_window(window)
        self.set_realized(True)

    def do_draw(self, cr):
        allocation = self.get_allocation()
        Gtk.render_background(self.get_style_context(), cr, 0, 0, allocation.width, allocation.height)

        for widget in self.children:
            self.propagate_draw(widget, cr)

class TestWindow(Gtk.Window):
    __gtype_name__ = "TestWindow"
    def __init__(self):
        Gtk.Window.__init__(self, title="GTK3 PyGObject Custom Container Test")

        label = Gtk.Label(label = "Text")

        self.area = TestContainer()
        self.area.add(label)
        self.add(self.area)
        self.show_all()

    def _on_quit(self, widget, event):
        Gtk.main_quit()


MainWindow = TestWindow()
MainWindow.connect("delete-event", MainWindow._on_quit)
MainWindow.show_all()
Gtk.main()

所有工作都很顺利,直到你关闭窗口。关闭窗口后,我遇到了这个问题:

Traceback (most recent call last):
  File "/home/cheatfate/Projects/test_container.py", line 36, in do_forall
    if not callback is None:
AttributeError: 'TestContainer' object has no attribute 'children'
Error in sys.excepthook:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/apport_python_hook.py", line 58, in apport_excepthook
    from cStringIO import StringIO
  File "<frozen importlib._bootstrap>", line 1565, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1523, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 1475, in _find_module
TypeError: 'NoneType' object is not iterable

Original exception was:
Traceback (most recent call last):
  File "/home/cheatfate/Projects/test_container.py", line 36, in do_forall
    if not callback is None:
AttributeError: 'TestContainer' object has no attribute 'children'
Error in sys.excepthook:

Original exception was:

经过一些调查,我发现由于某种原因,我的TestContainer在内存中移动到了其他地址,丢失了所有私有变量。正如您所看到的,我们在标准输出中得到了:

do_forall() self = 7f97be2c5140
do_forall() self = 7f97c7cc7820

所以问题是“我做错了什么?”
1个回答

4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接