Найти - Пользователи
Полная версия: PyQt: новый стиль подключения сигнал-слот
Начало » GUI » PyQt: новый стиль подключения сигнал-слот
1
voltron
Пробую использовать новый стиль подключения сигналов и слотов.

Есть диалоговое окно с QDialogButtonBox, на котором две кнопки OK и Close. В процессе работы надо сделать так, чтобы нажатие на Close не закрывало диалог, а вызывало другой слот. Раньше делал так
self.btnClose = self.buttonBox.button( QDialogButtonBox.Close )
# отсоединение
QObject.disconnect( self.buttonBox, SIGNAL( "rejected()" ), self.reject )
# и подключение к другому слоту
QObject.connect( self.btnClose, SIGNAL( "clicked()" ), self.stopProcessing )
....
# восстанавливаем исходное состояние
QObject.disconnect( self.btnClose, SIGNAL( "clicked()" ), self.stopProcessing )
QObject.connect( self.buttonBox, SIGNAL( "rejected()" ), self.reject )
и все работало как надо. При этом слот self.reject в коде отсутствует, т.е. вызывался слот родителя (QDialog). Теперь делаю с использованием нового стиля
self.btnClose = self.buttonBox.button( QDialogButtonBox.Close )
self.buttonBox.rejected.disconnect( self.reject )
self.btnClose.clicked.connect( self.stopProcessing )
...
self.btnClose.clicked.disconnect( self.stopProcessing )
self.buttonBox.rejected.connect( self.reject )
И при выполнении получаю следующую ошибку
line 147, in prepareProcess
self.buttonBox.rejected.disconnect( self.reject )
TypeError: disconnect() failed between ‘rejected’ and ‘reject’
Заменяю эти строки подключения на старый стиль — все работает. В чем может быть дело или это у меня карма плохая?
iroln
Есть диалоговое окно с QDialogButtonBox…
Окно создано в Designer, а код сгенерирован через pyqt-uic? Если так, то он генерирует код в котором соединение ‘rejected’ к ‘reject’ выполняется старым способом.

QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("accepted()"), Dialog.accept)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("rejected()"), Dialog.reject)

Мне кажется, проблема может быть в том, что соединение создано старым способом, а разрыв соединения вы пытаетесь сделать по-новому. Но эта теория, конечно, требует проверки.
reclosedev
Странно.
Попробовал на PySide, там работает нормально. Только если второй раз пытаешься disconnect сделать, тогда вылетает исключение.

На PyQt работает способ с отсоединением всех слотов т.е.
self.ui.buttonBox.rejected.disconnect()
В случае с диалогом, думаю, это допустимо.
voltron
iroln
Окно создано в Designer, а код сгенерирован через pyqt-uic?
Да, именно так: интерфейс создается в Designer а потом при помощи pyuic4 получаем код
iroln
Если так, то он генерирует код в котором соединение ‘rejected’ к ‘reject’ выполняется старым способом.
Похоже, проблема как раз в этом. Отредактировал сгенерированный pyuic4 код, заменив старый стиль на новый и все заработало. Но это костыльное решение, править автоматически генерируемые файлы не самый лучший вариант. Получается новый стиль еще не польностью готов к использованию.

reclosedev, я правильно понимаю, что у тебя на PyQt это воспроизводится? Можешь запостить используемые версии Qt, PyQt и Python? Попробую написать в рассылку.
reclosedev
voltron
reclosedev, я правильно понимаю, что у тебя на PyQt это воспроизводится?
Да, воспроизводится.
voltron
Можешь запостить используемые версии Qt, PyQt и Python? Попробую написать в рассылку.

Win32
Python 2.7.3, PyQt 4.9, Qt 4.8.0
Python 3.2.2, PyQt 4.9.1, Qt 4.8.0
iroln
voltron
Похоже, проблема как раз в этом. Отредактировал сгенерированный pyuic4 код, заменив старый стиль на новый и все заработало. Но это костыльное решение, править автоматически генерируемые файлы не самый лучший вариант. Получается новый стиль еще не польностью готов к использованию.
Мда… это провал. Если нет совместимости между api соединения сигналов, когда широко используется и то и то, подобные “прелести” будут лезть как из рога изобилия особенно в тех местах, где что-то генерирует код. Данный пример очень показательный, надо обязательно зарепортить баг в PyQt4.
voltron
Отписал в рассылку, посмотрим что скажут.
voltron
Получил ответ. Вот объяснение почему так происходит:
PyQt allows connections to be made to any Python callable.

With old style connections a proxy slot is created under the covers whenever a callable is used (as opposed to when SLOT() is used to refer to a C++ slot). Therefore, in your example, a proxy is always created for the connection to Dialog.reject even though that refers to the object that wraps the C++ slot (as there is no Python reimplementation of reject()).

New style connections are a bit smarter in that they treat slot objects that refer to a wrapped C++ slot and objects that refer to some real Python code differently - a proxy is only created in the latter case.
В качестве workaround'а предлагается реализовать слот-заглушку reject() вида
 def reject(self):
   QDialog.reject(self)
Это заставит подключения нового стиля создавать прокси и использовать его при вызове disconnect().

Разработчики согласны, что это баг, однако исправлять его не будут, т.к. для этого необходимо внести значительные изменения в старый код соединения сгналов-слотов, что в свою очередь может привести к появлению новых ошибок и уменьшить стабильность. Но обещают обновить документацию и добавить туда описание причин и способ решения.
iroln
Ясно. Хорошо, что хотя бы доку поправят. Отзывчивые разработчики. :)
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB