Основы сигналов и слотов PySide (или PyQt)

Рассмотрим простой пример, как этот, который связывает два ползунка, используя сигналы и слоты

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)

который переопределяет 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_())
 MountainX04 июн. 2012 г., 07:47
@jdi: Хорошо, спасибо за ваш ответ.
 04 июн. 2012 г., 07:39
Вам не нужно подкласс. Просто подключитесь к другому слоту. Воспользуйтесь тем, что вы можете подключить сигнал к любому методу. Проблема, на мой взгляд, заключается в том, что вы избегаете более простого пути использования функциональности, которая уже доступна в классе Qt, и создания подклассов, когда это не нужно. Сохраните ваши виджеты как атрибуты экземпляра и используйте их.
 04 июн. 2012 г., 07:47
Кроме того, теперь у вас есть класс MySlider, который просто жестко задан для установки его значения как99-int (Между прочим, затенение встроенногоint)
 MountainX04 июн. 2012 г., 07:58
@jdi: Я ценю отзывы о том, что int затеняет встроенный int. Код должен быть `def setValue (self, val): QSlider.setValue (self, 99-val)". Но твой подход все равно лучше. Для меня это было учебное упражнение, так что теперь я знаю несколько способов сделать это.

которые делают вещи. Ваш код не структурирован, чтобы сделать это легко и требует рефакторинга, поэтому вы можете сделать это простым способом:

stwo.setInvertedAppearance(True)
sone.valueChanged.connect(stwo.setValue)
Решение Вопроса

потому что вы забыли установить родительский элемент макета, а также сохранить виджеты ползунка в качестве атрибутов элемента, к которым вы будете обращаться позже ... Но чтобы ответить на ваш вопрос, на самом деле все так же просто, как просто указать ваше соединение к вашей собственной функции:

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() слот. Вместо того чтобы подключать один виджет напрямую к другому, вы подключаете его к пользовательскому методу, а затем преобразуете значение в то, что вам нужно, и действуете так, как вы хотите (устанавливая пользовательское значение наstwo)

 04 июн. 2012 г., 17:18
@MountainX: не нужно извиняться за ваши примеры. У вас был хорошо организованный вопрос. Рад, что ты получил это работает!
 MountainX04 июн. 2012 г., 07:50
Получил это работает. Благодарю.
 MountainX04 июн. 2012 г., 07:46
Извините за плохой пример. Я только учусь. Я попытался запустить ваш пример, и я получил пустое окно без ползунков (и без ошибок). Потом я заметил, что вы отредактировали свой ответ. Теперь я получаю сообщение об ошибке "NameError: name" a QWidget & apos; не определено & quot; когда я пытаюсь запустить ваш код. Я посмотрю, смогу ли я понять это. Кстати, спасибо за предложения о том, как правильно подойти к этому.

Ваш ответ на вопрос