简体   繁体   English

退出/退出 PyQt 程序的正确方法

[英]Proper way to quit/exit a PyQt program

I have a script which has a login screen and if the cancel button is pressed, I want to exit the application altogether.我有一个脚本,它有一个登录屏幕,如果按下取消按钮,我想完全退出应用程序。 I have tried 3 ways:我尝试了 3 种方法:

  1. sys.exit()系统退出()
  2. QApplication.quit() QApplication.quit()
  3. QCoreApplication.instance().quit() QCoreApplication.instance().quit()

Only number 1 works.只有 1 号有效。 The other two makes the dialog box white and it flashes then hangs and I cannot even switch to other applications.另外两个使对话框变白,它闪烁然后挂起,我什至无法切换到其他应用程序。 My code is below:我的代码如下:

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtSql import *
from PyQt5.QtWidgets import *


import csv
import sys
from datetime import datetime, timedelta, time
import os

from ci_co_table import *
from login import *

class Ci_Co(QMainWindow):
    """Check in and check out module"""

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

class Login(QDialog):
    """User login """
    def __init__(self):
        QDialog.__init__(self)
        self.ui = Ui_login_form()
        self.ui.setupUi(self)
        self.ui.buttonBox.accepted.connect(lambda: self.handle_login(servers=servers))
        servers = {}
        with open('servers.csv', newline='') as csvfile:
            server_reader = csv.reader(csvfile)
            for row in server_reader:
                self.ui.cbo_db_name.addItem(row[1])
                servers[row[1]] = (row[0],row[2])

    def handle_login(self, servers=''):
        global user
        global pword
        global database
        global server
        global bg_colour
        user = self.ui.username.text()
        pword = self.ui.password.text()
        database = self.ui.cbo_db_name.currentText()
        server = servers[database][0]
        bg_colour = servers[database][1]


if __name__=="__main__":
    app=QApplication(sys.argv)
    global hotdate
    global hotdate_string
    global folio_num
    global user
    global pword
    global dbase
    global server
    pword = ""
    global database
    global bg_colour
    #Login
    while True:
        if Login().exec_() == QDialog.Accepted:
            db = QSqlDatabase.addDatabase("QPSQL");
            db.setHostName(server)
            db.setDatabaseName(database);
            db.setUserName(user);
            db.setPassword(pword)
            if (db.open()==False):     
                QMessageBox.critical(None, "Database Error", db.lastError().text())
            else:
                break
        else:
            #QApplication.quit()
            QCoreApplication.instance().quit()            
            #sys.exit()


    myapp = Ci_Co()
    myapp.show()
    sys.exit(app.exec_())

Calling QCoreApplication.quit() is the same as calling QCoreApplication.exit(0) .调用QCoreApplication.quit()与调用QCoreApplication.exit(0) To quote from the qt docs :引用qt 文档

After this function has been called, the application leaves the main event loop and returns from the call to exec().调用此函数后,应用程序离开主事件循环并从对 exec() 的调用返回。 The exec() function returns returnCode . exec() 函数返回returnCode If the event loop is not running, this function does nothing .如果事件循环没有运行,这个函数什么都不做 [emphasis added] [强调]

So quit() or exit() are nothing like sys.exit() .所以quit()exit()sys.exit() The latter will terminate the program, but the former will merely terminate the event-loop (if it's running).后者将终止程序,但前者只会终止事件循环(如果它正在运行)。

When the user cancels the login dialog, your example should just call sys.exit() to terminate the program.当用户取消登录对话框时,您的示例应该只调用sys.exit()来终止程序。 Otherwise, your program will just get stuck in the blocking while-loop.否则,您的程序将卡在阻塞的 while 循环中。

Instead of using QApplication.quit() , since you defined app = QApplication(sys.argv) , you could just write app.quit() , and that should work!而不是使用QApplication.quit() ,因为你定义了app = QApplication(sys.argv) ,你可以只写app.quit() ,这应该可行!

Something unrelated but might be helpful: I think it would be easier if you put the login check at the beginning of the __init__ function of your Ci_Co class.一些无关但可能有用的东西:我认为如果您将登录检查放在Ci_Co类的__init__函数的开头会更容易。 That way, you will start Ci_Co at the beginning, but it will first spawn the Login class.这样,您将在开始时启动Ci_Co ,但它会首先生成Login类。 If the login fails, you can call app.quit() , and if it succeeds, it will automatically transition into Ci_Co .如果登录失败,您可以调用app.quit() ,如果成功,它会自动过渡到Ci_Co This saves you from a lot of the things you have to write in the if __name__ == "__main__" clause.这使您免于在if __name__ == "__main__"子句中编写许多内容。 Please comment if you have any more questions, I have a similar project with a login dialog box.如果您还有任何问题,请发表评论,我有一个带有登录对话框的类似项目。

sys.exit(app.exec_())添加到您的代码中

i try this 3 method to close my MainWindow() but it didn't work for my code.我尝试这 3 种方法来关闭我的MainWindow()但它对我的代码不起作用。

  1. sys.exit()系统退出()
  2. QApplication.quit() QApplication.quit()
  3. qApp.quite() qApp.quite()

So i use self.close() method which work Completely fine with my code.所以我使用self.close()方法,它与我的代码完全一致。

here is my code这是我的代码

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
    
        self.ui.QPushButton.clicked.connect(lambda: self.shutprocess())
    
    def shutprocess(self):
        reply = QMessageBox.question(self, 'Window Close', 'Are you sure you want to close the window?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

        if reply == QMessageBox.Yes:
                self.close()
            print('Window closed')
        else:
            pass

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM