3

In PyQGIS Cookbook, says:

Any background task (regardless of how it is created) must NEVER use any QObject that lives on the main thread, such as accessing QgsVectorLayer, QgsProject or perform any GUI based operations like creating new widgets or interacting with existing widgets.

But I have to use QObject to give feedback to User. For example, I have a Qlabel that keeps the user up to date on how many layers have been processed. If I change the text of label in thread, Qgis crashes. How can I change the label's text during processing layers. I use this approach:

btn_run.clicked.connect(task)
def task():
    t1 = threading.Thread(target=compilePage, args=("compilePageThread",))
    t1.start()
def compilePage(threadName):
    label.setText('Please Wait.')
    for layer in layers:
        #do some work on layer and then change label text to give feedback
        label.setText('{} has been processed.'.format(layer.name()))
3
  • 4
    for this, you can emit a signal connected you your main app and display the text send by signal. Signal won't affect the thread and don't modify the GUI, this is just your main loop that receive the signal and change label text. Mar 7, 2021 at 10:58
  • @J.Monticolo do you have an example plz ?
    – Linda
    Apr 21, 2022 at 15:02
  • @Linda: see my answer. Apr 21, 2022 at 15:50

1 Answer 1

6

By taking and simplifying the PyQGIS Cookbook example, here is an example :

from time import sleep
from qgis.core import QgsApplication, QgsTask
from PyQt5.QtCore import pyqtSignal


class MyTask(QgsTask):

    cycle_changed = pyqtSignal(int)

    def __init__(self):
        super(MyTask, self).__init__()

    def run(self):
        wait_time = 5 / 100
        for i in range(100):
            self.cycle_changed.emit(i)
            sleep(wait_time)
            # use setProgress to report progress
            self.setProgress(i)
            # check isCanceled() to handle cancellation
            if self.isCanceled():
                return False

        self.cycle_changed.emit(100)
        return True


longtask = MyTask()
my_label_text = "Number of cycles : {0}    "
my_label = QLabel(my_label_text.format("0/100"))
font = my_label.font()
font.setPointSize(20)
my_label.setFont(font)

# here the task signal is connected to a lambda but this can be a function
longtask.cycle_changed.connect(lambda v: my_label.setText(my_label_text.format(f"{v}/100")))

my_label.show()
QgsApplication.taskManager().addTask(longtask)
4
  • I thank you for your reply but integrating this in a plugin is still unclear to me... How can I call the number of cycles count (the longtask) within a function defined in my_plugin_class thanks to a pushbutton ?
    – Linda
    Apr 22, 2022 at 11:12
  • @Linda: maybe open a new question with this one linked, to detail your need as it's a little bit different than this one. Apr 22, 2022 at 20:29
  • ok I'm opening a new one related to this
    – Linda
    Apr 25, 2022 at 9:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.