PyQt5 открывает второе окно из основного - PullRequest
0 голосов
/ 09 апреля 2020

Привет, я новичок в python (до лекции 3 и MIT 6001 Введение в информатику и программирование

в Python) Тем не менее я начал играть с PyQt5 и Designer (Python3, PyQt5, на linux).

Я читал, немного о PyQt5, но не очень разбираюсь в объектно-ориентированном программировании, и документация на Qt

похожа на меня тоже на Клингона. Не могу понять, почему этот скрипт test.py не может открыть второе окно

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

, когда Я пу sh Кнопка выхода? Любая помощь ? И любой простой ресурс, где можно найти логи c

различных классов Qt и приложение l oop для таких необразованных людей, как я.

test.py

!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Apr  8 14:25:12 2020

@author: Pietro
"""

import sys

from PyQt5 import QtWidgets, uic

from PyQt5.QtWidgets import QDesktopWidget


def main():

    class quitto(QtWidgets.QMainWindow):

        def __init__(self):

            super(quitto, self).__init__()

            uic.loadUi('exitmain.ui', self)

            self.center()

            self.show()

            print('inside quitting2 ' *5)

        def center(self):

            qr = self.frameGeometry()

            cp = QDesktopWidget().availableGeometry().center()

            qr.moveCenter(cp)

            self.move(qr.topLeft())



    class menu(QtWidgets.QMainWindow):


        def __init__(self):

            super(menu, self).__init__()

            uic.loadUi('main.ui', self)


            self.ButtonQ.clicked.connect(self.QPushButtonQPressed) 

            self.center()

            self.show() 

        def center(self):

            qr = self.frameGeometry()

            cp = QDesktopWidget().availableGeometry().center()

            qr.moveCenter(cp)

            self.move(qr.topLeft())     


        def QPushButtonQPressed(self):

            #This is executed when the button is pressed

            print('buttonB pressed' *5)

            pippo=quitto()

            pippo.show()




    app = QtWidgets.QApplication(sys.argv)


    window=menu()

    app.exec_()


if __name__ == '__main__':

и main.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="windowModality">
   <enum>Qt::WindowModal</enum>
  </property>
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>520</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <property name="windowIcon">
   <iconset resource="resource001.qrc">
    <normaloff>:/main/python.png</normaloff>
    <normalon>:/main/python.png</normalon>
    <disabledoff>:/main/python.png</disabledoff>
    <disabledon>:/main/python.png</disabledon>
    <activeoff>:/main/python.png</activeoff>
    <activeon>:/main/python.png</activeon>
    <selectedoff>:/main/python.png</selectedoff>
    <selectedon>:/main/python.png</selectedon>:/main/python.png</iconset>
  </property>
  <property name="styleSheet">
   <string notr="true">QPushButton{
    background-color: #9de650;
}


QPushButton:hover{
    background-color: green;
}

QPushButton#ButtonQ{
    background-color: orange;
}


QPushButton#ButtonQ:hover{
    background-color: red;
}</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QLabel" name="label">
    <property name="geometry">
     <rect>
      <x>20</x>
      <y>0</y>
      <width>471</width>
      <height>71</height>
     </rect>
    </property>
    <property name="font">
     <font>
      <pointsize>16</pointsize>
      <weight>75</weight>
      <bold>true</bold>
      <underline>true</underline>
     </font>
    </property>
    <property name="text">
     <string>House-Buying-Menu</string>
    </property>
    <property name="alignment">
     <set>Qt::AlignCenter</set>
    </property>
   </widget>
   <widget class="QPushButton" name="ButtonA">
    <property name="geometry">
     <rect>
      <x>170</x>
      <y>100</y>
      <width>151</width>
      <height>81</height>
     </rect>
    </property>
    <property name="font">
     <font>
      <pointsize>20</pointsize>
      <weight>75</weight>
      <bold>true</bold>
     </font>
    </property>
    <property name="text">
     <string>A</string>
    </property>
   </widget>
   <widget class="QPushButton" name="ButtonB">
    <property name="geometry">
     <rect>
      <x>170</x>
      <y>210</y>
      <width>151</width>
      <height>81</height>
     </rect>
    </property>
    <property name="font">
     <font>
      <pointsize>20</pointsize>
      <weight>75</weight>
      <bold>true</bold>
     </font>
    </property>
    <property name="text">
     <string>B</string>
    </property>
   </widget>
   <widget class="QPushButton" name="ButtonC">
    <property name="geometry">
     <rect>
      <x>170</x>
      <y>320</y>
      <width>151</width>
      <height>81</height>
     </rect>
    </property>
    <property name="font">
     <font>
      <pointsize>20</pointsize>
      <weight>75</weight>
      <bold>true</bold>
     </font>
    </property>
    <property name="text">
     <string>C</string>
    </property>
   </widget>
   <widget class="QPushButton" name="ButtonQ">
    <property name="geometry">
     <rect>
      <x>170</x>
      <y>450</y>
      <width>151</width>
      <height>81</height>
     </rect>
    </property>
    <property name="font">
     <font>
      <pointsize>20</pointsize>
      <weight>75</weight>
      <bold>true</bold>
     </font>
    </property>
    <property name="text">
     <string>QUIT</string>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>520</width>
     <height>29</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources>
  <include location="resource001.qrc"/>
 </resources>
 <connections/>
</ui>

и mainexit.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>631</width>
    <height>496</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QDialogButtonBox" name="buttonBox">
    <property name="geometry">
     <rect>
      <x>200</x>
      <y>310</y>
      <width>174</width>
      <height>33</height>
     </rect>
    </property>
    <property name="standardButtons">
     <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>631</width>
     <height>29</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

Ответы [ 2 ]

0 голосов
/ 10 апреля 2020

@ musicamante спасибо за ваш длинный и подробный пост (я проголосовал за него, но это не считается) Я продолжал пытаться заставить мой скрипт работать, и в итоге я набрал:

test2.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Apr  8 14:25:12 2020

@author: Pietro
"""

