Кнопка pyqt автоматически привязывается к нажатой функции _..._ без connect или pyqtSlot - PullRequest
0 голосов
/ 25 февраля 2019

Я использую pyqt5 с qt-designer уже несколько недель.Я привык подключать сигналы к функциям-обработчикам с помощью операторов connect.

Вчера я создал фрагмент кода, который также автоматически подключал сигнал нажатия кнопки к функции-обработчику без декоратора pyqtSlot.

  • В результате подключения сигнала нажатия к функциипри выполнении функции три раза при нажатии кнопки один раз.

  • Удаление операторов соединения привело к двойному выполнению функции при нажатии кнопки один раз.

  • Добавление @pyqtSlot к функции привело к нормальному однократному выполнению.

  • Переименование функции-обработчика во что-то отличное от 'on_ button-name _clicked' также привело кпри обычном однократном выполнении.

Следующий код демонстрирует это поведение «автоматического подключения».

Может кто-нибудь объяснить, почему это автоматическое подключение с вызовом с двойным обработчиком происходит без подключения илиpyqtSlot?

Заранее спасибо, Мейс

from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QMainWindow
from PyQt5.uic import loadUi
import sys

class MainWindow(QMainWindow):

    def __init__(self):

        super().__init__()

        loadUi('MainWindowTestButton.ui', self)
        self.show()

    def on_pushButton_clicked(self):
        print('clicked')


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MainWindow()
    sys.exit(app.exec_())

Приведенный выше код печатает

нажал

нажал

при нажатии кнопки один.

Это файл MainWindowTestButton.ui из примера

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindowTestButton</class>
 <widget class="QMainWindow" name="MainWindowTestButton">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QPushButton" name="pushButton">
    <property name="geometry">
     <rect>
      <x>70</x>
      <y>60</y>
      <width>75</width>
      <height>23</height>
     </rect>
    </property>
    <property name="text">
     <string>PushButton</string>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>21</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

1 Ответ

0 голосов
/ 25 февраля 2019

Почему это автоматическое соединение?

Функция loadUi() внутренне вызывает метод connectSlotsByName () , который устанавливает автоматическое соединение, если какой-либо метод имеет структуру:

C ++:

void on_<object name>_<signal name>(<signal parameters>);

Python:

def on_<object name>_<signal name>(<signal parameters>):

В вашем случае метод on_pushButton_clicked удовлетворяет этому требованию, поскольку у вас естьQWidget (унаследовано от QObject) pushButton с именем объекта "pushButton":

<widget class="QPushButton" name="pushButton">

с сигналом с именем clicked.

Почему вы вызываете один и тот же метод дважды?

QPushButton имеет перегруженный сигнал щелчка, то есть существует несколько сигналов с одинаковым именем, но с разными аргументами.Если документы проверены:

void QAbstractButton::clicked(bool checked = false)

Хотя может быть сложно понять, что приведенный выше код эквивалентен:

clicked = pyqtSignal([], [bool])

И это похоже на:

clicked = pyqtSignal()
clicked = pyqtSignal([bool])

Таким образом, в заключение QPushButton имеет 2 сигнала щелчка, которые будут подключены к функции on_pushButton_clicked, поэтому, когда вы нажимаете кнопку, оба сигнала будут излучаться, вызывая оба одинаковых метода, так что нажатие будет напечатано 2раз.


Соединения не учитываются, если предыдущий сигнал был подключен тем же способом, поэтому при вашем ручном соединении будет 3 соединения (2 сигнала нажаты без аргументов [1 автоматическии еще один вручную] и 1 с сигналом, нажатым с аргументом), поэтому метод будет вызываться 3 раза.

Когда вы используете декоратор @pyqtSlot, вы указываете сигнатуру (то есть тип аргументов), поэтомуметод connect устанавливает соединение только с сигналом, соответствующим сигнатуре слота, so вы больше не видите проблему, поскольку используете сигнал без аргументов

...