将旧信号和插槽转换为新样式的正确方法?

2022-01-12 00:00:00 python pyqt5 pyqt4 syntax signals-slots

问题描述

我目前正在尝试将旧的 python 程序从 Python 2 转换为 Python 3,并从 PyQt4 更新为 PyQt5.该应用程序使用 PyQt5 不支持的旧式信号和插槽.我已经弄清楚了大部分需要做的事情,但下面有几行我似乎无法工作:

I'm currently trying to convert an old python program from Python 2 to Python 3, and update from PyQt4 to PyQt5. The application uses the old style signal and slots that are not supported under PyQt5. I have figured out most of what needs to be done, but below are a few lines that I can't seem to get working:

self.emit(SIGNAL('currentChanged'), row, col)
self.emit(SIGNAL("activated(const QString &)"), self.currentText())
self.connect(self,SIGNAL("currentChanged(const QString&)"), self.currentChanged)

前两行,我不知道从哪里开始,因为它们似乎没有附加任何东西.最后一个例子我不太确定如何处理 (const QString &).

The top two lines, I have no idea where to start since they don't seem to be attached to anything. The last example I'm not quite sure what to do with (const QString &).

我不完全确定如何处理这些问题,而且我仍在学习 python,但我们将不胜感激.

I'm not entirely sure how to approach these, and I'm still learning python, but any help would be appreciated.

文档似乎并没有真正深入探讨这些案例,至少以我理解的方式.

The documentation doesn't really seem to go into depth on these cases, at least in a way that I understand.


解决方案

这个问题的确切答案将取决于 self 是什么类型的对象.如果它是一个已经定义了这些信号的 Qt 类,那么新式语法将是这样的:

The exact answer to this will depend on what kind of object self is. If it is a Qt class that already defines those signals, then the new-style syntax would be this:

self.currentChanged[int, int].emit(row, col)
self.activated[str].emit(self.currentText())
self.currentChanged[str].connect(self.handleCurrentChanged)

但是,如果其中任何一个没有预定义,您需要为它们定义自定义信号,如下所示:

However, if any of those aren't pre-defined, you would need to define custom signals for them, like this:

class MyClass(QWidget):
    # this defines two overloads for currentChanged
    currentChanged = QtCore.pyqtSignal([int, int], [str])
    activated = QtCore.pyqtSignal(str)

    def __init__(self, parent=None):
        super(MyClass, self).__init__(parent)
        self.currentChanged[str].connect(self.handleCurrentChanged)   

    def handleCurrentChanged(self, text):
        print(text)

旧式语法允许动态发出自定义信号(即无需先定义它们),但这不再可能了.使用新式语法,必须始终明确定义自定义信号.

The old-style syntax allowed custom signals to be emitted dynamically (i.e. without defining them first), but that is not possible any more. With the new-style syntax, custom signals must always be explicitly defined.

请注意,如果只为信号定义了一个重载,则可以省略选择器:

Note that, if there is only one overload defined for a signal, the selector can be omitted:

    self.activated.emit(self.currentText())

有关更多信息,请参阅 PyQt 文档中的这些文章:

For more information, see these articles in the PyQt Docs:

  • 支持信号和插槽 (PyQt5)
  • 旧式信号和插槽支持 (PyQt4)
  • 新型信号和插槽支持 (PyQt4)

编辑:

对于您的实际代码,您需要对 currentChanged 信号进行以下更改:

For your actual code, you need to make the following changes for the currentChanged signals:

  1. 在 Multibar.py 中(大约第 30 行):

  1. In Multibar.py (around line 30):

这定义了一个自定义信号(因为QWidget没有它):

This defines a custom signal (because QWidget does not have it):

class MultiTabBar(QWidget):
    # add the following line
    currentChanged = pyqtSignal(int, int)

  • 在 Multibar.py 中(大约第 133 行):

  • In Multibar.py (around line 133):

    这会发出 (1) 中定义的自定义信号:

    This emits the custom signal defined in (1):

    # self.emit(SIGNAL('currentChanged'), row, col)
    self.currentChanged.emit(row, col)
    

  • 在 ScWindow.py 中(大约第 478 行):

  • In ScWindow.py (around line 478):

    这将连接(1)中定义的信号:

    This connects the signal defined in (1):

        # self.connect(self.PieceTab,SIGNAL("currentChanged"),self.pieceTabChanged)
        self.PieceTab.currentChanged.connect(self.pieceTabChanged)
    

  • 在 ItemList.py 中(大约第 73 行):

  • In ItemList.py (around line 73):

    QFileDialog 类已经定义了这个信号,它只有一个重载.但是插槽的名称必须更改,因为它隐藏了内置信号名称(已成为新式语法中的属性).所以连接应该是这样的:

    The QFileDialog class already defines this signal, and there is only one overload of it. But the name of the slot must be changed, because it is shadowing the built-in signal name (which has become an attribute in the new-style syntax). So the connection should be made like this:

        # self.connect(self,SIGNAL("currentChanged(const QString&)"),self.currentChanged)
        self.currentChanged.connect(self.onCurrentChanged)
    

  • 在 ItemList.py 中(大约第 78 行):

  • In ItemList.py (around line 78):

    这将重命名 (4) 中建立的连接的插槽:

    This renames the slot for the connection made in (4):

        # def currentChanged(self, file):
        def onCurrentChanged(self, file):
    

  • 相关文章