QFileDialog not closing after file selection

Question:

I have a simple function that opens a file dialog using pyqt6 to select a file.
The function works, but the dialog hangs after being called and I’m not sure why it’s not getting automatically closed when the file is selected.

def ui_find_file(title=None, initialdir=None, file_type=None):
  import os
  from PyQt6.QtWidgets import QApplication, QFileDialog

  app = QApplication([])
  file_dialog = QFileDialog()
  file_dialog.setFileMode(QFileDialog.FileMode.ExistingFile)

  if file_type:
      filter = f"{file_type} files (*.{file_type})"
      file_dialog.setNameFilter(filter)
  else:
      file_dialog.setNameFilter("All files (*);;")

  if initialdir is None:
      initialdir = os.getcwd()
  elif initialdir == '~':
      initialdir = os.path.expanduser('~')

  file_dialog.setDirectory(initialdir)

  if title:
      file_dialog.setWindowTitle(title)

  if file_dialog.exec():
      file_path = file_dialog.selectedFiles()[0]
      print(f"Selected {file_path}")
      file_dialog.deleteLater()  # Clean up the file dialog window
      app.quit()  # Exit the event loop
      return file_path
  else:
      print("No file selected")
      file_dialog.deleteLater()  # Clean up the file dialog window
      app.quit()  # Exit the event loop
      return None

When I try the first lines in the command line

from PyQt6.QtWidgets import QApplication, QFileDialog

app = QApplication([])
file_dialog = QFileDialog()
file_dialog.setFileMode(QFileDialog.FileMode.ExistingFile)

and I use either file_dialog.open() or file_dialog.exec(), I can select a file and the dialog closes without freezing the python instance. I don’t even have to call file_dialog.deleteLater() for it to close itself.

When I try to use this from another script, for example doing:

from utils import ui_find_file
ui_find_file()

It produces the freezing behavior.

Updates on things I have tried but didn’t work

I am running this in python 3.10, Ubuntu 20.04, from a terminal.

  • I have tried using destroy() instead of destroyLater().
  • I have tried using app.processEvents() below destroy() with del(app)

The reason I am creating app = QApplication([]) was because when I didn’t, I got QWidget: Must construct a QApplication before a QWidget (which I can reproduce by commenting out the line)

Python 3.10.6 (main, Mar 10 2023, 10:55:28) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from utils import ui_find_file
>>> ui_find_file()
QWidget: Must construct a QApplication before a QWidget
Aborted (core dumped)
Asked By: Matias Andina

||

Answers:

I modified the code as follows to quit when being called from another script

def ui_find_file(title=None, initialdir=None, file_type=None):
    """
    Find a file using a GUI.
    :param title: Title of the dialog.
    :param initialdir: Initial directory.
    :param file_type: File type.
    :return: File path.
    """
    import os
    from PyQt6.QtWidgets import QApplication, QFileDialog

    app = QApplication.instance()
    if app is None:
        app = QApplication([])
        is_new_instance = True
    else:
        is_new_instance = False

    if title is None:
        title = 'Find a file'
    if initialdir is None:
        initialdir = os.getcwd()
    if file_type is None:
        file_filter = 'All files (*.*)'
    else:
        file_filter = f"{file_type} files (*.{file_type})"

    file_path, _ = QFileDialog.getOpenFileName(None, title, initialdir, file_filter)

    if file_path:
        # no multiple files for now...file_path will be a string
        #file_path = file_path[0]
        print(f"Selected {file_path}")
        result = file_path
    else:
        print("No file selected")
        result = None

    if is_new_instance:
        app.quit()

    return result

In this modification, we added a boolean variable is_new_instance to determine whether the QApplication instance was newly created in this function. If it was, we quit the QApplication instance by calling app.quit() after the file dialog is closed. This ensures that the event loop is properly managed and should prevent the script from hanging after the file selection.

Answered By: Matias Andina
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.