我正在尝试使用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 = None
super().__init__()
def do_add(self, widget):
if not widget is None:
if not self.children is None:
self.children.append({ "widget" : widget })
else:
self.children = []
self.children.append({ "widget" : widget })
widget.set_parent(self)
def do_remove(self, widget):
print("do_remove()")
if not widget is None:
if not self.children is None:
for item in self.children:
if item["widget"] == widget:
self.children.remove(item)
widget.unparent()
break
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 self.children is None and not callback is None:
for item in self.children:
widget = item["widget"]
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
if not self.children is None:
length = len(self.children)
for item in self.children:
widget = item["widget"]
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)
if not self.children is None:
for item in self.children:
widget = item["widget"]
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 item in self.children:
self.propagate_draw(item["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 self.children is None and 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 self.children is None and not callback is None:
AttributeError: 'TestContainer' object has no attribute 'children'
Error in sys.excepthook:
Original exception was:
经过一些调查后我发现由于某些原因,我的TestContainer将内存移到其他地址并丢失了所有私有变量。如你所见,我们进入了stdout:
do_forall() self = 7f97be2c5140
do_forall() self = 7f97c7cc7820
所以问题是“我做错了什么?”