5

I'm trying to test the new QgsTask and QgsTaskManager, I found some examples in the PullRequest in github. I modified it slightly and added a print(i) in the code bellow:

from qgis.core import QgsTask, QgsTaskManager
from time import sleep
import random
def run1(task,time):
   wait_time = time / 100.0
   sum = 0
   iterations = 0
   for i in range(101):
       sleep(wait_time)
       print(i)
        # use task.setProgress to report progress
        task.setProgress( i )
        sum += random.randint(0,100)
        iterations += 1
        # check task.isCancelled() to handle cancellation
        if task.isCancelled():
            stopped()
            return
        # raise expections to abort task
        #if random.randint(0,100) == 7:
        #    raise Exception('bad value!')
    # use task object to store results of calculations or operations
    task.result = [sum,iterations]

task=QgsTask.fromFunction('waste cpu', run1, 2)
mgr=QgsTaskManager()
mgr.addTask(task)
task.isFinished()

When I run this code in the Python console it returns 0 two times and then nothing more. I expected 101 printouts (0-100)? Afterwards I tried to see if it was finished with trying to call task.isFinished(), hence that gave me a RuntimeError: wrapped C/C++ object of type QgsTaskWrapper has been deleted.

In the end I would like use one QgsTask to run a time consuming script and one QgsTask to run a dialog (maybe a progressbar) telling the user that script is still running..

Any suggestion what I'm doing/thinking wrong or were to look at other examples?

EDIT: The problem was not only that there was two "L" in isCancel and start of QgsTaskManager, it was also that I tried to use print() within QgsTask. So I tried another approach with two GUIs that I tried in this repo.

EDIT: I updated the github Master repo using a QtTimer, still no 100% success, hence the branch without QgsTask is working as expected. But I really want to understand how QgsTask is to be implemented..

2 Answers 2

4

There's a typo in that script - it should be isCanceled() (one l, not two)

You should also add your task to the global task manager instead of creating a new manager:

QgsApplication.taskManager().addTask(task)

One thing to be very careful about is never to create widgets or alter gui in a task. This is a strict Qt guideline - gui must never be altered outside of the main thread. So your progress dialog must operate on the main thread, connecting to the progress report signals from the task which operates in the background thread.

4
  • Allright, printing was altering in the main thread causing the qgis to crash when I edited as you suggested. So I updated my question with another example..
    – axel_ande
    Feb 28, 2018 at 13:17
  • I've tried now for some time to get a basic GUI to run two subwindows, hence I miss something, the program works as expected when I do not use the QgsTask, In the Master branch is QgsTask used and in the branch Without_QgsTask it is not and working... github.com/axelande/QgisTest
    – axel_ande
    Mar 10, 2018 at 7:12
  • Hi, Nyall, I've been using QgsTask for some time now and I have to say the function is really nice! Hence I haven't figured out how to fetch errors happening in the task? I found the task.taskTerminated and connected it to a function.. But I don´t know what to print in order to get the error?
    – axel_ande
    Jun 21, 2018 at 7:34
  • There's no generic error message handling built in - you need to implement something yourself (eg. make a "errorOccurred" signal which is thrown by your task when an error occurs)
    – ndawson
    Jun 21, 2018 at 8:21
1

I kind of made it :) I can run this once, hence when I tries to do it a second time it fails and I need to print(1) in run_counting. The project is uploaded to https://github.com/axelande/QgisTest

def run_counting(self):
    counting = int(self.dlg.LESeconds.text())
    counting_test = CountingTest()
    task1 = QgsTask.fromFunction('counting', counting_test.run_count,
                                 counting,
                                 on_finished=self.stop_from_counting)
    waiting_msg = WaitingMsg()
    task2 = QgsTask.fromFunction('waiting', waiting_msg.run)
    self.tsk_mngr.addTask(task1)
    print(1) #This is required but I don't know why?
    self.tsk_mngr.addTask(task2)

The classes CountingTest and WaitingMsg requires a sleep that is longer than the QtTimer timer.

class WaitingMsg(QtWidgets.QDialog, FORM_CLASS):
    def __init__(self, parent=None):
        """Constructor."""
        super(WaitingMsg, self).__init__(parent)
        self.setupUi(self)
        self.cancel_is_set = False
        self.task = None
        self.my_timer = None

    def set_cancel(self):
        if self.task.isCanceled():
            self.done(0)

    def run(self, task):
        self.task = task
        self.show()
        self.my_timer = QtCore.QTimer(self)
        self.my_timer.timeout.connect(self.set_cancel)
        self.my_timer.start(500)  # 1 sec intervall
        sleep(.6)
        self.exec_()
        self.done(0)

class CountingTest(QtWidgets.QDialog, FORM_CLASS):
    def __init__(self, parent=None):
        """Constructor."""
        super(CountingTest, self).__init__(parent)
        self.setupUi(self)
        self.my_timer = None
        self.task = None
        self.counting = None
        self.t0 = None

    def _update_text(self):
        tid = int(time() - self.t0)
        self.LSeconds.setText(str(tid))
        self.update()
        if tid == self.counting:
            self.done(0)
            return self.counting

    def run_count(self, task, counting):
        self.counting = int(counting)
        print(counting)
        self.t0 = time()
        self.task = task
        self.show()
        self.my_timer = QtCore.QTimer(self)
        self.my_timer.timeout.connect(self._update_text)
        self.my_timer.start(1000)  # 1 sec interval
        sleep(1.1)
        self.exec_()
        self.done(0)
        return counting

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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