QSpacerItem приводит к сбою PyQt при создании экземпляра дважды

#python #user-interface #crash #pyqt

#python #пользовательский интерфейс #сбой #pyqt

Вопрос:

Я искал неприятную ошибку сбоя при выходе из моего приложения PyQt https://github.com/chipmuenk/pyfda уже больше года и только что случайно нашли его: следующий фрагмент кода

     self.cmbResponseType = QtGui.QComboBox(self)
    self.cmbFilterType = QtGui.QComboBox(self)
    self.cmbDesignMethod = QtGui.QComboBox(self)

    spacer = QtGui.QSpacerItem(1, 0, QtGui.QSizePolicy.Expanding,
                                     QtGui.QSizePolicy.Fixed)

    layHFilWdg = QtGui.QHBoxLayout() # container for filter subwidgets
    layHFilWdg.addWidget(self.cmbResponseType)
    layHFilWdg.addItem(spacer)
    layHFilWdg.addWidget(self.cmbFilterType)
    layHFilWdg.addItem(spacer)
    layHFilWdg.addWidget(self.cmbDesignMethod)
  

помещает три поля со списком в поле горизонтальной компоновки с переменным интервалом между ними.

Ошибка исчезает (больше не происходит сбоя при выходе), когда я комментирую одну из двух layHFilWdg.addItem(spacer) инструкций. Я использую python 2.7 … 3.5 и PyQt 4.8.

У меня в приложении много виджетов с вкладками (а также много других ошибок), и я работал в потоке разработки, который каким-то образом слишком долго подавлял ошибку, вот почему это заняло у меня так много времени. То, что сбой происходит только тогда, когда холст matplotlib был создан в совершенно не связанном подвиджете, — это просто еще одна странность, из-за которой я долгое время лаял не на то дерево …

У кого-нибудь есть идея, в чем проблема с приведенным выше кодом?

Ответ №1:

Это похоже на типичный случай, когда сборщик мусора Python удаляет объекты в порядке, который Qt не ожидает. Возможно, что добавление разделителя несколько раз в один и тот же макет может привести к тому, что Qt попытается удалить его дважды или удалить, когда его больше нет. Очевидным решением является простое: не делайте этого.

Так что либо каждый раз создавайте новый разделитель:

     def spacer():
        return QtGui.QSpacerItem(
            1, 0, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)

    ...

    layHFilWdg.addItem(spacer())
  

или просто используйте метод макета addStretch() :

     layHFilWdg.addWidget(self.cmbResponseType)
    layHFilWdg.addStretch()
  

Комментарии:

1. Это имеет смысл! Было бы сложно столкнуться с аналогичной ситуацией с другими виджетами, где вы ожидаете другого поведения для каждого экземпляра, но с разделителем…

2. По крайней мере, для QT 4.8.7 макет дважды удаляет разделитель… Иногда трудно уловимая ошибка