import sys
from PyQt5 import QtWidgets, uic
#import resource


def main():

    class Quitto(QtWidgets.QDialog):

        def quitbuttonboxquit(self):
            print('system exit')
            app.quit()            

        def quitbuttonboxnonquit(self):
            print('return to main')
            window.show()
            self.close()    

        def __init__(self):
            super(Quitto, self).__init__()
            uic.loadUi('exitdialog2.ui', self)
            self.center()
            self.show()
            print('inside quitting2 ' *5)
            self.QuitbuttonBox.accepted.connect(self.quitbuttonboxquit)
            self.QuitbuttonBox.rejected.connect(self.quitbuttonboxnonquit)

        def center(self):
            qr = self.frameGeometry()
            cp = QtWidgets.QDesktopWidget().availableGeometry().center()
            qr.moveCenter(cp)
            self.move(qr.topLeft())

        def closeEvent(self, event): 
                event.ignore()

    class Menu(QtWidgets.QMainWindow):

        def __init__(self): 
            super(Menu, self).__init__()
            uic.loadUi('main.ui', self)
            self.ButtonQ.clicked.connect(self.qpushbuttonqpressed) 
            self.center()
            self.show() 

        def center(self):
            qr = self.frameGeometry()
            cp = QtWidgets.QDesktopWidget().availableGeometry().center()
            qr.moveCenter(cp)
            self.move(qr.topLeft())   


        def qpushbuttonqpressed(self): #This is executed when the button is pressed
            print('buttonB pressed' *5)
            window.hide()
            pippo=Quitto()
            pippo.exec_()


        def closeEvent(self, event): #Your desired functionality here 
                event.ignore()




    app = QtWidgets.QApplication(sys.argv)

    sshFile="coffee.qss"
    with open(sshFile,"r") as fh:
        app.setStyleSheet(fh.read())
    window=Menu()
    app.exec_()

if __name__ == '__main__':
    main()


и exitdialog.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Dialog</class>
 <widget class="QDialog" name="Dialog">
  <property name="windowModality">
   <enum>Qt::WindowModal</enum>
  </property>
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>586</width>
    <height>522</height>
   </rect>
  </property>
  <property name="font">
   <font>
    <italic>true</italic>
   </font>
  </property>
  <property name="windowTitle">
   <string>Dialog</string>
  </property>
  <property name="styleSheet">
   <string notr="true"/>
  </property>
  <widget class="QDialogButtonBox" name="QuitbuttonBox">
   <property name="geometry">
    <rect>
     <x>40</x>
     <y>460</y>
     <width>341</width>
     <height>32</height>
    </rect>
   </property>
   <property name="font">
    <font>
     <pointsize>18</pointsize>
     <weight>75</weight>
     <bold>true</bold>
    </font>
   </property>
   <property name="styleSheet">
    <string notr="true">QPushButton{                 
    background-color: #17eb3e;
}



QPushButton:hover{                 
    background-color: red;
}


</string>
   </property>
   <property name="orientation">
    <enum>Qt::Horizontal</enum>
   </property>
   <property name="standardButtons">
    <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
   </property>
  </widget>
  <widget class="QLabel" name="label">
   <property name="geometry">
    <rect>
     <x>50</x>
     <y>30</y>
     <width>491</width>
     <height>341</height>
    </rect>
   </property>
   <property name="styleSheet">
    <string notr="true">image: url(:/main/alert.png);</string>
   </property>
   <property name="text">
    <string/>
   </property>
  </widget>
  <widget class="QLabel" name="label_2">
   <property name="geometry">
    <rect>
     <x>170</x>
     <y>400</y>
     <width>271</width>
     <height>41</height>
    </rect>
   </property>
   <property name="font">
    <font>
     <pointsize>18</pointsize>
     <weight>75</weight>
     <italic>false</italic>
     <bold>true</bold>
    </font>
   </property>
   <property name="styleSheet">
    <string notr="true">QLabel { 
    color : red
 }</string>
   </property>
   <property name="text">
    <string>Are you sure to Quit ?!?</string>
   </property>
  </widget>
 </widget>
 <resources>
  <include location="resource001.qrc"/>
 </resources>
 <connections>
  <connection>
   <sender>QuitbuttonBox</sender>
   <signal>accepted()</signal>
   <receiver>Dialog</receiver>
   <slot>accept()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>248</x>
     <y>254</y>
    </hint>
    <hint type="destinationlabel">
     <x>157</x>
     <y>274</y>
    </hint>
   </hints>
  </connection>
  <connection>
   <sender>QuitbuttonBox</sender>
   <signal>rejected()</signal>
   <receiver>Dialog</receiver>
   <slot>reject()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>316</x>
     <y>260</y>
    </hint>
    <hint type="destinationlabel">
     <x>286</x>
     <y>274</y>
    </hint>
   </hints>
  </connection>
 </connections>
