You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PySide6/Python中DBus PropertiesChanged信号无法触发槽函数

连接DBus PropertiesChanged信号(含嵌套结构)的PySide6/Python解决方案

问题背景

需要通过PySide6/Python连接DBus的PropertiesChanged信号,该信号签名为:

org.freedesktop.DBus.Properties.PropertiesChanged (STRING interface_name,
                                                   ARRAY of DICT_ENTRY<STRING,VARIANT> changed_properties,
                                                   ARRAY<STRING> invalidated_properties);

目标是获取MPRIS标准的元数据(含嵌套字典、数组结构),当前用NetworkManager测试时,触发信号但槽函数始终不执行;sdbus+asyncio可正常工作,但PySide的asyncio存在未实现方法无法使用。此前已成功处理简单类型的DBus信号,但复杂嵌套结构的信号连接失败。

测试代码如下:

import sys
from PySide6.QtWidgets import QMainWindow
from PySide6 import QtDBus, QtCore
from PySide6.QtCore import QLibraryInfo, qVersion, Slot
from PySide6.QtWidgets import QApplication, QMainWindow

class MainWindow(QMainWindow):

    def __init__ (self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        service = "org.freedesktop.NetworkManager"
        #service="org.mpris.MediaPlayer2.spotifyd.instance7453"
        path = "/org/freedesktop/NetworkManager"
        #path="/org/mpris/MediaPlayer2"
        iface = "org.freedesktop.DBus.Properties"
        conn = QtDBus.QDBusConnection.systemBus()

        #without this, the conn.connect call hangs, seems to be a bug, is already reported and fixed.
        conn.registerObject('/', self)
        
        #bus.connect(service, path, iface, "PropertiesChanged", self, QtCore.SLOT("dbuspropertieschanged(QString,QVariantMap,QStringList)"))    
        #qt.dbus.integration: Could not connect "org.freedesktop.DBus.Properties" to dbuspropertieschanged(QString,QVariantMap,QStringList)

        conn.connect(service, path, iface, "PropertiesChanged", self, QtCore.SLOT("dbuspropertieschanged(QString, QVariantMap, QVariantList)"))    
        pass

    @Slot(str, dict, list)
    def dbuspropertieschanged(self, arg1:str, arg2:dict, arg3:list) -> None:
        print(arg1)
        print(arg2)
        print(arg3)
        pass

if __name__ == '__main__':
    print('Python {}.{}.{} {}'.format(sys.version_info[0], sys.version_info[1],
                                       sys.version_info[2], sys.platform))
    print(QLibraryInfo.build())
    app = QApplication(sys.argv)
    window = MainWindow()
    window.setWindowTitle(qVersion())
    window.resize(800, 480)
    window.show()
    sys.exit(app.exec())

解决方案

1. 修正信号-槽类型匹配问题

原代码中SLOT宏的类型签名与实际参数不匹配:DBus的ARRAY<STRING>对应Qt的QStringList,而非QVariantList。更可靠的方式是使用新风格信号连接,直接传递槽函数对象,避免手动编写字符串类型签名导致的错误。

2. 处理嵌套结构的自动转换

PySide6会自动将DBus的VARIANT类型转换为对应的Python类型(嵌套字典→dict、数组→list),无需额外注册自定义元类型,只需确保参数类型与信号签名对齐。

修正后的完整代码

import sys
from PySide6.QtWidgets import QMainWindow, QApplication
from PySide6 import QtDBus, QtCore
from PySide6.QtCore import QLibraryInfo, qVersion, Slot

class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 可替换为MPRIS服务信息,比如spotify
        service = "org.freedesktop.NetworkManager"
        path = "/org/freedesktop/NetworkManager"
        iface = "org.freedesktop.DBus.Properties"
        conn = QtDBus.QDBusConnection.systemBus()

        # 注册对象解决连接挂起的已知Bug
        conn.registerObject('/', self)

        # 使用新风格信号连接,自动推导类型
        success = conn.connect(
            service,
            path,
            iface,
            "PropertiesChanged",
            self.dbuspropertieschanged
        )
        # 调试连接状态
        if not success:
            print("信号连接失败!")
            print(conn.lastError().message())

    @Slot(str, dict, list)
    def dbuspropertieschanged(self, interface_name: str, changed_props: dict, invalidated_props: list) -> None:
        print(f"接口名: {interface_name}")
        print("变更的属性:")
        # 处理嵌套结构,比如MPRIS的Metadata
        for key, value in changed_props.items():
            print(f"  {key}: {value}")
        print(f"失效的属性: {invalidated_props}")

if __name__ == '__main__':
    print(f'Python {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro} {sys.platform}')
    print(QLibraryInfo.build())
    app = QApplication(sys.argv)
    window = MainWindow()
    window.setWindowTitle(qVersion())
    window.resize(800, 480)
    window.show()
    sys.exit(app.exec())

关键说明

  • 新风格连接:避免了字符串类型签名的拼写错误,Qt会自动匹配信号与槽的参数类型。
  • 错误排查:通过conn.connect的返回值和conn.lastError()可快速定位连接失败原因。
  • MPRIS适配:只需将service和path替换为对应媒体播放器的DBus信息(如org.mpris.MediaPlayer2.spotify和/org/mpris/MediaPlayer2),即可获取歌曲元数据等嵌套结构数据。

内容的提问来源于stack exchange,提问作者Drexel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 16:33:16