Register Guidelines E-Books Today's Posts Search

Go Back   MobileRead Forums > E-Book Software > Calibre > Development

Notices

Reply
 
Thread Tools Search this Thread
Old 08-14-2018, 12:47 PM   #1
Phssthpok
Age improves with wine.
Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.
 
Posts: 558
Karma: 95229
Join Date: Nov 2014
Device: Kindle Oasis, Kobo Libra II
How to use progress dialog?

I'm trying to create a UI plugin which processes selected books. All is well, but I end up with a loop of the form:
Code:
for book in book_list:
    ... do stuff ...
which does the work successfully enough, but tells me nothing until it finishes.

What I'd like is to have a blocking progress dialog that goes from 0 to len(book_list), updating each time around the loop. The only code sample I can find uses ProgressDialog and seems to involve lots of complication with WorkerThreads and suchlike. Maybe this is the easiest way to do it, maybe not... but can anyone give me some pointers on how to write minimal code to do what I want?

Last edited by Phssthpok; 08-14-2018 at 01:14 PM.
Phssthpok is offline   Reply With Quote
Old 08-14-2018, 03:00 PM   #2
jackie_w
Grand Sorcerer
jackie_w ought to be getting tired of karma fortunes by now.jackie_w ought to be getting tired of karma fortunes by now.jackie_w ought to be getting tired of karma fortunes by now.jackie_w ought to be getting tired of karma fortunes by now.jackie_w ought to be getting tired of karma fortunes by now.jackie_w ought to be getting tired of karma fortunes by now.jackie_w ought to be getting tired of karma fortunes by now.jackie_w ought to be getting tired of karma fortunes by now.jackie_w ought to be getting tired of karma fortunes by now.jackie_w ought to be getting tired of karma fortunes by now.jackie_w ought to be getting tired of karma fortunes by now.
 
Posts: 6,212
Karma: 16534894
Join Date: Sep 2009
Location: UK
Device: Kobo: KA1, ClaraHD, Forma, Libra2, Clara2E. PocketBook: TouchHD3
I remember going through this exact same learning process. Here's some minimal boiler-plate code for running a modal QProgressDialog with a Cancel button in a calibre User Interface plugin:

Spoiler:
Code:
from PyQt5.Qt import (QProgressDialog, QTimer)

class MyProgressDialog(QProgressDialog):

    def __init__(self, gui, book_ids, arg1, arg2, ...):
        self.total_books = len(book_ids)
        QProgressDialog.__init__(self, '', 'Cancel', 0, self.total_books, gui)
        self.gui = gui
        self.book_ids = book_ids
        self.db = self.gui.current_db.new_api
        # ... etc etc ...
        
        self.i = 0
        
        self.setWindowTitle('blah, blah')
        icon = get_icons('images/plugin_icon.png')
        self.setWindowIcon(icon)
        
        QTimer.singleShot(0, self.do_book_action)
        self.exec_()

    def do_book_action(self):
        # Process a single book 
        if self.wasCanceled():
            return self.do_close()
        if self.i >= self.total_books:
            return self.do_close()
        
        # get data for current book, e.g.
        book_id = self.book_ids[self.i]
        title = self.db.field_for('title', book_id)
        pathtoepub = self.db.format(book_id, 'EPUB', as_path=True)
        # ... do stuff ...
        
        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


Then to run the QProgressDialog from your main process:
Code:
dlg = MyProgressDialog(self.gui, self.book_ids, arg1, arg2, ...)
if dlg.wasCanceled():
    # do cancelled stuff
else:
    # do ran-to-completion stuff
jackie_w is offline   Reply With Quote
Advert
Old 08-15-2018, 04:59 AM   #3
Phssthpok
Age improves with wine.
Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.
 
Posts: 558
Karma: 95229
Join Date: Nov 2014
Device: Kindle Oasis, Kobo Libra II
Quote:
Originally Posted by jackie_w View Post
I remember going through this exact same learning process. Here's some minimal boiler-plate code for running a modal QProgressDialog with a Cancel button in a calibre User Interface plugin:
Wow. If that's minimal, I'd hate to see something really complex!

