PyQt5 QFileDialog停止应用程序关闭

时间:2016-12-23 11:18:32

标签: python python-3.x pyqt pyqt5

我正在尝试编写一个执行以下操作的PyQt5应用程序:

  • 创建并打开主窗口。 MainWindow有一个打开QFileDialog窗口的函数。
  • 在显示主窗口后,可以通过两种方式(1)从名为“打开”(2)的文件菜单选项中自动触发打开QFileDialog的功能。

我的问题是我没有找到一种方法让QfileDialog自动打开(2),当主窗口关闭时不会导致应用程序挂起。代码的基本示例可以在下面找到:

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_())

代码已经在KDE Neon和Arch Linux上测试过,两者都有同样的问题。

我可以通过手动处理主窗口的关闭事件来解决这个问题 - 即将此功能添加到MainWindow:

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

但我不确定a)为什么这是必要的b)如果这是最佳实践。

1 个答案:

答案 0 :(得分:1)

我在macOS Sierra上尝试了你的代码,它可以正常工作。不过,我会提出一种不同的方法来解决你的问题。

您可以做的是在showEvent()类中实现MainWindow函数,该函数在窗口小部件显示时执行(使用.show().showMaximized())和触发您的自定义广告位以打开QFileDialog。执行此操作时,您可以使用单次计时器以最小延迟触发插槽:这背后的原因是,如果您只是在showEvent()内打开对话框,您将看到对话框窗口但不是它下方的MainWindow(因为QFileDialog阻止了UI,直到用户执行某些操作)。单发计时器为QFileDialog的开启添加了一些延迟,并允许MainWindow在模态对话框后面呈现。这是一个可能的解决方案(不是我对您的代码进行了一些小的更改,您应该能够轻松获取):

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_())