[PySide] wait for QFileDialog to close

Frank Rueter | OHUfx frank at ohufx.com
Thu Dec 12 00:16:36 CET 2013


Ok, will report back if I stumble across anything interesting. For now I 
will just assume that my example simply shouldn't work :-D


On 12/12/13 12:07, Sean Fisk wrote:
> Frank,
>
> Understood. I'm going to try your example on CentOS 6.4 with PySide 
> 1.2.1 and see what happens. Let me know what happens with future 
> progress bars. I'm going to start doing a lot of asynchronous stuff 
> soon, so it would be helpful to know.
>
> Thanks,
>
>
> --
> Sean Fisk
>
>
> On Wed, Dec 11, 2013 at 4:45 PM, Frank Rueter | OHUfx <frank at ohufx.com 
> <mailto:frank at ohufx.com>> wrote:
>
>     Hi Sean,
>
>     I totally agree that it shouldn't work, and I paid little
>     attention to it as I just wanted to provide an example for the signal.
>
>     I am on Kubuntu 12.10 using PySide 1.2.1.
>     I just ran the code on an OSX box with an old PySide installation
>     (1.0.9) and the progressbar didn't move there.
>
>     I have a few simple apps to write which will involve proper use of
>     progressbar to indicate background image processing, so I'm sure I
>     will run into it again.
>
>
>     Cheers,
>     frank
>
>
>
>     On 12/12/13 09:56, Sean Fisk wrote:
>>     Janwillem,
>>
>>     I'm glad you were able to able to figure out the problem. Sorry
>>     for my red herrings!
>>
>>     Frank,
>>
>>     I thought about it, and I have no idea why the progress bar works
>>     fine for you and not for me. It hangs for me, which is exactly
>>     what I expected to happen. Maybe some platform difference? I'm on
>>     Mac OS 10.6 with PySide 1.2.1.
>>
>>
>>     --
>>     Sean Fisk
>>
>>
>>     On Wed, Dec 11, 2013 at 9:16 AM, Janwillem van Dijk
>>     <jwevandijk at xs4all.nl <mailto:jwevandijk at xs4all.nl>> wrote:
>>
>>         The solution Frank proposed yesterday works (after I found
>>         out that you can get the output using selectedFiles()[0]).
>>         No problems with the progressbar.
>>         The actual processing can take a bit long because the exif's
>>         of digital camera shots are analysed (GExiv2 for photos and
>>         exiftool for movies ) and than copied to folders as
>>         /camara_make/year/month/imagetype/yyyymmddhhmmss_fname. When
>>         copying more than say 50 16MB raw photos the gui becomes
>>         blocked. In other apps I indeed solved that with threading
>>         but, although not elegant, I decided to live with that for
>>         this one.
>>         Many thanks for teaching me this extra bit of Python.
>>         Cheers, Janwillem
>>
>>
>>         On 11/12/13 05:45, Sean Fisk wrote:
>>>
>>>         Frank,
>>>
>>>         Your example is a good demonstration of |QFileDialog|‘s
>>>         signals. However, since the processing runs in the GUI
>>>         thread, the progress bar is virtually useless as the GUI has
>>>         no time to update it. It starts empty, the application
>>>         hangs, and then it is filled when the processing is done.
>>>
>>>         Janwillem,
>>>
>>>         As I see it, if you would like a progress bar, you have
>>>         three options:
>>>
>>>          1. Call |QCoreApplication.processEvents()|
>>>             <http://seanfisk.github.io/pyside-docs/pyside/PySide/QtCore/QCoreApplication.html#PySide.QtCore.PySide.QtCore.QCoreApplication.processEvents>
>>>             during your processing code. This is not always a great
>>>             idea, and more of a hack than a solution. But it usually
>>>             works.
>>>          2. Split your processing into chunks as in this example
>>>             <http://qt-project.org/wiki/Threads_Events_QObjects#72c9aabadf52900fbf3d4c1ff2b6008c>.
>>>             However, the code is a bit convoluted and it still runs
>>>             in the GUI thread. The whole page that contains that
>>>             example is a great read for asynchronous programming.
>>>          3. Send your processing to a thread, and dispatch events
>>>             from the thread indicating the progress.
>>>
>>>         The first two solutions involve running processing code
>>>         within the GUI thread. If any step of the processing takes
>>>         longer than a second, then it’s probably not a good idea as
>>>         the user will see the application hang. Here is an example
>>>         implementation of the third solution:
>>>
>>>         |#!/usr/bin/env python
>>>
>>>         # Example: Asynchronously process a directory of files with a progress bar.
>>>
>>>         import  sys
>>>         import  os
>>>         import  time
>>>
>>>         from  PySideimport  QtCore, QtGui
>>>
>>>         class  ProcessingThread(QtCore.QThread):
>>>              # Fired when each file is processed.
>>>              file_processed = QtCore.Signal(int, str)
>>>
>>>              def  __init__(self, parent=None):
>>>                  super(ProcessingThread, self).__init__(parent)
>>>                  self.files = []
>>>
>>>              def  run(self):
>>>                  # Code that's run in the thread.
>>>                  for  i, filenamein  enumerate(self.files):
>>>                      # The actual code for one file goes here. Stubbed out with
>>>                      # time.sleep() for now.
>>>                      time.sleep(0.5)
>>>                      print  'Processed:', filename
>>>                      # Send update to the GUI thread.
>>>                      self.file_processed.emit(i +1, filename)
>>>
>>>         class  MyWidget(QtGui.QWidget):
>>>              def  __init__(self, parent=None):
>>>                  super(MyWidget, self).__init__(parent)
>>>
>>>                  # Setup UI.
>>>                  self._layout = QtGui.QVBoxLayout(self)
>>>                  self._button = QtGui.QPushButton('Open files...')
>>>                  self._progress = QtGui.QProgressBar()
>>>                  self._filelist = QtGui.QPlainTextEdit()
>>>                  self._layout.addWidget(self._button)
>>>                  self._layout.addWidget(self._filelist)
>>>                  self._layout.addWidget(self._progress)
>>>
>>>                  # Setup events.
>>>                  self._button.clicked.connect(self._button_clicked)
>>>
>>>                  # Create the thread. Note that this doesn't actually _start_ it.
>>>                  self._thread = ProcessingThread()
>>>                  self._thread.file_processed.connect(self._file_processed)
>>>
>>>                  # We need to wait for the thread before exiting. Either use this or
>>>                  # don't let the user close the window if processing is happening. See
>>>                  # the next method in this class.
>>>                  QtCore.QCoreApplication.instance().aboutToQuit.connect(
>>>                      self._thread.wait)
>>>
>>>              # def closeEvent(self, event):
>>>              #     # This is an alternative to waiting for the threads. Just don't let
>>>              #     # the user close the window.
>>>              #     if self._thread.isRunning():
>>>              #         QtGui.QMessageBox.critical(
>>>              #             self, 'Processing',
>>>              #             'Cannot exit while processing is happening.')
>>>              #         event.ignore()
>>>              #     else:
>>>              #         event.accept()
>>>
>>>              def  _button_clicked(self):
>>>                  # If we are already running the processing, produce an error.
>>>                  if  self._thread.isRunning():
>>>                      QtGui.QMessageBox.critical(
>>>                          self,'Processing',
>>>                          'Can only process one directory at a time.')
>>>                      return
>>>
>>>                  # Get the directory name from the user.
>>>                  dir_name = QtGui.QFileDialog.getExistingDirectory(
>>>                      parent=self,
>>>                      caption='Choose files...',
>>>                      dir=os.getcwd())
>>>
>>>                  # Activate the main dialog as it will be deactivated for some reason
>>>                  # after the file dialog closes (at least on my machine).
>>>                  self.activateWindow()
>>>
>>>                  # Get the list of files in the directory and prime the progress bar.
>>>                  files = os.listdir(dir_name)
>>>
>>>                  # Set values for progress bar.
>>>                  self._progress.setRange(0, len(files))
>>>                  self._progress.setValue(0)
>>>
>>>                  # Create and start the thread.
>>>                  self._thread.files = files
>>>                  self._thread.start()
>>>
>>>              def  _file_processed(self, num_files_processed, filename):
>>>                  # Called for each file that is processed.
>>>                  self._filelist.appendPlainText(filename)
>>>                  self._progress.setValue(num_files_processed)
>>>
>>>         if  __name__ =='__main__':
>>>              app = QtGui.QApplication(sys.argv)
>>>              w = MyWidget()
>>>              w.show()
>>>              w.raise_()
>>>              raise  SystemExit(app.exec_())|
>>>
>>>         This is all fine, but it might not solve your original
>>>         problem of the file dialog not closing. On my Mac, the file
>>>         dialog is gone as soon as the call to
>>>         |getExistingDirectory()| finishes. However, since I don’t
>>>         have a runnable portion of your code, I can’t really test
>>>         it. I would recommend attempting to run my example to see if
>>>         it exhibits the same problem as your program. Hope this helps!
>>>
>>>         Cheers,
>>>
>>>
>>>
>>>
>>>         --
>>>         Sean Fisk
>>>
>>>
>>>         On Tue, Dec 10, 2013 at 4:43 PM, Frank Rueter | OHUfx
>>>         <frank at ohufx.com <mailto:frank at ohufx.com>> wrote:
>>>
>>>             Here is an example using signals/slots
>>>
>>>
>>>             On 11/12/13 09:56, Janwillem van Dijk wrote:
>>>>
>>>>             Here is the snippet: It reads the filenames in a folder
>>>>             and determines new names for photo's based on the exif
>>>>             info.
>>>>
>>>>             I apreciate that threading might be a solution but the
>>>>             problem seems too simple for that. Can you give an
>>>>             example on how to use the signal concept?
>>>>
>>>>
>>>>             self.outFolder = QFileDialog.getExistingDirectory(
>>>>
>>>>             caption='Destination folder', dir=self.defOutFolder)
>>>>
>>>>             self.outFiles = []
>>>>
>>>>             if self.outFolder:
>>>>
>>>>             self.outFolder = self.outFolder.replace('\\', '/')
>>>>
>>>>             self.lineEdit_dest.setText(self.outFolder)
>>>>
>>>>             self.progressBar.setRange(0, self.numFiles)
>>>>
>>>>             for i, fname in enumerate(self.inFiles):
>>>>
>>>>             self.progressBar.setValue(i + 1)
>>>>
>>>>             newpath, newfname = rename_photo(self.inFolder, fname)
>>>>
>>>>             newpath = path.join(self.outFolder, newpath)
>>>>
>>>>             self.outFiles.append([fname, newpath, newfname])
>>>>
>>>>             s = fname + ' --> ' + self.outFolder + '\n'
>>>>
>>>>             s += path.join(newpath,
>>>>             newfname).replace(self.outFolder, '')
>>>>
>>>>             self.plainTextEdit_dest.appendPlainText(s)
>>>>
>>>>
>>>>
>>>>             On 10/12/13 21:35, Sean Fisk wrote:
>>>>>
>>>>>             Hi Janwillem,
>>>>>
>>>>>             Are you running the “lengthy part that processes a
>>>>>             files list” within the GUI thread? If so, you will
>>>>>             probably see your GUI hang while this is happening
>>>>>             (you won’t be able to click or do anything). In this
>>>>>             case, you should consider running the processing in a
>>>>>             different thread using QThread
>>>>>             <http://seanfisk.github.io/pyside-docs/pyside/PySide/QtCore/QThread.html>
>>>>>             or QThreadPool
>>>>>             <http://seanfisk.github.io/pyside-docs/pyside/PySide/QtCore/QThreadPool.html>.
>>>>>
>>>>>             Can you post the relevant part of the code?
>>>>>
>>>>>             Thanks,
>>>>>
>>>>>
>>>>>
>>>>>             --
>>>>>             Sean Fisk
>>>>>
>>>>>
>>>>>             On Tue, Dec 10, 2013 at 3:17 PM, Janwillem van Dijk
>>>>>             <jwevandijk at xs4all.nl <mailto:jwevandijk at xs4all.nl>>
>>>>>             wrote:
>>>>>
>>>>>                 Hi, I have a PySide script that uses
>>>>>                 QFileDialog.getExistingDirectory(). After clicking
>>>>>                 the Open button the script proceeds with a lengthy
>>>>>                 part that processes a files list and writes to a
>>>>>                 QPlainTextEdit. Unfortunately the QFileDialog
>>>>>                 widget does only disappear after this processing
>>>>>                 is finished, hiding the QPlainTextEdit.
>>>>>
>>>>>                 How can I make that the QFileDialog widget is gone
>>>>>                 before the processing starts?
>>>>>
>>>>>                 Cheers, Janwillem
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>                 _______________________________________________
>>>>>                 PySide mailing list
>>>>>                 PySide at qt-project.org <mailto:PySide at qt-project.org>
>>>>>                 http://lists.qt-project.org/mailman/listinfo/pyside
>>>>>
>>>>>
>>>>
>>>
>>>
>>
>>
>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/pyside/attachments/20131212/216a62ca/attachment.html>


More information about the PySide mailing list