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