Your help is much appreciated. A bit of expert guidance is much better than burrowing around in the code base looking for relevant snippets. Many thanks.
Phssthpok is offline   Reply With Quote
Old 08-15-2018, 08:16 AM   #4
davidfor
Grand Sorcerer
davidfor ought to be getting tired of karma fortunes by now.davidfor ought to be getting tired of karma fortunes by now.davidfor ought to be getting tired of karma fortunes by now.davidfor ought to be getting tired of karma fortunes by now.davidfor ought to be getting tired of karma fortunes by now.davidfor ought to be getting tired of karma fortunes by now.davidfor ought to be getting tired of karma fortunes by now.davidfor ought to be getting tired of karma fortunes by now.davidfor ought to be getting tired of karma fortunes by now.davidfor ought to be getting tired of karma fortunes by now.davidfor ought to be getting tired of karma fortunes by now.
 
Posts: 24,907
Karma: 47303748
Join Date: Jul 2011
Location: Sydney, Australia
Device: Kobo:Touch,Glo, AuraH2O, GloHD,AuraONE, ClaraHD, Libra H2O; tolinoepos
An alternative is to grab the common_utils.py from one of kiwidudes plugins, or one of mine. This has a ProgressBar implementation. Here is how it is called:

Code:
        pb = ProgressBar(parent=self.gui, window_title=_("Removing annotations"), on_top=True)
        total_books = len(db.data)
        pb.set_maximum(total_books)
        pb.set_value(0)
        pb.set_label('{:^100}'.format(_("Scanning {0} of {1}").format(0, total_books)))
        pb.show()

        for i, record in enumerate(db.data.iterall()):
            pb.set_label('{:^100}'.format(_("Scanning {0} of {1}").format(i, total_books)))
            pb.increment()
            # Do whatever

        # Hide the progress bar
        pb.hide()
This is modal and can't be cancelled. Overall, probably no simpler as it relies on another class, but it feels simpler when actually using it.
davidfor is offline   Reply With Quote
Old 08-15-2018, 12:52 PM   #5
Phssthpok
Age improves with wine.
Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.Phssthpok knows how to set a laser printer to stun.
 
Posts: 558
Karma: 95229
Join Date: Nov 2014
Device: Kindle Oasis, Kobo Libra II
Quote:
Originally Posted by davidfor View Post
An alternative is to grab the common_utils.py from one of kiwidudes plugins, or one of mine. This has a ProgressBar implementation. Here is how it is called:
Many thanks, this looks much simpler! I'll do it next time (if there is one)...

Meanwhile I got my plugin working, but I don't have the time to polish it to make it more professional or error-resistant or to invent an icon for it. I'm attaching it here in case anyone wants to pick it up. What it does is to extract the tables of contents from selected ePub files to generate a CSV file. The idea was to make it easier for me to create a list of the short stories in my collection of anthologies. It incorporates a copy of https://pypi.org/project/Unidecode/ which is used to flatten all strings to ASCII, since Microsoft Excel seems to be allergic to UTF-8. The authors, titles, series and ToC entry are all converted to title case to make it easier to sort the output file. Hope someone will find a use for it besides me.
Attached Files
File Type: zip Extract_ToCs.zip (208.7 KB, 308 views)

Last edited by Phssthpok; 08-15-2018 at 12:56 PM.
Phssthpok is offline   Reply With Quote
Advert
Old 08-16-2018, 05:42 AM   #6
Terisa de morgan
Grand Sorcerer
Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.
 
Terisa de morgan's Avatar
 
Posts: 6,233
Karma: 11768331
Join Date: Jun 2009
Location: Madrid, Spain
Device: Kobo Clara/Aura One/Forma,XiaoMI 5, iPad, Huawei MediaPad, YotaPhone 2
Quote:
Originally Posted by Phssthpok View Post
Many thanks, this looks much simpler! I'll do it next time (if there is one)...

