PySide(或PyQt)信号和槽的基础知识

3
考虑一个简单的例子,它使用信号和槽将两个滑块链接起来:
```html

考虑一个简单的例子,它使用信号和槽将两个滑块链接起来:

```
from PySide.QtCore import *
from PySide.QtGui import *
import sys

class MyMainWindow(QWidget):
 def __init__(self):
  QWidget.__init__(self, None)

  vbox = QVBoxLayout()

  sone = QSlider(Qt.Horizontal)
  vbox.addWidget(sone)

  stwo = QSlider(Qt.Horizontal)
  vbox.addWidget(stwo)

  sone.valueChanged.connect(stwo.setValue)

if __name__ == '__main__':
 app = QApplication(sys.argv)
 w = MyMainWindow()
 w.show()
 sys.exit(app.exec_())

您想如何更改此代码,以使第二个滑块的方向与第一个相反?首个滑块将使用以下值初始化:

  sone.setRange(0,99)
  sone.setValue(0)

滑块二将使用这些值进行初始化:

  stwo.setRange(0,99)
  stwo.setValue(99)

然后stwo的值将为99-sone.sliderPosition

您将如何实现信号和槽以使其工作?我将感谢一个建立在上述简单示例基础上的可行示例。

3个回答

3

您可以将信号连接到执行操作的函数。如果您的代码不能轻松实现这一点,需要进行重构,那么您可以采用简单的方法:

stwo.setInvertedAppearance(True)
sone.valueChanged.connect(stwo.setValue)

3

您的示例有点问题,因为您忘记设置布局的父级,并且还要将滑块小部件保存为成员属性以供以后访问...但是回答您的问题,只需要将连接指向自己的函数即可:

class MyMainWindow(QWidget):
    def __init__(self):
        QWidget.__init__(self, None)

        vbox = QVBoxLayout(self)

        self.sone = QSlider(Qt.Horizontal)
        self.sone.setRange(0,99)
        self.sone.setValue(0)
        vbox.addWidget(self.sone)

        self.stwo = QSlider(Qt.Horizontal)
        self.stwo.setRange(0,99)
        self.stwo.setValue(99)
        vbox.addWidget(self.stwo)

        self.sone.valueChanged.connect(self.sliderChanged)

    def sliderChanged(self, val):
        self.stwo.setValue(self.stwo.maximum() - val)

注意,sliderChanged() 的签名与原始的 setValue() slot 相同。您不是直接将一个widget连接到另一个widget,而是将其连接到自定义方法,然后将值转换为所需的值,并以所需的方式进行操作(在 stwo 上设置自定义值)。


抱歉这个例子不好,我还在学习中。我尝试运行了你的例子,但是出现了一个空白窗口,没有滑块(也没有错误)。后来我注意到你编辑了你的回答,现在当我尝试运行你的代码时,会出现“NameError: name 'QWidget' is not defined”的错误。我会看看能否自己解决。顺便说一句,感谢你对正确处理这个问题提出的建议。 - MountainX
@MountainX:不需要为你的示例道歉。你提出了一个组织良好的问题。很高兴你解决了它! - jdi

0

这是我实现的方法。我添加了一个重新实现setValue的类。(我从http://zetcode.com/tutorials/pyqt4/eventsandsignals/得到了灵感)

class MySlider(QSlider):
    def __init__(self):
        QSlider.__init__(self, Qt.Horizontal)

    def setValue(self, int):
        QSlider.setValue(self, 99-int)

这是完整的代码。这是一个好的方法吗?

from PySide.QtCore import *
from PySide.QtGui import *
import sys

class MySlider(QSlider):
    def __init__(self):
        QSlider.__init__(self, Qt.Horizontal)

    def setValue(self, int):
        QSlider.setValue(self, 99-int)

class MyMainWindow(QWidget):
 def __init__(self):
  QWidget.__init__(self, None)

  vbox = QVBoxLayout()

  sone = QSlider(Qt.Horizontal)
  sone.setRange(0,99)
  sone.setValue(0)
  vbox.addWidget(sone)

  stwo = MySlider()
  stwo.setRange(0,99)
  stwo.setValue(0)
  vbox.addWidget(stwo)

  sone.valueChanged.connect(stwo.setValue)

  self.setLayout(vbox)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MyMainWindow()
    w.show()
    sys.exit(app.exec_())

你不需要子类化。只需连接到另一个槽。利用您可以将信号连接到任何方法的事实。我认为这种方法的问题在于,您正在避免使用Qt类上已经可用的功能,并且仅在不需要时进行子类化。将您的小部件保存为实例属性并使用它们。 - jdi
此外,现在您有一个名为MySlider的类,它只是硬编码将其值设置为99-int(int顺便遮蔽了内置的int)。 - jdi
@jdi:感谢您对int变量遮蔽内置int的反馈。代码应该是def setValue(self, val): QSlider.setValue(self, 99-val)。但无论如何,您的方法更好。这对我来说是一个学习练习,现在我知道了几种方法可以做到这一点。 - MountainX

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接