The approach I would suggest would be using custom PyQt signals. The example below is based on the example for extending QgsTask in the PyQGIS Developer Cookbook, modified to emit custom signals from the background task and listen for them from the main thread. You can then connect to a slot which pushes a message to the message bar or otherwise interacts with interface/gui elements and widgets.
import random
from time import sleep
MESSAGE_CATEGORY = 'RandomIntegerSumTask'
class RandomIntegerSumTask(QgsTask):
# declare custom signals
half_finished = pyqtSignal(str)
number_found = pyqtSignal()
def __init__(self, description, duration):
super().__init__(description, QgsTask.CanCancel)
self.description = description
self.duration = duration
self.iterations = 0
def run(self):
QgsMessageLog.logMessage('Started task "{}"'.format(
self.description),
MESSAGE_CATEGORY, Qgis.Info)
wait_time = self.duration / 50
for i in range(20):
# report progress
self.setProgress(i*5)
if i*5 == 50:
# emit custom signal at 50% task completion
self.half_finished.emit(self.description)
arandominteger = random.randint(0, 100)
self.iterations += 1
# check isCanceled() to handle cancellation
if self.isCanceled():
return False
if arandominteger == 42:
self.number_found.emit()
super().cancel()
sleep(wait_time)
return True
def finished(self, result):
if result:
QgsMessageLog.logMessage(
'RandomTask {} completed with {} iterations'.format(
self.description, self.iterations), MESSAGE_CATEGORY, Qgis.Success)
else:
QgsMessageLog.logMessage(
'RandomTask {} did not complete successfully- '\
'encountered random integer 42!)'.format(
self.description),
MESSAGE_CATEGORY, Qgis.Warning)
class main(QWidget):
def __init__(self):
QWidget.__init__(self)
layout = QVBoxLayout()
self.lbl1 = QLabel('Task Progress:', self)
self.prog1 = QProgressBar(self)
self.lbl2 = QLabel('Sub-Task Progress:', self)
self.prog2 = QProgressBar(self)
for c in self.children():
layout.addWidget(c)
self.setLayout(layout)
self.task = RandomIntegerSumTask('waste cpu', 10)
self.task.progressChanged.connect(lambda: self.prog1.setValue(self.task.progress()))
# self.task.half_finished.connect(self.push_message_halfway)
# listen for custom signal and connect to a slot
self.task.number_found.connect(self.push_message_number_found)
self.subtask = RandomIntegerSumTask('waste cpu subtask short', 5)
self.subtask.progressChanged.connect(lambda: self.prog2.setValue(self.subtask.progress()))
# custom signals
self.subtask.half_finished.connect(self.push_message_halfway)
self.subtask.number_found.connect(self.push_message_number_found)
# Add a subtask
self.task.addSubTask(self.subtask)
QgsApplication.taskManager().addTask(self.task)
self.show()
def push_message_halfway(self, name):
iface.messageBar().pushMessage('Task {} is halfway through'.format(name))
def push_message_number_found(self):
iface.messageBar().pushMessage('Number 42 was generated- task cancelled!')
main()