简体   繁体   中英

PyQt5 QFileDialog stops application from closing

I am trying to write a PyQt5 application that does the following:

  • Creates and opens a Main Window. The MainWindow has a function that opens a QFileDialog window.
  • Function to open QFileDialog can be triggered in two ways (1) from a file menu option called 'Open' (2) automatically, after the Main window is shown.

My problem is that I haven't found a way to get the QfileDialog to automatically open (2) that doesn't cause the application to hang when the main window is closed. Basic example of code can be found below:

import sys
from PyQt5.QtWidgets import (QApplication, QMainWindow, QMenuBar, QWidget,
        QHBoxLayout, QCalendarWidget, QScrollArea, QFileDialog, QAction, QFrame)
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt

class MainWindow(QMainWindow):

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        self.openAction = QAction(QIcon('/usr/share/icons/breeze/places/64/folder-open.svg'), 'Open', self)
        self.openAction.triggered.connect(self.openDialog)

        self.menubar = QMenuBar(self)
        fileMenu = self.menubar.addMenu('&File')
        fileMenu.addAction(self.openAction)

        self.event_widgets = EventWidgets(self)
        self.setMenuBar(self.menubar)
        self.setCentralWidget(self.event_widgets)

    def openDialog(self):

        ics_path = QFileDialog.getOpenFileName(self, 'Open file', '/home/michael/')

class EventWidgets(QWidget):

    def __init__(self, parent):
        super(EventWidgets, self).__init__(parent)

        self.initUI()

    def initUI(self):
        self.calendar = QCalendarWidget(self)

        self.frame = QFrame()

        self.scrollArea = QScrollArea()
        self.scrollArea.setWidget(self.frame)

        horizontal_box = QHBoxLayout()
        horizontal_box.addWidget(self.calendar)
        horizontal_box.addWidget(self.scrollArea)

        self.setLayout(horizontal_box)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    app_window = MainWindow()
    app_window.showMaximized()
    app_window.openDialog()
    sys.exit(app.exec_())

Code has been tested on KDE Neon and Arch Linux, both have same issue.

I can get round this issue by handling the close event of the Main Window manually - ie adding this function to MainWindow:

def closeEvent(self, event):
        sys.exit()

But I am not sure a) why this is necessary b) if it is best practice.

I tried your code on macOS Sierra and it works as it's supposed to. However I would propose a different approach to solve your problem.

What you could do is to implement the showEvent() function in your MainWindow class, which is executed whenever a widget is displayed (either using .show() or .showMaximized() ) and trigger your custom slot to open the QFileDialog . When doing this you could make use of a single shot timer to trigger the slot with some minimal delay: the reason behind this is that if you simply open the dialog from within the showEvent() , you will see the dialog window but not the MainWindow below it (because the QFileDialog is blocking the UI until the user perform some action). The single shot timer adds some delay to the opening of the QFileDialog , and allows the MainWindow to be rendered behind the modal dialog. Here is a possible solution (not that I made some minor changes to your code, which you should be able to easily pick up):

import sys

from PyQt5 import QtCore
from PyQt5 import QtWidgets


class MainWindow(QtWidgets.QMainWindow):

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.openAction = QtWidgets.QAction('Open', self)
        self.openAction.triggered.connect(self.openDialog)
        menuBar = self.menuBar()
        fileMenu = menuBar.addMenu('&File')
        fileMenu.addAction(self.openAction)
        self.event_widgets = EventWidgets(self)
        self.setCentralWidget(self.event_widgets)

    def showEvent(self, showEvent):
        QtCore.QTimer.singleShot(50, self.openDialog)

    @QtCore.pyqtSlot()
    def openDialog(self):
        ics_path = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file', '/Users/daniele/')


class EventWidgets(QtWidgets.QWidget):

    def __init__(self, parent):
        super(EventWidgets, self).__init__(parent)
        self.calendar = QtWidgets.QCalendarWidget(self)
        self.frame = QtWidgets.QFrame()
        self.scrollArea = QtWidgets.QScrollArea()
        self.scrollArea.setWidget(self.frame)
        horizontal_box = QtWidgets.QHBoxLayout()
        horizontal_box.addWidget(self.calendar)
        horizontal_box.addWidget(self.scrollArea)
        self.setLayout(horizontal_box)


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    app_window = MainWindow()
    app_window.showMaximized()
    sys.exit(app.exec_())

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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