tl; dr
Проблема в том, что вы дважды вызывали setupUi
, а второй раз он использовал другой виджет в качестве аргумента.
Почему это не работает?
Когда вы генерируете файл с pyui c, он фактически создает класс на основе типа Python object
. Этот класс ничего не делает сам по себе, это просто «интерфейс» для загрузки элементов пользовательского интерфейса «pythoni c way».
Если вы попытаетесь открыть один из этих файлов (который Если никогда нельзя редактировать!), вы увидите что-то вроде этого:
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
self.progressBar = QtWidgets.QProgressBar(Form)
self.progressBar.setProperty("value", 24)
# ...
def retranslateUi(self, Form):
# things related to the localization of the ui
Официальное руководство по с использованием Designer сообщает в качестве первого примера, который на самом деле Ничего , кроме показа окна.
from PyQt5.QtWidgets import QApplication, QWidget
from ui_form import Ui_Form
# create an instance of the <i>base</i> class
window = QWidget()
# create an instance of the Ui "builder"
ui = Ui_Form()
# apply the ui to the base class created before
ui.setupUi(window)
Последний шаг является наиболее важным для понимания: внимательно посмотрите, какому объекту принадлежит метод setupUi
и его аргумент, затем go назад к содержимому файла, созданного с помощью pyui c:
def setupUi(self, Form):
Form.setObjectName("Form")
self.progressBar = QtWidgets.QProgressBar(Form)
Form
- это экземпляр QWidget, созданный ранее ("окно"), тогда как, очевидно, self
относится к экземпляру Ui_Form
; давайте переведем переменные в имя экземпляров, которые они представляют:
def setupUi(<b>ui</b>, <b>window</b>):
<b>window</b>.setObjectName("Form")
<b>ui</b>.progressBar = QtWidgets.QProgressBar(<b>window</b>)
В примере в начале это означает, что, хотя window
отображается с дочерними виджетами, они не атрибуты экземпляра: нет window.progressBar
.
Во втором примере в документации показан метод «одиночного наследования», который позволяет реализовать взаимодействия между виджетами («logi c») , Я буду использовать имена классов, как и выше:
from PyQt5.QtWidgets import QApplication, QWidget
from ui_form import Ui_Form
class MyWidget(QWidget):
def __init__(self):
super(MyWidget, self).__init__()
self.ui = Ui_Form()
self.ui.setupUi(self)
Теперь ui
является атрибутом экземпляра window
; давайте «переведем» setupUi
еще раз, предполагая, что теперь «self» является экземпляром создаваемого MyWidget:
class Ui_Form(object):
def setupUi(<b>window.ui</b>, <b>window</b>):
<b>window</b>.setObjectName("Form")
<b>window.ui</b>.progressBar = QtWidgets.QProgressBar(<b>window</b>)
Это означает, что теперь вы можете иметь доступ к виджетам из экземпляра окна. , но только через self.ui
(как в window.ui ).
Теперь давайте рассмотрим подход множественного наследования, который очень похож:
class MyWidget(QWidget, Ui_Form):
def __init__(self):
super(MyWidget, self).__init__()
self.setupUi(self)
В этом случае MyWidget наследует методы и атрибуты и Qwidget и Ui_Form. Давайте переведем это снова (обратите внимание на класс):
class MyWidget(object):
def setupUi(<b>window</b>, <b>window</b>):
<b>window</b>.setObjectName("Form")
<b>window</b>.progressBar = QtWidgets.QProgressBar(<b>window</b>)
Этот подход делает все виджеты прямыми атрибутами экземпляра (self.progressBar
, et c), и я обычно предлагаю это как более прямой и просто (часто случается так, что вы пытаетесь получить доступ к виджету и забываете префикс ui
, с этим методом этого не происходит).
Теперь, наконец, ваша проблема.
window = QWidget()
app = MyTest()
setupUi
вызывается в __init__
MyTest, что означает, что app
имеет атрибут с именем progressBar
, который в этот момент должен быть "видимым", как только мы вызовем app.show()
.
Вы также создали другой виджет (window
) и использовали setupUi
, используя , что в качестве параметра:
app.setupUi(window)
Давайте переведем его в последний раз (для чтобы избежать путаницы, давайте изменим имя «оконного» QWidget, который вы создали по ошибке):
def setupUi(<b>app</b>, <b>otherWindow</b>):
<b>otherWindow</b>.setObjectName("Form")
<b>app</b>.progressBar = QtWidgets.QProgressBar(<b>otherWindow</b>)
Как вы можете видеть, теперь вы «перезаписали» атрибут app.progressBar
, но этот индикатор выполнения на самом деле новый один, и это ребенок window
(который вы никогда не показываете).
Функция updateProgressBar затем успешно изменит значение индикатора выполнения, но не того, который вы видите.
Наконец, есть и другой способ использования файлов пользовательского интерфейса, и это через модуль uic
, который может напрямую загружать файлы пользовательского интерфейса.
from PyQt5 import QtWidgets, uic
class MyTest(QtWidgets.QWidget):
def __init__(self, parent=None)
super().__init__(parent)
<b>uic.loadUi('mywindow.ui', self)</b>
Этот подход является большим преимуществом с другой стороны: вам больше не нужно создавать файлы с pyui c, и он ведет себя точно так же, как метод множественного наследования, поэтому вы можете использовать self.progressBar
, как и раньше.