</ui>

Я постараюсь Функция разделения и классы позже (сначала мне нужно больше узнать о классах) тем не менее я изменил класс Quitto на:

class Quitto(QtWidgets.QDialog)

и изменил:

        def qpushbuttonqpressed(self): #This is executed when the button is pressed
            print('buttonB pressed' *5)
            window.hide()
            pippo=Quitto()
            pippo.exec_() 

в предыдущий сценарий с использованием:

- window.hide () закрывал все вниз после краткого показа двух windows

при использовании

- pippo.exe c () вместо pippo.show () показывал новое 2-е окно поверх другого

, и после закрытия я получал:

AttributeError: 'quitto' object has no attribute 'exec_'

Использование pippo.show () во втором скрипте также не работало, но pippo.exe_ () выполнило трюк

. Как это может обойти сборку мусора ???

И почему при изменении класса Quitto () на QtWidgets.QMainWindow я получаю ошибку атрибута?

0 голосов
/ 09 апреля 2020

Причина такого поведения заключается в том, что создаваемый вами экземпляр quitto является "сборщиком мусора". Как и многие языки более высокого уровня, Python имеет систему, которая автоматически управляет памятью и отвечает за освобождение памяти от объектов, которые «решают», больше не нужны.

Любая локальная переменная, созданная в функции всегда удаляется, как только функция возвращается, если только она не ссылается на постоянный объект каким-либо образом.

Следующий пример объясняет это более простым способом: «my_variable» создается в function, но как как только он завершен (он возвращает) python удаляет эту переменную, и это хорошо, потому что если этого не произойдет, вы легко go нехватите памяти:

class DeletingObject(object):
    '''
    A basic class that prints a message whenever any of its instances
    is going to be deleted.
    '''
    def __del__(self):
        print('Goodbye cruel world...')

def function():
    my_variable = DeletingObject()
    print(my_variable)

>>> function()
<__main__.DeletingObject object at 0xb593a46c>
Goodbye cruel world...

То же самое происходит в вашем случае: вы создаете quitto, но для него нет постоянной ссылки, поэтому, как только функция, которая его создает, возвращается, она удаляется.

Самый распространенный способ избежать этого, когда вы создание объектов внутри класса, это сделать новый объект атрибут экземпляра :

    def QPushButtonQPressed(self):
        <b>self.pippo</b> = quitto()
        self.pippo.show()

Теперь новый объект больше не удаляется руда, и окно больше не будет разрушено.


Поскольку вы только начали изучать все это, я хотел бы поделиться некоторыми советами по поводу вашего примера:

  • классы не должны быть объявлены внутри функций; в некоторых случаях это можно сделать, но они очень специфичны c ситуаций, которые обычно не нужны для использования generic c (основная причина в том, что классы должны быть доступны из любого места, чтобы их экземпляры могли быть созданы в любое время , но это также потому, что определение класса в функции означает, что он всегда объявляется при каждом запуске функции, что не очень хорошо для производительности);
  • используют пустые строки в функциях только при разделении логических фрагментов вашего код, а не между каждой строкой;
  • Для большинства языков принято использовать заглавные имена для классов и строчные имена для функций, переменных и экземпляров. Подробнее об этом читайте в официальном руководстве по стилю для Python (он же PEP-8);
  • , хотя с технической точки зрения в этом нет ничего плохого, обычно лучше не смешивать способ импорта из модулей, особенно если имеется несколько уровней подмодулей (например, с PyQt): вы либо импортируете субмодуль как в первой строке (from PyQt5 import QtWidgets) или в отдельных классах, которые вы собираетесь использовать, как во втором импорте (from PyQt5.QtWidgets import QDesktopWidget); второй подход обычно подходит для простых случаев, но если ваш код сильно растет, вы можете оказаться с десятками классов, которые нужно импортировать вручную, и хотя вы можете сделать from PyQt5.QtWidgets import *, обычно лучше импортировать подмодули и получить доступ к классы оттуда:
from PyQt5 import QtWidgets
# ...
cp = QtWidgets.QDesktopWidget().availableGeometry().center()
  • QDesktopWidget устарел, вместо него используйте QScreen ;
...