[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