首页 > 解决方案 > 有没有办法在 pygobject 中修补 Gtk.Widget 方法(用于调试)

问题描述

我正在使用 pygobject 3.24 在 python+gtk3 中编写应用程序

我正在开发自定义小部件,需要有关调用堆栈和返回值的信息do_get_preferred_widthdo_size_allocate等等,以便调试我遇到的布局问题。

我正在尝试为常规 Gtk 小部件(如 Gtk.Box、Gtk.Paned 等)修补这些方法。新方法只会调用原始方法,但会将它们的输入/输出打印到日志文件中,这样我就可以遵循布局逻辑.

我可以通过为其中的每一个创建子类来实现这一点,但由于我的应用程序使用.ui依赖于原始类的文件,我无法安装这些修补类并仍然使用模板(pygobject不支持模板中的派生小部件)。在应用程序中重新创建模板逻辑需要大量工作。

理想情况下,我可以像这样动态地修补方法:

builder = Gtk.Builder.new_from_file('my-template.ui')
box = builder.get_object('my-box')
box.do_get_preferred_width = patched_do_get_preferred_width

但这似乎没有效果。如果我尝试在班级级别设置它,它也不起作用:

Gtk.Box.do_get_preferred_width = patched_do_get_preferred_width

运行时似乎完全没有意识到这些变化。我怀疑这是因为底层调用都在 C 中。此时我很想将日志消息插入到 C 源代码中并自己构建它,但这感觉有点过头了。

有谁知道我怎样才能完成这个猴子补丁?或者轻松获取我需要的信息?(GTK 调试器信息量不足)

标签: gtk3pygobject

解决方案


您是否需要在生产中仅用于调试目的?如果是后者,您可以从特定的 Gtk 小部件子类化并覆盖您感兴趣的方法。试试这个 MCVE:

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk

class Box(Gtk.Box):
    def __init__(self, *args):
        super().__init__(self, *args)

    def get_allocated_width(self):
        val = super().get_allocated_width()
        print("val: ", val)
        return val

def clicked(button, box):
    print (box.get_allocated_width())

Gtk.Box = Box # make following calls to Gtk.Box return overriden version
win = Gtk.Window()
box = Gtk.Box()
win.add(box)
button = Gtk.Button("foo")
button.connect("clicked", clicked, box)
box.add(button)
win.show_all()
Gtk.main()

如果您需要批量修补,您可以使用技术。


推荐阅读