Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save martin-chatterjee/326d6fd2523a215212fb55b815fa434a to your computer and use it in GitHub Desktop.
Save martin-chatterjee/326d6fd2523a215212fb55b815fa434a to your computer and use it in GitHub Desktop.
PySide2: A QFileDialog displayed modally can not be closed by triggering accept().
# -*- coding: utf-8 -*-
# try to import PySide2, fall back to PySide
try:
from PySide2 import QtCore, QtGui, QtWidgets
except ImportError:
from PySide import QtCore, QtGui
import PySide.QtGui as QtWidgets
import sys
import os
import tempfile
import shutil
# -----------------------------------------------------------------------------
def repro():
"""Creates a FileDialog and displays it modally.
Using a QTimer the FileDialog should automatically get closed after
3 seconds by triggering the slot 'accept()'.
This works (on Windows 10):
- in standalone Python 2.7 + PySide
- in Maya 2016 SP6 (--> PySide)
This does not work: (tested on Windows 10)
- in Maya 2017 Update4 (--> PySide2).
- in Maya 2018 Update2 (--> PySide2).
"""
parent_widget = _resolveParentWidget()
# creates a FileDialog in save mode and
# points it to a valid temp directory
temp_dir = tempfile.mkdtemp()
file_dialog = QtWidgets.QFileDialog(parent=parent_widget,
directory=temp_dir)
file_dialog.selectFile('saveName')
file_dialog.setAcceptMode(QtWidgets.QFileDialog.AcceptSave)
# trigger 'accept' after 3 seconds
def triggerAccept():
file_dialog.accept()
# proof that QTimer is working and this got executed
print 'triggerAccept got called'
# QtCore.QTimer.singleShot(3000, file_dialog.accept)
QtCore.QTimer.singleShot(3000, triggerAccept)
print '- displaying QFileDialog modally.'
print '- triggering "accept()" after 3 seconds.'
status = file_dialog.exec_()
print '- return value: %s (expected: 1)' % status
# cleanup
file_dialog = None
shutil.rmtree(temp_dir)
# -----------------------------------------------------------------------------
def _resolveParentWidget():
"""Resolves and returns context-specific parent widget.
In a standalone Python context a QApplication gets created
and None gets returned.
In a Maya context the Main Maya Window gets returned.
"""
context = os.path.basename(sys.executable).lower()
if context.find('python') != -1:
app = QtWidgets.QApplication(sys.argv)
return None
elif context.find('maya') != -1:
for widget in QtWidgets.QApplication.topLevelWidgets():
name = widget.objectName()
if name == 'MayaWindow':
return widget
else:
raise NotImplementedError('Context not supported: %s' % context)
if __name__ == '__main__':
repro()
@martin-chatterjee
Copy link
Author

martin-chatterjee commented Mar 8, 2018

I stumbled over this issue while writing tests for some UI code.
I want to display a QDialog modally and then automatically close it with a few seconds delay by calling accept().
This does work as expected in PySide -- however it does not work anymore in PySide2.

In PySide (both Standalone Python 2.7 and Maya 2016 SP6) I can:

1.) create a QFileDialog
2.) set up a QTimer to call accept() with a few seconds delay
3.) display it modally by calling exec_()

The expected result of this is that the QFileDialog gets displayed modally and then gets closed by the delayed call to accept().
The return value of the exec_() call will be '1' as expected.

In PySide2 (Maya 2017 & Maya 2018) this does not work...

  • the QFileDialog gets displayed modally.
  • the QTimer gets executed (verified by a print message)
  • however the accept() call gets ignored. The QFileDialog remains open until I manually click the OK button.

Repro:

1.) Download the provided Gist Python file.

2.) Execute it in a PySide environment (either standalone Python 2.7 + PySide, or in the Script Editor of Maya 2016)
--> this works as expected

3.) Now execute it in a PySide2 environment (in the Script Editor of Maya 2017 or Maya 2018)
--> this does not work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment