如何在MVC架构下处理Gtk.Switch的notify::active信号?
搞定Gtk.Switch notify::active信号的TypeError问题
嘿,你遇到的这个TypeError问题其实是自定义信号的签名和参数传递不匹配导致的,我来给你拆解一下问题根源和解决办法:
问题出在哪?
- 你在
View类里定义的switch_serial_toggled自定义信号,没有声明要传递任何参数,但Controller里的_on_switch_serial_toggled函数却等着接收switch和state两个参数。 - 当你在
View的on_switch_serial_toggled方法里触发自定义信号时,只调用了self.emit('switch_serial_toggled'),没把switch和state传过去,导致Controller的处理函数接不到足够的参数,直接报错。
修正方案
只需要两步就能解决:
- 第一步:更新
View类的__gsignals__定义,让自定义信号能传递对应的参数 - 第二步:在触发自定义信号时,把
switch和state参数一起传出去
修改后的完整代码
import sys import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk, Gio, GObject class Application(Gtk.Application): def __init__(self): app_id = "org.iea.etc" flags = Gio.ApplicationFlags.FLAGS_NONE super(Application, self).__init__(application_id=app_id, flags=flags) def do_activate(self): Controller(None, View(application=self)) def do_startup(self): Gtk.Application.do_startup(self) class Controller(object): def __init__(self, model, view): self._model = model self._view = view self._view.connect('switch_serial_toggled', self._on_switch_serial_toggled) self._view.show_all() def _on_switch_serial_toggled(self, switch, state): if switch.get_active(): print('Switch ON') else: print('Switch OFF') class View(Gtk.ApplicationWindow): # 这里修改了信号签名,声明要传递两个参数:Gtk对象和任意Python对象 __gsignals__ = { 'switch_serial_toggled': (GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_OBJECT, GObject.TYPE_PYOBJECT)) } def __init__(self, **kw): super(View, self).__init__(**kw) self._switch_serial = Gtk.Switch() self._switch_serial.connect("notify::active", self.on_switch_serial_toggled) self.add(self._switch_serial) def on_switch_serial_toggled(self, switch, state): # emit时把接收到的switch和state一起传递出去 self.emit('switch_serial_toggled', switch, state) if __name__ == '__main__': app = Application() exit_status = app.run(sys.argv) sys.exit(exit_status)
关键修改说明
- 在
__gsignals__里,第三个元素是参数类型的元组:(GObject.TYPE_OBJECT, GObject.TYPE_PYOBJECT)分别对应Gtk.Switch实例和notify信号的state参数(GParamSpec对象)。 - 触发信号时
self.emit('switch_serial_toggled', switch, state),把原信号的参数原封不动传递给自定义信号,这样Controller的处理函数就能拿到需要的参数,不会再报错。
另外,如果你的业务逻辑里不需要state参数(毕竟可以直接通过switch.get_active()获取开关状态),也可以简化自定义信号的参数,比如只传递switch,或者不传递参数,但记得同步修改Controller的处理函数参数哦。
内容的提问来源于stack exchange,提问作者amartin1911
相关产品推荐
相关产品推荐