Meanwhile I got my plugin working, but I don't have the time to polish it to make it more professional or error-resistant or to invent an icon for it. I'm attaching it here in case anyone wants to pick it up. What it does is to extract the tables of contents from selected ePub files to generate a CSV file. The idea was to make it easier for me to create a list of the short stories in my collection of anthologies. It incorporates a copy of https://pypi.org/project/Unidecode/ which is used to flatten all strings to ASCII, since Microsoft Excel seems to be allergic to UTF-8. The authors, titles, series and ToC entry are all converted to title case to make it easier to sort the output file. Hope someone will find a use for it besides me.
Thank you very much, it's useful and comfortable for anthologies. It's in my calibre now If I was able to link it with ePubSplit....
Terisa de morgan is offline   Reply With Quote
Old 10-16-2020, 06:16 PM   #7
un_pogaz
Chalut o/
un_pogaz understands the importance of being earnest.un_pogaz understands the importance of being earnest.un_pogaz understands the importance of being earnest.un_pogaz understands the importance of being earnest.un_pogaz understands the importance of being earnest.un_pogaz understands the importance of being earnest.un_pogaz understands the importance of being earnest.un_pogaz understands the importance of being earnest.un_pogaz understands the importance of being earnest.un_pogaz understands the importance of being earnest.un_pogaz understands the importance of being earnest.
 
un_pogaz's Avatar
 
Posts: 410
Karma: 145324
Join Date: Dec 2017
Device: Kobo
Sorry for the Necro-post, but the solution presented here is not the most optimal.
(Recursive call of a QTimer object in the function)
Too bad, but excepted this, Thanks to this thread, I was able to make my plugin, so I return the elevator.

My optimised version:
Code:
class CustomProgressDialog(QProgressDialog):
    
    def __init__(self, gui, book_ids):
        
        # DB API
        self.dbA = gui.current_db;
        # list of books id
        self.book_ids = book_ids;
        # Books count 
        self.book_count = len(self.book_ids);
        # Output book dic 
        self.books_dic = {};
        
        
        QProgressDialog.__init__(self, '', _('Cancel'), 0, self.book_count, gui);
        self.gui = gui;
        
        self.setWindowTitle(_('Progress Bar Name'));
        self.setWindowIcon(get_icon('images/plugin_icon.png'));
        
        self.setValue(0);
        self.setMinimumWidth(500);
        self.setMinimumDuration(100);
        
        self.setAutoClose(True);
        self.setAutoReset(False);
        
        self.hide();
        debug_print('Launch cleaning for {0} book.'.format(self.book_count));
        
        QTimer.singleShot(0, self._do_book_action);
        self.exec_();
        

    def close(self):
        self.dbA = None;
        self.books_dic = None;
        super(CleanerProgressDialog, self).close();

    def _do_book_action(self):
        
        self.setValue(0);
        
        for num, book_id in enumerate(self.book_ids, start=1):
            
            # update ProgressBar
            self.setValue(num);
            self.setLabelText(_('Book {0} of {1}').format(num, self.book_count));
            
            if self.book_count < 100:
                self.hide();
            else:
                self.show();
            
            if self.wasCanceled():
                self.close();
                return;
            
            #
            # Write your code here
            #
            #
            # Example
            
            miA = self.dbA.get_metadata(book_id, index_is_id=True, get_cover=False);
            comment = miA.get('comments');
            
            if comment is not None:
                self.books_dic[book_id] = CleanHTML(comment);
            #
            
        
        
        # end of your code if not canceled
        #
        # update the database library
        debug_print('ProgressDialog - Finish')
        debug_print('Update the database for {0} books...\n'.format(len(self.books_dic)));
        self.setLabelText(_('Update the library for {0} books...').format(len(self.books_dic)));
        
        self.dbA.new_api.set_field('comments', {id:self.books_dic[id] for id in self.books_dic.keys()});
        self.gui.iactions['Edit Metadata'].refresh_gui(self.books_dic.keys(), covers_changed=False);
        
        self.hide();
        return;
un_pogaz is offline   Reply With Quote
Reply


Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Q: 'See What Changed' dialog phossler Editor 7 06-30-2017 09:05 AM
QT dialog osX Pr.BarnArt Development 5 09-01-2013 11:26 PM
Dialog Question VydorScope Writers' Corner 17 08-04-2013 06:03 PM
Help with dialog... VydorScope Writers' Corner 9 06-14-2013 09:57 PM
A dialog with Borders Taylor514ce Sony Reader 45 06-19-2008 11:04 PM


All times are GMT -4. The time now is 09:24 PM.


MobileRead.com is a privately owned, operated and funded community.