Sur cette page

Démonstration de TaskTree

Illustre comment les différents modes d'exécution et politiques de workflow influencent l'exécution d'un TaskTree complexe.

La démo TaskTree montre comment construire une recette TaskTree imbriquée à l’aide de timeoutTask, et présente différentes execution modes et workflow policies. Son application offre une vue d’ensemble graphique de la progression au fur et à mesure que le TaskTree exécute les différents éléments de travail composant la tâche.

Groupes de tâches imbriqués avec des statuts identifiés par des codes couleur, indiquant une progression de 78 %

L’application de démonstration utilise un seul QWidget pour afficher et gérer une hiérarchie TaskTree. Voici ce que vous trouverez dans l’interface :

  • Les tâches apparaissent sous forme de nœuds feuilles sur le côté droit de l’arborescence.

    Pour chaque tâche, vous pouvez définir la durée d’exécution et configurer les états de réussite ou d’échec.

  • Les nœuds de groupe apparaissent à gauche et au milieu de l'arborescence.

    Chaque groupe peut contenir plusieurs tâches enfants ou des groupes imbriqués. Vous pouvez configurer les paramètres « execution modes » et « workflow policies » pour chaque groupe.

  • Des indicateurs de couleur indiquent l’état d’exécution actuel de chaque nœud.

Les sections suivantes décrivent plus en détail le code de l’exemple.

Classes auxiliaires de liaison

La classe abstraite ` GlueItem ` relie les composants de l’interface utilisateur (UI) à leurs recettes `TaskTree` correspondantes. Ce modèle de conception permet une séparation claire entre l’interface utilisateur et la logique des tâches.

class GlueItem
{
public:
    virtual ExecutableItem recipe() const = 0;
    virtual QWidget *widget() const = 0;
    virtual void reset() const = 0;

    virtual ~GlueItem() = default;
};

La classe ` GlueItem ` définit trois méthodes virtuelles clés :

MéthodeObjectif
recipe()Crée et renvoie une recette TaskTree qui définit le comportement de l'élément
widget()Permet d’accéder au composant UI associé
reset()Rétablit le composant d'interface utilisateur à son état initial

La classe ` GroupGlueItem ` gère les éléments ` Group ` dans votre hiérarchie de tâches. Chaque groupe peut contenir d’autres éléments ` GlueItem ` en tant qu’enfants, y compris des ` GroupGlueItem` ou des ` TaskGlueItem` imbriqués.

Voici comment la méthode recipe() crée et configure un groupe :

ExecutableItem GroupGlueItem::recipe() const
{
    GroupItems childRecipes;
    for (GlueItem *child : m_children)
        childRecipes.append(child->recipe());

    return Group {
        m_groupWidget->executeModeItem(),
        m_groupWidget->workflowPolicyItem(),
        onGroupSetup([this] { m_groupWidget->setState(State::Running); }),
        childRecipes,
        onGroupDone([this](DoneWith result) { m_groupWidget->setState(resultToState(result)); })
    };
}

Composants clés de l’implémentation :

  • Crée un nouveau « Group » avec des recettes enfants
  • Applique les paramètres « execution mode » et « workflow policy » issus des paramètres de l’interface utilisateur
  • Utilise la méthode ` onGroupSetup()` pour mettre à jour l’interface utilisateur au début de l’exécution
  • Utilise ` onGroupDone()` pour afficher les résultats d’exécution dans l’interface utilisateur

La classe ` TaskGlueItem ` implémente les nœuds feuilles dans votre arborescence de tâches à l’aide de ` timeoutTask`.

Voici l’implémentation de recipe() qui crée la tâche :

ExecutableItem TaskGlueItem::recipe() const
{
    return Group {
        onGroupSetup([this] { m_taskWidget->setState(State::Running); }),
        timeoutTask(seconds(m_taskWidget->busyTime()), m_taskWidget->desiredResult()),
        onGroupDone([this](DoneWith result) { m_taskWidget->setState(resultToState(result)); })
    };
}

L’implémentation :

  • Crée un objet ` Group ` qui encapsule un timeoutTask
  • Utilise les paramètres de l’interface utilisateur pour configurer la durée et le résultat attendu
  • Met à jour l’état de l’interface utilisateur lorsque la tâche commence via ` onGroupSetup()`
  • Reflète l'état d'achèvement de la tâche via ` onGroupDone()`

Construire la hiérarchie des tâches

Deux méthodes d’aide simplifient la création d’arborescences de tâches :

static GlueItem *group(const GroupSetup &groupSetup, const QList<GlueItem *> children)
{
    return new GroupGlueItem(groupSetup, children);
}

static GlueItem *task(int busyTime = 1, DoneResult result = DoneResult::Success)
{
    return new TaskGlueItem(busyTime, result);
}
  • group(): Crée une nouvelle GroupGlueItem
  • task(): Crée un nouvel TaskGlueItem

Définition de la structure arborescente

Le code suivant montre comment construire une hiérarchie complète de tâches :

    std::unique_ptr<GlueItem> tree {
        group({WorkflowPolicy::ContinueOnSuccess}, {
            group({}, {
                task(),
                task(2, DoneResult::Error),
                task(3)
            }),
            task(),
            task(),
            group({WorkflowPolicy::FinishAllAndSuccess}, {
                task(),
                task(),
                group({WorkflowPolicy::StopOnError, ExecuteMode::Parallel}, {
                    task(4),
                    task(2),
                    task(1),
                    task(3, DoneResult::Error)
                }),
                task(2),
                task(3)
            }),
            task()
        })
    };

Vous pouvez modifier la construction ci-dessus pour créer différentes structures arborescentes.

Connexion de l'interface utilisateur à TaskTree

La dernière étape consiste à relier l'arborescence des tâches aux contrôles de l'interface utilisateur de l'application :

    QSingleTaskTreeRunner taskTreeRunner;

    const auto resetTaskTree = [&] {
        taskTreeRunner.reset();
        tree->reset();
        progressBar->setValue(0);
        cancelButton->setEnabled(false);
    };

    const auto cancelTaskTree = [&] { taskTreeRunner.cancel(); };

    const auto startTaskTree = [&] {
        resetTaskTree();
        cancelButton->setEnabled(true);

        const auto onTaskTreeSetup = [progressBar](QTaskTree &taskTree) {
            progressBar->setMaximum(taskTree.progressMaximum());
            QObject::connect(&taskTree, &QTaskTree::progressValueChanged,
                             progressBar, &QProgressBar::setValue);
        };

        const auto onTaskTreeDone = [cancelButton] { cancelButton->setEnabled(false); };

        taskTreeRunner.start({tree->recipe()}, onTaskTreeSetup, onTaskTreeDone);
    };

    QObject::connect(startButton, &QAbstractButton::clicked, &app, startTaskTree);
    QObject::connect(cancelButton, &QAbstractButton::clicked, &app, cancelTaskTree);
    QObject::connect(resetButton, &QAbstractButton::clicked, &app, resetTaskTree);

    mainWidget.show();

    return app.exec();

Ce code :

  • Crée un QSingleTaskTreeRunner pour exécuter l'arborescence des tâches
  • Configure les gestionnaires pour les boutons Démarrer, Annuler et Réinitialiser
  • Relie la barre de progression pour suivre l'exécution des tâches

Exécution de l'exemple

Vous pouvez exécuter l'exemple à partir de :

Exemple de projet sur code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.