08-18-2012, 05:59 PM | #1 |
Grand Sorcerer
Posts: 6,212
Karma: 16534894
Join Date: Sep 2009
Location: UK
Device: Kobo: KA1, ClaraHD, Forma, Libra2, Clara2E. PocketBook: TouchHD3
|
Help with python QProgressBar, please.
Please can someone help me with a Python problem?
In my user interface plugin's main processing file the basic code looks something like this Code:
class CopyCoverUiAction(InterfaceAction): ... ... def genesis(self): ... ... def apply_settings(self): ... ... ... ... def copycover_selected(self): # some validation actions # get user selected book rows for book in range(len(rows)): # process the book # some end actions # open a QTextBrowser info dialog to display results However, for some devices the book looping can be quite lengthy if many books are selected (max 99), and from a user POV it can appear that calibre isn't doing anything and is unresponsive. So what I want to do is add some kind of progress bar pop-up, starting just before the loops start, ending just after the loops finish and being updated once at the end of each cycle. I've tried to get a QProgressBar() working but I'm obviously doing it wrong. In fact I've tried so many different combinations that I'm now completely scrambled. For the sake of my sanity please can someone show me some sample code of how to set up a simple ProgressBar with appropriate signals/slots so that the bar opens, visibly updates at the completion of each cycle then closes without any user interaction. The limited amount of python/Qt sample code I've found on Google, if it works at all, is using timer intervals or other widgets to update the Progbar and I'm not sure that's what I need. I've also looked at some calibre source code but am not able to see the wood for the trees. I've managed to pick up (I think) some basics like self.pb = QProgressBar(self) but am totally unable to arrange them into something that works. I also know that event handling can be complex and my OOP skills are very limited. So if there is a simple, robust way forward I'd be most grateful.self.pbar.setRange(0, len(rows)) self.pbar.setValue(int step) P.S. In some of my own non-calibre python experiments I've had some success with progressive screen updating using this piece of magic code QApplication.instance().processEvents() (thanks to chaley) but I'm not sure how to apply it in this case. |
08-18-2012, 06:05 PM | #2 |
Calibre Plugins Developer
Posts: 4,636
Karma: 2162064
Join Date: Oct 2010
Location: Australia
Device: Kindle Oasis
|
Have a look at the Quality Check plugin source code - specifically "dialogs.py" and copy/modify the "QualityProgressDialog" class which is at the top of the file. Basically you just do your work inside that "do_book_action" function, and that self.i counter and self.setValue stuff increments the progress bar, using QTimer.singleShot to ensure it pumps the message threads to keep the UI updated while it does the work.
It is invoked from the check_base.py file, inside the "check_all_files" function - just a case of instantiating it passing in whatever parameters it needs to do the work. In the case of this plugin it passes in a callback_fn parameter, being a function pointer reference to a dynamically chosen function (since the same dialog is redisplayed for a whole range of different purposes) but you can ignore that and do the work inside the dialog itself if you want as I mentioned above. It is a pattern I have used over and over again in my plugins, many of them have it. |
Advert | |
|
08-18-2012, 06:12 PM | #3 |
Grand Sorcerer
Posts: 6,212
Karma: 16534894
Join Date: Sep 2009
Location: UK
Device: Kobo: KA1, ClaraHD, Forma, Libra2, Clara2E. PocketBook: TouchHD3
|
You are one fast reader, kiwidude Shouldn't you be out on the town in the hotspots of London?
Thank you so much. I'll try to make sense of it. I can't promise I won't be back though. |
08-18-2012, 06:16 PM | #4 |
Calibre Plugins Developer
Posts: 4,636
Karma: 2162064
Join Date: Oct 2010
Location: Australia
Device: Kindle Oasis
|
Probably "should" be but not my scene really, peace and quiet at home preferred to competing with the countless drunken hordes ejected from the pubs as London shuts down about now...
|
08-19-2012, 01:05 PM | #5 |
Grand Sorcerer
Posts: 6,212
Karma: 16534894
Join Date: Sep 2009
Location: UK
Device: Kobo: KA1, ClaraHD, Forma, Libra2, Clara2E. PocketBook: TouchHD3
|
Just a follow-up to say that everything seems to be working Thanks for your help.
|
Advert | |
|
09-03-2012, 10:07 AM | #6 |
Zealot
Posts: 109
Karma: 419
Join Date: Aug 2012
Location: Spain
Device: Kindle Touch
|
I was using a QProgess Bar, after looking kiwidude's Quality Check plugin.
I works OK, but I have a problem when the user cancel the process. I assign the progressbar object, and then I do "progressbar.exec_()". The function assigned to QTimer.singleShot makes it work, but if the user closes the window, the function continues executing (and obviously, I get some errors). I tried hidding "cancel" and "close" buttons, but if the user press "ESC" the window still closes. Somebody can help me? |
09-03-2012, 10:32 AM | #7 |
Grand Sorcerer
Posts: 6,212
Karma: 16534894
Join Date: Sep 2009
Location: UK
Device: Kobo: KA1, ClaraHD, Forma, Libra2, Clara2E. PocketBook: TouchHD3
|
At the risk of the blind leading the blind, this is what I did after having looked at kiwidude's Quality Check code.
I used a QProgressDialog rather than QProgressBar. This was the dialog: Code:
class CoverProgressDialog(QProgressDialog): def __init__(self, gui, total_books, some_more_params): self.total_books = total_books QProgressDialog.__init__(self, '', QString('Cancel'), 0, self.total_books, gui) self.gui = gui # ... ... self.i = 0 # ... ... QTimer.singleShot(0, self.do_book_action) self.exec_() def do_book_action(self): if self.wasCanceled(): return self.do_close() if self.i >= self.total_books: return self.do_close() # code for processing a single book ... self.i += 1 self.setLabelText('%d of %d' % (self.i, self.total_books)) self.setValue(self.i) QTimer.singleShot(0, self.do_book_action) def do_close(self): self.hide() self.gui = None Code:
dlg = CoverProgressDialog(self.gui, total_books, some_more_params) if dlg.wasCanceled(): # do whatever should be done if user cancelled |
09-03-2012, 10:45 AM | #8 |
Calibre Plugins Developer
Posts: 4,636
Karma: 2162064
Join Date: Oct 2010
Location: Australia
Device: Kindle Oasis
|
@jackie_w - I think that would be "the blind leading the blind leading the blind"
|
09-03-2012, 11:01 AM | #9 | |
Grand Sorcerer
Posts: 6,212
Karma: 16534894
Join Date: Sep 2009
Location: UK
Device: Kobo: KA1, ClaraHD, Forma, Libra2, Clara2E. PocketBook: TouchHD3
|
Quote:
... which brings me to another question, is there a good manual for learning about PyQt, with lots of examples? I found 'Rapid GUI Programming with Python and Qt' by Mark Summerfield. The early chapters were good enough to give me a very basic toolkit, but it soon got beyond me |
|
09-03-2012, 12:52 PM | #10 |
Zealot
Posts: 109
Karma: 419
Join Date: Aug 2012
Location: Spain
Device: Kindle Touch
|
jackie_w, I do the same way than you do (I also look at kiwidude's code).
The only difference is that I don't have a cancel button, so I never had a self.wasCanceled() true value. But the problem is when the user doesn't cancel, but closes the window. Try with your code, when the bar is on screen, if you press "ESC" or push the X button, the window closes, but it doesn't produces a "Cancel" event (maybe because you're not canceling, but closing). I found the way to hide the close button, but the "ESC" key still closes it. In my case, the code in the function "do_book_action" (in your example), continues executing when the progress bar window is closed at this way, and the execution at the main window continues. The process I was doing is to uncompress a ZIP file to a temporary folder, then the progress bar shows when adding some books to the library, and at last it closes, and I delete the temporary files from the main window. When the user closes the progress bar window before the process is finished, the function who add books continues, but the code at the main window deletes the files, so I get lots of errors. Last edited by Pepin33; 09-03-2012 at 12:56 PM. |
09-03-2012, 02:04 PM | #11 |
Grand Sorcerer
Posts: 6,212
Karma: 16534894
Join Date: Sep 2009
Location: UK
Device: Kobo: KA1, ClaraHD, Forma, Libra2, Clara2E. PocketBook: TouchHD3
|
I just tried my plugin again - as a normal user would use it.
When I Esc or Close-window-with-x-button, I get the same result as I do when I press the Cancel button of the QProgressDialog widget. In my case it is copying images from calibre to a directory on a connected reader. The copying stops when any of the 3 actions is taken. The files already copied seem to be useable. It is also apparent from the logging info I am collecting that dlg.wasCanceled() = True when tested by the calling program. |
09-03-2012, 02:16 PM | #12 |
Zealot
Posts: 109
Karma: 419
Join Date: Aug 2012
Location: Spain
Device: Kindle Touch
|
Maybe the problem is that I don't have a "Cancel" button, then. I'm going to put one, and checking self.wasCanceled() to stop the process...
Last edited by Pepin33; 09-03-2012 at 02:19 PM. |
09-04-2012, 02:54 AM | #13 |
Zealot
Posts: 109
Karma: 419
Join Date: Aug 2012
Location: Spain
Device: Kindle Touch
|
Right. I tried putting a "Cancel" button, and then I have a self.wasCanceled()=true when the progress dialog is closed by the user (pressing "Cancel", "Close" or "ESC" key).
The problem comes if you don't use a "Cancel" button. Then, the wasCanceled() function doesn't help. Then, how can you know that the window is closing to stop the process you're doing? Another question: Anybody knows how can I cancel the "ESC" signal at PyQt windows, to prevent the user can close the dialog this way? |
|
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Python help please | AndyW1691 | Library Management | 3 | 02-08-2012 09:51 AM |
python 2.X to 3.X migration? | KevinH | Calibre | 7 | 02-13-2011 07:56 PM |
What is python | The Terminator | General Discussions | 20 | 01-21-2011 12:58 PM |
Python 2.7 | DiapDealer | Calibre | 4 | 12-17-2010 11:19 AM |
Python 2.5 or 2.6? | itimpi | Calibre | 5 | 01-19-2009 12:48 PM |