Уведомления

Группа в Telegram: @pythonsu

#1 Сен. 12, 2017 16:25:04

gmaksim
От: Россия
Зарегистрирован: 2017-07-17
Сообщения: 42
Репутация: +  0  -
Профиль   Отправить e-mail  

PyQt5 Вызов классов из метода

PEHDOM
У меня вообще ни одно окно не создаеться из вашего примера.
Там совсем “вытащил из контекста”, вряд ли это запуститься в таком виде.
PEHDOM
сборщик мусора удаляет обьект-окно из памяти.
Это и было первой мыслью, так как класс two - режим просмотра, как обойти это так и не догадался (возможно “костыль” в виде скрытого QLineEdit на форме?).

Офлайн

#2 Сен. 12, 2017 17:32:31

PEHDOM
Зарегистрирован: 2016-11-28
Сообщения: 2196
Репутация: +  294  -
Профиль   Отправить e-mail  

PyQt5 Вызов классов из метода

gmaksim
(возможно “костыль” в виде скрытого QLineEdit на форме?).
Зачем такие сложности?
У вас все классы это QWidget, Если в кратце то КуВиджет становиться окном только если не указан родительский виджет иначе он вписываеться в родителя. У вас есть несколько вариантов: Передавать родителя и использовать например QDialog или QMainWindow для дочерних окон. например так:
 from PyQt4.QtGui import \
    (QWidget, QPushButton, QApplication, QLabel, QComboBox, QLineEdit, QGridLayout, QMessageBox, QListWidget, QMainWindow, QDialog)
