【问题标题】:Qt5 application not terminating on QMainWindow.close() after opening QFileDialog打开 QFileDialog 后 Qt5 应用程序未在 QMainWindow.close() 上终止
【发布时间】:2021-11-17 12:19:18
【问题描述】:

我有一个不是很复杂但也不是微不足道的 Qt5 python 应用程序(完整的东西在这里:https://gitlab.com/rulrich/pydatagrab请参阅下面的最小示例

我的问题如下:

我有一个 QMainWindow,在构造函数中我做了很多事情,而且:

        self.exitAct = QAction("Exit", self, shortcut="Ctrl+Q", triggered=self.close)
        ...
        self.fileMenu = QMenu("File", self)
        self.fileMenu.addAction(self.exitAct)

另外,我在构造函数中调用了一个文件对话框

          options = QFileDialog.Options()
          fileName, _ = QFileDialog.getOpenFileName(self, 'QFileDialog.getOpenFileName()', '',
                                                    'Images (*.png *.jpeg *.jpg *.bmp *.gif *.yaml)',
                                                    options=options)

当我按下 Ctrl+Q 或单击 File->Exit 时,同样的事情发生了:GUI 消失了,没有错误。但是该过程保持活动状态并且不会终止。在 Linux 上,当我在 shell 中启动它时,用 Ctrl+C (SIGINT) 终止进程甚至不起作用(很奇怪),我必须用 kill (SIGTERM) 终止它。

我的应用程序中没有任何特殊的“关闭”方法或功能。这直接是QMainWindow.close()

最初,我 100% 不清楚从哪里开始寻找问题。然而,在这个问题和回复的帮助下,我发现是 QFileDialog 本身导致了这种行为。如果我把它拿出来,应用程序就会正常运行。

最小重现代码在这里:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys, os

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

class MainWindow(QMainWindow):

     def __init__(self, fileName=None):
         
          super().__init__()

          self.exitAct = QAction("Exit", self, shortcut="Ctrl+Q", triggered=self.close)
          self.fileMenu = QMenu("File", self)
          self.fileMenu.addAction(self.exitAct)
          self.menuBar().addMenu(self.fileMenu)

          self.openFile()

    
     def openFile(self):
          options = QFileDialog.Options()
          fileName, _ = QFileDialog.getOpenFileName(self, 'QFileDialog.getOpenFileName()', '',
                                                    'Images (*.png *.jpeg *.jpg *.bmp *.gif *.yaml)',
                                                    options=options)
          # load some data ...
          # ...
                        

        
if __name__ == '__main__':
     app = QApplication(sys.argv)
     window = MainWindow()
     window.show()
     sys.exit(app.exec_())

==================================

print(app.allWidgets()) 的输出(修复问题后):

[<PyQt5.QtWidgets.QMenu object at 0x7fb8e6ae49d0>, <PyQt5.QtWidgets.QScrollBar object at 0x7fb8e6ae4b80>, <PyQt5.QtWidgets.QWidget object at 0x7fb8e6ae4c10>, <PyQt5.QtWidgets.QMenu object at 0x7fb8e6ae4ca0>, <PyQt5.QtWidgets.QWidget object at 0x7fb8e6ae4d30>, <PyQt5.QtWidgets.QPushButton object at 0x7fb8e6ae4160>, <PyQt5.QtWidgets.QScrollBar object at 0x7fb8e6ae4dc0>, <PyQt5.QtWidgets.QLineEdit object at 0x7fb8ee6ea790>, <PyQt5.QtWidgets.QMenu object at 0x7fb8e6ae4790>, <PyQt5.QtWidgets.QLineEdit object at 0x7fb8ee6eae50>, <PyQt5.QtWidgets.QFrame object at 0x7fb8e6ae4e50>, <PyQt5.QtWidgets.QScrollArea object at 0x7fb8ee6ea5e0>, <PyQt5.QtWidgets.QLabel object at 0x7fb8ee6ea670>, <PyQt5.QtWidgets.QLabel object at 0x7fb8e6ae40d0>, <PyQt5.QtWidgets.QToolButton object at 0x7fb8e6ae4ee0>, <PyQt5.QtWidgets.QWidget object at 0x7fb8e6ae4f70>, <PyQt5.QtWidgets.QLineEdit object at 0x7fb8ee6eac10>, <PyQt5.QtWidgets.QFrame object at 0x7fb8e6af5040>, <PyQt5.QtWidgets.QScrollBar object at 0x7fb8e6af50d0>, <PyQt5.QtWidgets.QWidget object at 0x7fb8e6af5160>, <PyQt5.QtWidgets.QLineEdit object at 0x7fb8ee6ea9d0>, <PyQt5.QtWidgets.QWidget object at 0x7fb8e6ae4af0>, <__main__.MainWindow object at 0x7fb8ee6ea160>, <PyQt5.QtWidgets.QLabel object at 0x7fb8e6ae4040>, <PyQt5.QtWidgets.QComboBox object at 0x7fb8ee6ea430>, <PyQt5.QtWidgets.QFrame object at 0x7fb8e6af51f0>, <PyQt5.QtWidgets.QListView object at 0x7fb8e6af5280>, <PyQt5.QtWidgets.QScrollBar object at 0x7fb8e6af5310>, <PyQt5.QtWidgets.QWidget object at 0x7fb8e6af53a0>, <__main__.DataArea object at 0x7fb8ee6ea550>, <PyQt5.QtWidgets.QScrollBar object at 0x7fb8e6af5430>, <PyQt5.QtWidgets.QWidget object at 0x7fb8e6af54c0>, <PyQt5.QtWidgets.QWidget object at 0x7fb8e6af5550>, <PyQt5.QtWidgets.QWidget object at 0x7fb8e6af55e0>, <PyQt5.QtWidgets.QScrollBar object at 0x7fb8e6af5670>, <PyQt5.QtWidgets.QMenuBar object at 0x7fb8e6ae4a60>, <PyQt5.QtWidgets.QLabel object at 0x7fb8ee6eadc0>, <PyQt5.QtWidgets.QWidget object at 0x7fb8e6af5700>, <PyQt5.QtWidgets.QFrame object at 0x7fb8e6af5790>, <PyQt5.QtWidgets.QListView object at 0x7fb8e6af5820>, <PyQt5.QtWidgets.QComboBox object at 0x7fb8ee6eab80>, <PyQt5.QtWidgets.QWidget object at 0x7fb8e6af58b0>, <PyQt5.QtWidgets.QListView object at 0x7fb8e6af5940>, <PyQt5.QtWidgets.QWidget object at 0x7fb8e6af59d0>, <PyQt5.QtWidgets.QLabel object at 0x7fb8ee6eaaf0>, <PyQt5.QtWidgets.QWidget object at 0x7fb8e6af5a60>, <PyQt5.QtWidgets.QComboBox object at 0x7fb8ee6ea4c0>, <PyQt5.QtWidgets.QScrollBar object at 0x7fb8e6af5af0>, <PyQt5.QtWidgets.QScrollBar object at 0x7fb8e6af5b80>, <PyQt5.QtWidgets.QWidget object at 0x7fb8e6af5c10>, <PyQt5.QtWidgets.QWidget object at 0x7fb8e6af5ca0>, <PyQt5.QtWidgets.QWidget object at 0x7fb8e6af5d30>, <PyQt5.QtWidgets.QLabel object at 0x7fb8ee6eaca0>, <PyQt5.QtWidgets.QWidget object at 0x7fb8e6af5dc0>, <PyQt5.QtWidgets.QLabel object at 0x7fb8ee6ea820>, <PyQt5.QtWidgets.QLabel object at 0x7fb8ee6ea940>, <PyQt5.QtWidgets.QScrollBar object at 0x7fb8e6af5e50>, <PyQt5.QtWidgets.QScrollBar object at 0x7fb8e6af5ee0>, <PyQt5.QtWidgets.QComboBox object at 0x7fb8ee6ea700>, <PyQt5.QtWidgets.QListView object at 0x7fb8e6af5f70>, <PyQt5.QtWidgets.QWidget object at 0x7fb8e6ae41f0>, <PyQt5.QtWidgets.QWidget object at 0x7fb8e6afc040>, <PyQt5.QtWidgets.QMenu object at 0x7fb8e6ae48b0>]

进一步简化的 MRE:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys, os

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

class MainWindow(QMainWindow):

     def __init__(self, fileName=None):         
          super().__init__()
          key = QShortcut(QKeySequence("Ctrl+Q"), self)
          key.activated.connect(self.close)
          self.openFile()

    
     def openFile(self):
          fileName, _ = QFileDialog.getOpenFileName(self, 'QFileDialog.getOpenFileName()', '',
                                                    'Images (*.png *.jpeg *.jpg *.bmp *.gif *.yaml)')#)
          #,options=QFileDialog.DontUseNativeDialog)
                        

        
if __name__ == '__main__':
     app = QApplication(sys.argv)
     window = MainWindow()
     window.show()
     sys.exit(app.exec_())

-> 行为没有变化。

【问题讨论】:

  • 请提供minimal reproducible example,也不要提供外部链接
  • 我希望解决方案如此简单,但我是如此愚蠢,以至于我添加的代码片段足以让专家解决问题。但我会看看我是否管理一个更小的例子......
  • 最少不是更少的代码,而是重现问题所需的代码。在您的情况下,3 行代码是不够的。请阅读How to Ask并通过tour
  • @RalfUlrich 关键是问题中提供的代码不足以理解问题,帖子应该始终是独立的,因为问题(及其答案)应该对整体有用社区和未来,不仅仅是那些问他们的人。您提供了一个存储库,并且在某些时候该代码可能会更改甚至变得不可用,这会使您的问题无效并且无法被将来可能面临类似问题的其他人理解。除此之外,恕我直言,您不能指望我们为您调试 1000 行代码。
  • 是的,我明白,我正在看这个(无论如何),但我的麻烦是:如果我只是缩小到一个最小的 Qt 示例:当然它可以工作......但是,我没有不知道从哪里开始寻找为什么它在我的代码中不起作用。我不想放整个代码(1000 行),因为很明显其中大部分是无关的......但让我(暂时)做,直到我设法找到缩小它的方法。

标签: python pyqt5 gtk qfiledialog


【解决方案1】:

看来这个问题可能与QTBUG-59184 有关,它会影响 Qt5 打开的原生 GTK 文件对话框。该错误仍未解决并且具有关键优先级,因此希望它会很快得到修复。同时,解决方法是使用内置的 Qt 文件对话框,可以通过options 指定,如下所示:

QFileDialog.getOpenFileName(parent, caption, options=QFileDialog.DontUseNativeDialog)

或者像这样:

dialog = QFileDialog(parent, caption)
dialog.setOption(QFileDialog.DontUseNativeDialog, True)

【讨论】:

    猜你喜欢
    • 2017-07-09
    • 2018-01-13
    • 1970-01-01
    • 2018-04-14
    • 2017-07-17
    • 1970-01-01
    • 1970-01-01
    • 2017-04-10
    • 1970-01-01
    相关资源
    最近更新 更多