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 <[email protected]>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 sysimport osimport time > from PySide import 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, filename in 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 <[email protected]>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 <[email protected] >> > 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 >>> [email protected] >>> http://lists.qt-project.org/mailman/listinfo/pyside >>> >>> >> >> >> > >
_______________________________________________ PySide mailing list [email protected] http://lists.qt-project.org/mailman/listinfo/pyside
