Дополнение QLayout — предотвращает передачу права собственности

#python #qt #pyqt #qlayout

#python #qt #pyqt #qlayout

Вопрос:

У меня возникли проблемы со ссылками на объекты при использовании QLayout для размещения моих виджетов в большом окне рядом друг с другом.

У меня следующая ситуация

 class MyClass(QObject):
     widgetCollection = []

     def spawn(self):
         widget = MyQWidget() #containing a QLineWidget called "nameEdit"
         self.widgetCollection.append(widget)
         self._window = QtGui.QWidget()
         layout = QtGui.QHBoxLayout()

         listView = QtGui.QListWidget()            
         for equation in self.wigdetCollection:
              equationName = equation.nameEdit.text()
              item = QtGui.QListWidgetItem(equationName)
              listView.addItem(item)

         layout.addWidget(listView)
         layout.addWidget(widget)

         self._window.setWindowTitle("Equation Editor")
         self._window.setLayout(layout)

         self._window.show()

    def respawn(self):
         self.spawn()
  

Каждый раз, когда я вызываю spawn(), я хочу добавить новый виджет в коллекцию. Кроме того, я хочу открыть новое окно, в котором есть ListView со всеми именами виджетов слева и вновь созданным виджетом справа.

Теперь первый вызов метода spawn() работает так, как ожидалось. Но второй вызов выдает исключение:

 equationName = widget.nameEdit.text()
RuntimeError: wrapped C/C   object of type QLineEdit has been deleted
  

Я думаю, что это как-то связано со строкой

 layout.addWidget(widget)
  

Я где-то читал, что макет становится владельцем виджета при добавлении в качестве элемента. При этом я удаляю виджет, как только я выхожу за пределы области ссылки на макет (которая в данном случае является локальной). Итак, похоже, что элемент виджета в моей коллекции тоже удаляется.

Кто-нибудь может помочь? Как мне это предотвратить.

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

1. Вам нужно показать код для MyQWidget класса.

Ответ №1:

Проблема в том, что self._window заменяется каждый раз при закрытии spawn(): Python удаляет старый виджет window и self._window создается для ссылки на новый экземпляр QWidget. Поскольку старый виджет window является родительским для представления списка и виджета qlineedit (называемого в коде — ошибочно — просто «widget»), они будут уничтожены в смысле Qt этого термина — т. Е. их часть C будет уничтожена. Представление списка нигде больше не упоминается в показанном коде, поэтому часть представления списка на Python также будет уничтожена, и так и должно быть.

ОДНАКО на qlineedit есть ссылка в реестре всего класса (widgetCollection), и поэтому часть qlineedit на языке Python не будет уничтожена. Это означает, что каждый раз, когда вызывается spawn(), предыдущий экземпляр QLineEdit (через MyQWidget в widgetCollection всего класса) становится зомби: он мертв на уровне C Qt, но он все еще жив на уровне Python. Доступ к методам зомби по-прежнему возможен, но во многих случаях вы увидите ошибку Qt об удалении C / C , и вы можете получить сбой или другое неопределенное поведение.

Из опубликованного кода неясно, какова цель widgetCollection, но поскольку предыдущий добавленный элемент станет зомби во время spawn(), widgetCollection бесполезен, как показано. Решение проблемы зависит от деталей о том, как используется коллекция, но поскольку можно предположить, что у коллекции есть назначение, тогда проблема заключается в замене window widget: возможно, коллекция виджетов должна быть window collection, тогда, когда self._window заменяется, предыдущее окно остается активным, поэтому дочерние виджеты тоже остаются активными.

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

1. MyQWidget() — это диалоговое окно с некоторыми QLineEdits для пользовательского ввода. В каждом диалоговом окне есть кнопка, которая связана с методом Respawn(). _window показывает это диалоговое окно в сочетании со списком всех предыдущих добавленных диалоговых окон. Все обрабатывается суперклассом MyClass(), который является своего рода основной функцией, вызываемой другой программой. Этот класс хранит все ссылки. Поскольку мне нужны входные данные из разных диалоговых окон, все они собираются в widgetCollection и только позже анализируются сканером. Respawn создает диалоговое окно внутри диалогового окна.

Ответ №2:

Решил это сам 🙂

Мой первоначальный вызов метода spawn() был таким:

 mc = MyClass()
mc.spawn()
  

Первый вариант в порядке. Теперь я хотел создать другой изнутри inst1 . Для этого я использовал

 self.spawn()
  

в respawn() -методе возникает вышеупомянутая ошибка.

Это должно быть следующее

  def respawn(self):
     mc = MyClass()
     mc.spawn()
  

Мне пришлось создать другой экземпляр, MyClass который разделяет widgetCollection со всеми другими экземплярами. По желанию….

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

1. Вы можете принять свой собственный ответ, чтобы указать, что вы решили проблему самостоятельно — это обычный сценарий.

2. Я знаю 🙂 Но не в течение следующих двух дней. Я получаю сообщение «Вы можете принять свой собственный ответ через 2 дня»….

3. Это очень неясно. Во-первых, spawn() ничего не возвращает, поэтому inst1 и 2 будут None. Пожалуйста, уточните.