Pygobject / Gtk 在小部件上绘制
Pygobject / Gtk draw on top of widgets
在 pygobject(或 Gtk)中是否可以在 Gtk.Container 小部件(例如 VBox
)的 children 小部件之上绘制?
我知道我可以连接到任何自定义绘图小部件的 'draw'
信号。但是回调是在正常的widget绘制之前调用的。
所以任何“自定义”绘图都留在容器的 children 后面,除非回调函数连接到绘图信号 return True,在这种情况下信号不会传播并且容器不绘制其 children;但这不是我想要的。
我需要在 容器 绘制其 children 之后绘制 。
我知道除了响应绘图信号外,我还可以重写子class 中的do_draw
方法,但容器又不会绘制其children。我必须调用 parent class 绘图方法,但我不知道如何调用。
我尝试调用 super().do_draw 和 super().draw() 但出现堆栈溢出错误,这意味着我的 do_draw 函数正在调用自身。
你知道一些解决办法吗?
python GObject 中的方法名称如 do_something
被视为基本 C classes/interfaces 之一中相应的 something
虚函数的实现。 Metaclass wizadry/hackery is used to implement this virtual function registration whenever you subclass GObject.Object
. I believe you want to know how to chain up 到 PyGObject 中父虚函数的实现。
我的猜测是,当您调用 super().draw()
时,您只是 calling a wrapper draw()
函数,然后会将调用转发给子 class 的虚拟函数实现。
当您访问 super().do_draw
时,您正在直接检索 VFuncInfo
. This is a callable wrapper object that will invoke the appropriate virtual function for you. It uses the owner argument from __get__()
(descriptor protocol) to determine which child class implementation to use when you __call__()
. As such, super().do_draw()
will also again refer to your subclass's implementation. You can manually specify the class whose vfunc implementation you actually want by calling VFuncInfo.invoke()
,例如
super().do_draw.invoke(Gtk.VBox, self, *args, **kwargs)
没有什么可以阻止您使用您未继承的 class,尽管可能会发生不好的事情。
或者您可以通过父 class 访问 do_draw
,以便根据需要分配描述符协议中的所有者参数,您只需 __call__()
:
Gtk.VBox.do_draw(self, *args, **kwargs)
演示:
import cairo
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class MyVBox(Gtk.VBox):
def do_draw(self, cr: cairo.Context) -> None:
"""Overlay a red rectangle in the top-left corner."""
Gtk.VBox.do_draw(self, cr)
# If you don't want to hard-code the parent class:
# __class__.mro()[1].do_draw(self, cr)
cr.rectangle(10, 10, 64, 64)
cr.set_source_rgba(1., 0., 0.)
cr.fill()
window = Gtk.Window()
vbox = MyVBox()
window.add(vbox)
button = Gtk.Button(label="Button")
label = Gtk.Label(label="^^^ Click me ^^^")
vbox.add(button)
vbox.add(label)
window.show_all()
button.connect('clicked', lambda *_: print("Button clicked"))
window.connect('delete-event', Gtk.main_quit)
Gtk.main()
我不知道这是否是在小部件上绘制的最佳方式。
在 pygobject(或 Gtk)中是否可以在 Gtk.Container 小部件(例如 VBox
)的 children 小部件之上绘制?
我知道我可以连接到任何自定义绘图小部件的 'draw'
信号。但是回调是在正常的widget绘制之前调用的。
所以任何“自定义”绘图都留在容器的 children 后面,除非回调函数连接到绘图信号 return True,在这种情况下信号不会传播并且容器不绘制其 children;但这不是我想要的。
我需要在 容器 绘制其 children 之后绘制 。
我知道除了响应绘图信号外,我还可以重写子class 中的do_draw
方法,但容器又不会绘制其children。我必须调用 parent class 绘图方法,但我不知道如何调用。
我尝试调用 super().do_draw 和 super().draw() 但出现堆栈溢出错误,这意味着我的 do_draw 函数正在调用自身。
你知道一些解决办法吗?
python GObject 中的方法名称如 do_something
被视为基本 C classes/interfaces 之一中相应的 something
虚函数的实现。 Metaclass wizadry/hackery is used to implement this virtual function registration whenever you subclass GObject.Object
. I believe you want to know how to chain up 到 PyGObject 中父虚函数的实现。
我的猜测是,当您调用 super().draw()
时,您只是 calling a wrapper draw()
函数,然后会将调用转发给子 class 的虚拟函数实现。
当您访问 super().do_draw
时,您正在直接检索 VFuncInfo
. This is a callable wrapper object that will invoke the appropriate virtual function for you. It uses the owner argument from __get__()
(descriptor protocol) to determine which child class implementation to use when you __call__()
. As such, super().do_draw()
will also again refer to your subclass's implementation. You can manually specify the class whose vfunc implementation you actually want by calling VFuncInfo.invoke()
,例如
super().do_draw.invoke(Gtk.VBox, self, *args, **kwargs)
没有什么可以阻止您使用您未继承的 class,尽管可能会发生不好的事情。
或者您可以通过父 class 访问 do_draw
,以便根据需要分配描述符协议中的所有者参数,您只需 __call__()
:
Gtk.VBox.do_draw(self, *args, **kwargs)
演示:
import cairo
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class MyVBox(Gtk.VBox):
def do_draw(self, cr: cairo.Context) -> None:
"""Overlay a red rectangle in the top-left corner."""
Gtk.VBox.do_draw(self, cr)
# If you don't want to hard-code the parent class:
# __class__.mro()[1].do_draw(self, cr)
cr.rectangle(10, 10, 64, 64)
cr.set_source_rgba(1., 0., 0.)
cr.fill()
window = Gtk.Window()
vbox = MyVBox()
window.add(vbox)
button = Gtk.Button(label="Button")
label = Gtk.Label(label="^^^ Click me ^^^")
vbox.add(button)
vbox.add(label)
window.show_all()
button.connect('clicked', lambda *_: print("Button clicked"))
window.connect('delete-event', Gtk.main_quit)
Gtk.main()
我不知道这是否是在小部件上绘制的最佳方式。