【问题标题】:PyQt5 opening second window from mainPyQt5 从主窗口打开第二个窗口
【发布时间】:2020-04-09 14:45:37
【问题描述】:

您好,我是 python 新手(直到第 3 课和 MIT 6001 计算机科学和编程导论)

在 Python 中)尽管如此,我还是开始使用 PyQt5 和 Designer(Linux 上的 Python3、PyQt5)。

我读过,对 PyQt5 有一点了解,但对面向对象编程和 Qt 不太了解

文档对我来说就像克林贡语一样。想不通为什么这个脚本 test.py 打不开第二个

窗口,实际上它确实打开了它,我可以在第一个窗口前看到它在 desolve 前短暂显示

当我按下退出按钮时?有什么帮助吗?以及任何可以找到

逻辑的简单资源

对于像我这样没有受过教育的人来说,不同类别的 Qt 和应用程序循环。

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>

【问题讨论】:

    标签: python-3.x pyqt5 designer


    【解决方案1】:

    这种行为的原因是您正在创建的quitto 实例是“垃圾收集”。像许多高级语言一样,Python 有一个自动管理内存的系统,并负责释放它“决定”不再有用的对象的内存。

    函数内创建的任何局部变量总是在函数返回后立即删除,除非它以某种方式引用到持久对象。

    以下示例以更简单的方式解释它:“my_variable”是在function 中创建的,但一旦完成(它返回)python 就会删除该变量,这很好,因为如果它不会你会很容易耗尽内存:

    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):
            self.pippo = quitto()
            self.pippo.show()
    

    现在新对象不再被删除,窗口也不再被销毁。


    由于您刚刚开始研究这一切,我想就您的示例分享一些建议:

    • 类不应在函数中声明;在某些情况下可以这样做,但它们是非常特殊的情况,通常不需要泛型使用(主要原因是类应该可以从任何地方访问,以便可以随时创建它们的实例,但这也是因为定义函数中的类意味着每次运行函数时总是声明它,这对性能不是很好);
    • 仅在分隔代码的逻辑片段时才在函数中使用空行,而不是在每一行之间;
    • 大多数语言的通用约定是对类使用大写名称,对函数、变量和实例使用小写名称,请参阅官方 style guide for 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

    【讨论】:

    • 很好解释,但我确实有一个问题。如果我们使用exec_(),我们不需要将新对象设为实例(通过使用self),为什么会这样?
    【解决方案2】:

    @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() 在短暂显示两个窗口后关闭一切

    使用时

    -- pippo.exec() 而不是 pippo.show() 在

    顶部显示新的第二个窗口

    其他,关闭它们后我得到了一个:

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

    在第二个脚本中使用 pippo.show() 也不起作用,但 pippo.exe_() 做到了

    诡计。怎么绕过垃圾回收???

    为什么将类 Quitto() 更改为 QtWidgets.QMainWindow 我得到属性错误?

    【讨论】:

    • @musicamante,理解您的类示例需要一段时间,尝试 print(dir(DeletingObject)) 并使用 init 而不是 del 有所帮助我了解更多关于类的信息
    【解决方案3】:

    在我的项目中,我使用它从主窗口打开另一个窗口。我粘贴了具有额外中心功能的全功能脚本,将主窗口放在屏幕中间。在 Designer 中创建两个文件,“UIMain.ui”(主窗口)和第二个窗口“notes.ui”并保存。

    # Open Second Window/Dialog/Form from Main Window
    
    from PyQt5 import uic
    from PyQt5.QtWidgets import (
                                QMainWindow,
                                QApplication,
                                QDesktopWidget
                                )
    
    form_2, base_2 = uic.loadUiType('notes.ui')
    
    
    class MainNotes(base_2, form_2):
        def __init__(self, parent=None):
            super(base_2, self).__init__(parent)
            self.setupUi(self)
    
    
    class MainApp(QMainWindow):
        """ Main Class
        """
        def __init__(self):
            super(MainApp, self).__init__()
            self.mainnotes = MainNotes()
            self.ui = uic.loadUi('UIMain.ui', self)
    
            self.initapp()
    
        def initapp(self):
            self.ui.bt_notes.clicked.connect(self.notes)
    
        def notes(self):
            """
            Put your code here
            """
            self.mainnotes.show()
    
        def center(self):
            qr = self.frameGeometry()
            cp = QDesktopWidget().availableGeometry().center()
            qr.moveCenter(cp)
            self.move(qr.topLeft())
    
    
    def main():
        import sys
        try:
            myapp = QApplication([])
            mywindow = MainApp()
            mywindow.center()
            mywindow.show()
            myapp.exec_()
        except SystemExit:
            sys.exit(0)
    
    
    if __name__ == '__main__':
        main()
    

    【讨论】:

      猜你喜欢
      • 2017-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-21
      相关资源
      最近更新 更多