from PyQt4.QtCore import Qt
import sys
class one(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        # ...
        self.start()
    def start(self):
        self.layout = QGridLayout()
        self.setWindowTitle('One')
        self.setLayout(self.layout)
        self.setGeometry(20, 20, 100, 100)
        # ...
        self.show()
class two(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        # ...
        self.start()
    def start(self):
        self.layout = QGridLayout()
        self.setWindowTitle('Two')
        self.setLayout(self.layout)
        self.setGeometry(20, 20, 100, 100)
        # ...
        self.show()
def main():
    app = QApplication(sys.argv)
    def start1(parent):
        s1 = one(parent)
    def start2(parent):
        s2 = two(parent)
    root = QWidget()
    root.layout = QGridLayout()
    root.setLayout(root.layout)
    root.setGeometry(100, 100, 600, 500)
    # ...
    root.butt = QPushButton(text='start 1')
    root.butt.clicked.connect(lambda: start1(root))
    root.layout.addWidget(root.butt, 1, 1)
    root.butt = QPushButton(text='start 2')
    root.butt.clicked.connect(lambda: start2(root))
    root.layout.addWidget(root.butt, 2, 1)
    root.show()
    sys.exit(app.exec_())
if __name__ == "__main__":
    main()
или таки гдето хранить ссылку на обьект… пример
 from PyQt4.QtGui import \
    (QWidget, QPushButton, QApplication, QLabel, QComboBox, QLineEdit, QGridLayout, QMessageBox, QListWidget)
from PyQt4.QtCore import Qt
import sys
class one(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        # ...
        self.start()
    def start(self):
        self.layout = QGridLayout()
        self.setWindowTitle('One')
        self.setLayout(self.layout)
        self.setGeometry(20, 20, 100, 100)
        # ...
        self.show()
class two(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        # ...
        self.start()
    def start(self):
        self.layout = QGridLayout()
        self.setWindowTitle('Two')
        self.setLayout(self.layout)
        self.setGeometry(20, 20, 100, 100)
        # ...
        self.show()
def main():
    app = QApplication(sys.argv)
    def start1():
        root.s1 = one()
    def start2():
        root.s2 = two()
    root = QWidget()
    root.layout = QGridLayout()
    root.setLayout(root.layout)
    root.setGeometry(100, 100, 600, 500)
    # ...
    root.butt = QPushButton(text='start 1')
    root.butt.clicked.connect(start1)
    root.layout.addWidget(root.butt, 1, 1)
    root.butt = QPushButton(text='start 2')
    root.butt.clicked.connect(start2)
    root.layout.addWidget(root.butt, 2, 1)
    root.show()
    sys.exit(app.exec_())
if __name__ == "__main__":
    main()
Можно даже держать ссылку на обьект внутри самого обьекта, тогда обьект будет держать сам себя. Като так:
 from PyQt4.QtGui import \
    (QWidget, QPushButton, QApplication, QLabel, QComboBox, QLineEdit, QGridLayout, QMessageBox, QListWidget)
from PyQt4.QtCore import Qt
import sys
class one(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        # ...
        self.w = self # Держим ссылку на самих себя чтобы окно не закрылось
        self.start()
    def start(self):
        self.layout = QGridLayout()
        self.setWindowTitle('One')
        self.setLayout(self.layout)
        self.setGeometry(20, 20, 100, 100)
        # ...
        self.show()
    def closeEvent(self, event):
        self.w = None # На всякий случай при закрытии удаляем ссылку, чтобы избежать утечек.
        event.accept()
class two(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        # ...
        self.start()
    def start(self):
        self.layout = QGridLayout()
        self.setWindowTitle('Two')
        self.setLayout(self.layout)
        self.setGeometry(20, 20, 100, 100)
        # ...
        self.show()
def main():
    app = QApplication(sys.argv)
    def start1():
        s1 = one()
    def start2():
        s2 = two()
    root = QWidget()
    root.layout = QGridLayout()
    root.setLayout(root.layout)
    root.setGeometry(100, 100, 600, 500)
    # ...
    root.butt = QPushButton(text='start 1')
    root.butt.clicked.connect(start1)
    root.layout.addWidget(root.butt, 1, 1)
    root.butt = QPushButton(text='start 2')
    root.butt.clicked.connect(start2)
    root.layout.addWidget(root.butt, 2, 1)
    root.show()
    sys.exit(app.exec_())
if __name__ == "__main__":
    main()
Класс one сам себя “держит в памяти”, а класс two - нет
но тут нужно быть крайне осторожным, так как это может привести к “утечке памяти” когда окно не нужно и закрыто, а оно все еще занимает память.



==============================
Помещайте код в теги:
[code python][/code]
Бериегите свое и чужое время.

Отредактировано PEHDOM (Сен. 12, 2017 17:33:19)

Офлайн

#3 Сен. 13, 2017 16:09:04

gmaksim
От: Россия
Зарегистрирован: 2017-07-17
Сообщения: 42
Репутация: +  0  -
Профиль   Отправить e-mail  

PyQt5 Вызов классов из метода

Первый способ подошел отлично, спасибо!
Единственное хотел уточнить, в реализации первого варианта, как можно сделать возврат к исходному окну (main) - если вызвать метод по нажатию кнопки внутри класса выполняющий main снова, приложение завершается и GUI не появляется (так как gc видимо уже все собрал?).
Сделать аналог “parent=” ?

Или в main включить некую проверку на наличие инициализированного QWidget и если он есть то как-то вызывать его из памяти (предварительно не допуская его выгрузку)?
Я так понимаю надо копать в сторону понимания использования “слотов” в Python.

Отредактировано gmaksim (Сен. 13, 2017 16:15:47)

Офлайн

#4 Сен. 13, 2017 16:24:51

PEHDOM
Зарегистрирован: 2016-11-28
Сообщения: 2196
Репутация: +  294  -
Профиль   Отправить e-mail  

PyQt5 Вызов классов из метода

gmaksim
Единственное хотел уточнить, в реализации первого варианта, как можно сделать возврат к исходному окну (main)
что значит возврат? У вас оно закрываеться при открытии второго окна?
gmaksim
если вызвать метод по нажатию кнопки внутри класса выполняющий main снова, приложение завершается и GUI не появляется (так как gc видимо уже все собрал?).
млин, три раза перечитал ничего не понял… можете пояснить что вы нажимаете и где? А лучше привести простой код котороый отбражает проблему, потому как лучше один раз увидеть чем сто раз услышать…
ЗЫ на вский случай простой код, :
 from PyQt4.QtGui import \
    (QWidget, QPushButton, QApplication, QLabel, QComboBox, QLineEdit, QGridLayout, QMessageBox, QListWidget, QMainWindow, QDialog)
from PyQt4.QtCore import Qt
import sys
class one(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        # ...
        self.start()
        parent.hide()
    def start(self):
        self.layout = QGridLayout()
        self.setWindowTitle('One')
        self.setLayout(self.layout)
        self.setGeometry(20, 20, 100, 100)
        # ...
        self.show()
    def closeEvent(self, event):
        self.parent().show()
        event.accept()
class two(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        # ...
        self.start()
    def start(self):
        self.layout = QGridLayout()
        self.setWindowTitle('Two')
        self.setLayout(self.layout)
        self.setGeometry(20, 20, 100, 100)
        # ...
        self.show()
def main():
    app = QApplication(sys.argv)
    def start1(parent):
        s1 = one(parent)
    def start2(parent):
        s2 = two(parent)
    root = QWidget()
    root.layout = QGridLayout()
    root.setLayout(root.layout)
    root.setGeometry(100, 100, 600, 500)
    # ...
    root.butt = QPushButton(text='start 1')
    root.butt.clicked.connect(lambda: start1(root))
    root.layout.addWidget(root.butt, 1, 1)
    root.butt = QPushButton(text='start 2')
    root.butt.clicked.connect(lambda: start2(root))
    root.layout.addWidget(root.butt, 2, 1)
    root.show()
    sys.exit(app.exec_())
if __name__ == "__main__":
    main()
ХЗ как у вас там все закручено, можно просто еще вынести окно что у вас в main() в отдельный класс.



==============================
Помещайте код в теги:
[code python][/code]
Бериегите свое и чужое время.

Отредактировано PEHDOM (Сен. 13, 2017 16:30:15)

Офлайн

#5 Сен. 13, 2017 19:12:41

vic57
Зарегистрирован: 2015-07-07
Сообщения: 913
Репутация: +  127  -
Профиль  

PyQt5 Вызов классов из метода

PEHDOM
три раза перечитал ничего не понял…
чет у меня тоже лыжи не едут
 from PyQt5.Qt import *
class A(QFrame):
	def __init__(self):
		super().__init__()
		self.setWindowTitle('A')
		self.resize(120,30)
		self.move(0,10)
		self.show()
class B(QFrame):
	def __init__(self):
		super().__init__()
		self.setWindowTitle('B')
		self.resize(120,30)
		self.move(0,100)
		self.show()
class W(QWidget):
	def __init__(self):
		super().__init__()
		self.btnA = QPushButton('btnA')
		self.btnA.clicked.connect(self.clickA) 
		self.btnB = QPushButton('btnB')
		self.btnB.clicked.connect(self.clickB)
		grid = QGridLayout(self)
		grid.addWidget(self.btnA)
		grid.addWidget(self.btnB)
	def clickA(self):
		self.a = A()
	def clickB(self):
		self.b = B()
if __name__ == "__main__":
	app = QApplication([])
	w = W()
	w.show()
	app.exec_()
в чем аффтар видит проблему?

Офлайн

#6 Сен. 14, 2017 10:27:08

gmaksim
От: Россия
Зарегистрирован: 2017-07-17
Сообщения: 42
Репутация: +  0  -
Профиль   Отправить e-mail  

PyQt5 Вызов классов из метода

Извиняюсь, если взять за пример код PEHDOM, то я имею ввиду следующее -

PEHDOM
  from PyQt4.QtGui import \
    (QWidget, QPushButton, QApplication, QLabel, QComboBox, QLineEdit, QGridLayout, QMessageBox, QListWidget, QMainWindow, QDialog)
from PyQt4.QtCore import Qt
import sys
class one(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        # ...
        self.start()
        parent.hide()
    def start(self):
        self.layout = QGridLayout()
        self.setWindowTitle('One')
        self.setLayout(self.layout)
        self.setGeometry(20, 20, 100, 100)
        # ...
        self.show()
    def closeEvent(self, event):
        self.parent().show()
        event.accept()
class two(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        # ...
        self.start()
    def start(self):
        self.layout = QGridLayout()
        self.setWindowTitle('Two')
        self.setLayout(self.layout)
        self.setGeometry(20, 20, 100, 100)
        # ...
        self.show()
def main():
    app = QApplication(sys.argv)
    def start1(parent):
        s1 = one(parent)
    def start2(parent):
        s2 = two(parent)
    root = QWidget()
    root.layout = QGridLayout()
    root.setLayout(root.layout)
    root.setGeometry(100, 100, 600, 500)
    # ...
    root.butt = QPushButton(text='start 1')
    root.butt.clicked.connect(lambda: start1(root))
    root.layout.addWidget(root.butt, 1, 1)
    root.butt = QPushButton(text='start 2')
    root.butt.clicked.connect(lambda: start2(root))
    root.layout.addWidget(root.butt, 2, 1)
    root.show()
    sys.exit(app.exec_())
if __name__ == "__main__":
    main()
В классе one размещена кнопка, которая (должна) возвращать нас обратно на стартовый экран (то что выводит класс main - две кнопки с выбором).
Т.е. запустился main, предлагает по нажатию кнопок свой функционал (на примере кода выше one и two), по завершению этого функционала идет возврат к “главному экрану” (метод main) где опять можем выбрать какое-то действие (классы one и two).
Надеюсь так понятнее.

Отредактировано gmaksim (Сен. 14, 2017 10:28:03)

Офлайн

#7 Сен. 14, 2017 10:30:56

gmaksim
От: Россия
Зарегистрирован: 2017-07-17
Сообщения: 42
Репутация: +  0  -
Профиль   Отправить e-mail  

PyQt5 Вызов классов из метода

Я реализовал схожим образом как тут:

PEHDOM
 from PyQt4.QtGui import \
    (QWidget, QPushButton, QApplication, QLabel, QComboBox, QLineEdit, QGridLayout, QMessageBox, QListWidget, QMainWindow, QDialog)
from PyQt4.QtCore import Qt
import sys
class one(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        # ...
        self.start()
    def start(self):
        self.layout = QGridLayout()
        self.setWindowTitle('One')
        self.setLayout(self.layout)
        self.setGeometry(20, 20, 100, 100)
        # ...
        self.show()
class two(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        # ...
        self.start()
    def start(self):
        self.layout = QGridLayout()
        self.setWindowTitle('Two')
        self.setLayout(self.layout)
        self.setGeometry(20, 20, 100, 100)
        # ...
        self.show()
def main():
    app = QApplication(sys.argv)
    def start1(parent):
        s1 = one(parent)
    def start2(parent):
        s2 = two(parent)
    root = QWidget()
    root.layout = QGridLayout()
    root.setLayout(root.layout)
    root.setGeometry(100, 100, 600, 500)
    # ...
    root.butt = QPushButton(text='start 1')
    root.butt.clicked.connect(lambda: start1(root))
    root.layout.addWidget(root.butt, 1, 1)
    root.butt = QPushButton(text='start 2')
    root.butt.clicked.connect(lambda: start2(root))
    root.layout.addWidget(root.butt, 2, 1)
    root.show()
    sys.exit(app.exec_())
if __name__ == "__main__":
    main()
но по завершению функционала класса, банальный вызов main не срабатывает, ничего не отображается.
Причем перед этим даже (перед стартом по нажатию кнопки класса) добавил “очистку” от виджетов:
      def clear():
         for i in reversed(range(root.layout.count())):
             root.layout.itemAt(i).widget().deleteLater()

Офлайн

#8 Сен. 14, 2017 11:51:14

vic57
Зарегистрирован: 2015-07-07
Сообщения: 913
Репутация: +  127  -
Профиль  

PyQt5 Вызов классов из метода

имхо вы много лишнего накрутили. наследуйтесь от QDialog

 from PyQt5.Qt import *
class A(QDialog):
	def __init__(self,parent=None):
		QDialog.__init__(self,parent)
		self.setWindowTitle('A')
		self.resize(120,30)
		self.move(0,10)
class B(QFrame):
	def __init__(self,parent=None):
		QFrame.__init__(self,parent)
		self.setWindowTitle('B')
		self.resize(120,30)
		self.move(0,100)
		self.show()
class W(QWidget):
	def __init__(self):
		super().__init__()
		self.btnA = QPushButton('btnA')
		self.btnA.clicked.connect(self.clickA) 
		self.btnB = QPushButton('btnB')
		self.btnB.clicked.connect(self.clickB)
		grid = QGridLayout(self)
		grid.addWidget(self.btnA)
		grid.addWidget(self.btnB)
	def clickA(self):
		self.hide()
		dlg = A()
		ret = dlg.exec_()
		print('ret',ret)
		self.show()
	def clickB(self):
		self.b  = B()
if __name__ == "__main__":
	app = QApplication([])
	w = W()
	w.show()
	app.exec_()

Отредактировано vic57 (Сен. 14, 2017 11:51:35)

Офлайн

#9 Сен. 14, 2017 12:33:39

PEHDOM
Зарегистрирован: 2016-11-28
Сообщения: 2196
Репутация: +  294  -
Профиль   Отправить e-mail  

PyQt5 Вызов классов из метода

gmaksim
В классе one размещена кнопка, которая (должна) возвращать нас обратно на стартовый экран (то что выводит класс main - две кнопки с выбором).
Т.е. запустился main, предлагает по нажатию кнопок свой функционал (на примере кода выше one и two), по завершению этого функционала идет возврат к “главному экрану” (метод main) где опять можем выбрать какое-то действие (классы one и two).
Надеюсь так понятнее.
Всеравно нихрена непонятно, что значит “идет возврат к главному экрану”, а где в это время главный экран? вы его закрываете или как? если не закрываете, то почему нельзя просто сдерать
 root.show() 
root.activateWindow()
Пятью постами выше я приводил пример в котором при нажатии на кнопку 1 главное окно скрываеться, и отображаеться дочернее, а при закрытии дочернего главное опять появляеться.
В любом случае налицо проблема с архитектурой. Вынесите “основное окно” в отдельный класс, как в примере vic57 и создавайте сколько хотите инстансов этого класса, из любого места.
Я уже не говорю про отделение “математики” от GUI, или MVC модель..
gmaksim
но по завершению функционала класса, банальный вызов main не срабатывает, ничего не отображается.
О_о. Это ересь и жесть, в вашем конкретном случае. Налицо непонимание как работает Qt вообще и пайтон в частности.
возьмем ваш main()
 def main():
    app = QApplication(sys.argv)
   ........
    sys.exit(app.exec_())
Вы думаете когда появляеться ваше главное, или вы вызвали дочернее окно то main() отработал? А вот нифига, пока вы играетесь окошками, app.exec_() продолжает работать и main() не завершиться пока app.exec_() не завершиться. Когда вы еще раз вызываете main() то опять создаеться инстанс QApplication, но на этапе app.exec_() вы получаете “индейскую народную избу - фигвам называеться”. Потому как не может быть двух главный циклов обработки сообщений в Qt. Соотвественно второй app.exec_() прекращает работу с какимто кодом ошибки или исключением, и отрабатывает sys.exit().
А что делает sys.exit() вы, наверно и без меня догадываетесь?



==============================
Помещайте код в теги:
[code python][/code]
Бериегите свое и чужое время.

Отредактировано PEHDOM (Сен. 14, 2017 12:35:34)

Офлайн

#10 Сен. 14, 2017 13:38:11

gmaksim
От: Россия
Зарегистрирован: 2017-07-17
Сообщения: 42
Репутация: +  0  -
Профиль   Отправить e-mail  

PyQt5 Вызов классов из метода

Разобрался, всем спасибо!

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version