5.10.contrôler le flux d’exécution
Applications en Delphi & V-Basic






Plan du chapitre:

1. Le contrôle de l’exécution en Delphi ...
 

    1.1 le contrôle par les instructions structurées
    1.2 le contrôle par des procédures
    1.3 le contrôle par la fiche principale
    1.4 le contrôle par la variable Application
    1.5 le contrôle par le timing


2. Exemples de contrôle de l’exécution en Delphi ...
 

    2.1 le contrôle par ProcessMessages


3. Le contrôle de l’exécution en Visual Basic ...
 

    3.1 les structures de contrôle
      Les structures de décision
      Les fonctions de sélection
      Les structures de boucle
    3.2 utilisation des structures de contrôle
      Structures de contrôle imbriquées
      Sortie d'une structure de contrôle
      Sortie d'une procédure sub, fonction, ou property
    3.3 le contrôle par le timing
    3.4 arrêt d'une application


4. Exemple de contrôle de l’exécution en Visual Basic ...
 

    4.1 le contrôle par DoEvents
    4.2 conclusion
     


 

1. Le contrôle de l’exécution en Delphi

Les programmes s’exécutent séquentiellement jusqu'à leur fin normale. Le programmeur peut vouloir arrêter, interrompre temporairement, mettre en attente, ou sauter l’exécution de portions de code. Cette opération se définit comme le contrôle du flux d’exécution. Nous pouvons, sans entrer dans des détails de bas niveau inutiles pour le débutant, indiquer de quels moyens nous disposons pour contrôler ce flux.
 
 

1.1 le contrôle par les instructions structurées

Le premier niveau de contrôle de l’exécution que découvre l’étudiant, se situe dans la méthodologie de conception structurée descendante.

    La programmation structurée contient en elle-même une variété de mécanismes de contrôle du flux d’exécution avec par exemple ses instructions de boucles (while..., repeat..., for...) permettant de ré-exécuter plusieurs fois la même portion de code. L’instruction conditionnelle (if ... then ... else ...) et le case ... of, autorisent par sélection l’exécution ou la non exécution de portions de code.
     
     

    1.2 le contrôle par des procédures

    La conception structurée par bloc donne le pouvoir aux procédures et aux fonctions de n’être exécutées que lorsque le programmeur décide de les " appeler ".

    Il existe en Delphi des procédures spéciales destinées uniquement au contrôle du flux d’exécution.
     
    Procedure Break ;

    Procedure Exit ;

    Procedure Halt ;

    Description :

    La procédure Break, qui doit obligatoirement se trouver dans le corps d’une boucle while, for, repeat, fait quitter le flux de contrôle d'une instruction while, for, repeat, et poursuit l’exécution à la prochaine instruction qui suit l'instruction de boucle.

    La procédure Exit se trouve obligatoirement dans une procédure ou dans une fonction ; elle fait passer le contrôle du flux d'exécution en dehors de la procédure. Si la procédure en cours est le programme principal, Exit termine l'exécution du programme. Exit continue la poursuite de l’exécution dans la procédure appelante avec l'instruction qui suit celle qui a appelé la procédure contenant le Exit.

    La procédure Halt met fin volontairement à l’exécution d'un programme et renvoie le contrôle au système d'exploitation.

    (Mentionnons aussi dans ce cadre les procédures Continue et RunError)
     
     

    1.3 le contrôle par la fiche principale
     
    Méthode Close

    Utilisation de la méthode Close pour fermer une fiche et le code associé.

    Si la fermeture est possible, l'événement OnClose a lieu. Si la fiche est la fiche principale de l'application, la méthode Close termine l'application.
     

    Exemple avec une seule fiche Form1 (donc principale) :

    Delphi.Close.dlfi
     

    Le gestionnaire du bouton termine l’application
    procedure TForm1.Button1Click(Sender: TObject); 
    begin
       Form1.Close 
    end
     

     

    1.4 le contrôle par la variable Application

    A chaque fois que nous écrivons un programme en Delphi (nommé un projet), il lui est associé lors de l’exécution un objet non visible nommé Application qui encapsule tout notre programme. Il est possible d'exploiter cet objet Application pour récupérer des informations concernant l'application en cours d'exécution.
     
    var Application: TApplication

    Comme toutes les classes, la classe TApplication possède des méthodes et des événements. Nous utilisons ici deux méthodes permettant d’interrompre le flux d’exécution de notre application.
     
    Méthode Terminate

    La méthode Terminate appelle la fonction PostQuitMessage de l'API Windows pour effectuer la fermeture de l'application. PostQuitMessage est une fonction de l'API windows qui signale au système qu'un thread a introduit une requête de terminaison.
     
     
    Méthode ProcessMessages

    La méthode ProcessMessages interrompt l'exécution de l'application pour que Windows puisse répondre aux événements présents dans la file d’attente de Windows. La méthode ProcessMessages interrompt le code qui l’a lancée pour parcourir la file d’attente des messages Windows jusqu'à ce que cette file soit vide, puis rend le contrôle du flux d’exécution à l'application.

    Nous allons voir plus loin des exemples de tels contrôles. Pour l’instant terminons ce petit tour d’horizon avec un dernier outil faisant intervenir l’horloge interne de l’ordinateur et la notion de temps.
     
     

    1.5 le contrôle par le timing

    Le programmeur peut vouloir interrompre son flux d’exécution non pas pour aller faire exécuter des messages venant d’ailleurs, mais tout simplement afin de temporiser des affichages ou des traitements. Dans un ordinateur, tout s’exécute à la vitesse de traitement des instructions, vitesse qui reste la même pour une instruction donnée. Il est clair que le souci de " ralentir " l’exécution du code est plus lié à la communication dans l’interface plutôt qu’au traitement interne des données qui souvent a besoin d’être accéléré.

Delphi met à notre service une classe non visuelle permettant d’effectuer du séquencement de temps. La classe Ttimer
 

Elle possède deux propriétés intéressantes :
property Enabled: Boolean;
property Interval: Cardinal;

Elle est sensible à un seul événement :
property OnTimer: TNotifyEvent;

  • Enabled détermine si l’objet Ttimer répond à l’événement OnTimer.
  • Interval définit l'intervalle de temps, exprimé en millisecondes, s'écoulant avant que le composant Ttimer génère un autre événement OnTimer.
  • Un objet Timer de la classe Ttimer est utilisé pour faire exécuter le code contenu dans le gestionnaire de son unique événement OnTimer d’une façon périodique. L’événement OnTimer se produit quand le temps spécifié par la propriété Interval s'est écoulé.

  • Exemple

    Delphi.Timer.dlfi
     
     
    var Changer :boolean ;

    Timer1.Interval := 250; // 250 ms
    Timer1.Enabled := true;
    Changer :=true ; 

    On veut faire clignoter le fond de Edit1 alternativement
    du bleu au rouge toutes les 250 ms.

    Le gestionnaire de l’événement OnTimer lancé toutes les 250 ms:
    procedure TForm1.Timer1Timer(Sender: TObject); 
    begin
     if Changer then begin
       Edit1.color :=clblue ; 
       Changer :=false  // change alternativement de valeur
     end
     else begin
      Edit1. color :=clRed ; 
      Changer :=true  // change alternativement de valeur 
     end
    end

     
     
     

    2. Exemples de contrôle de l’exécution
     
     

    2.1 le contrôle par ProcessMessages
     

    Soit l’interface suivante :  Delphi.ProcessMessages\MessageBoucles
     
    Les boutons servent à lancer,interrompre, reprendre ou arrêter définitivement l’ exécution de la boucle :

    for i:=1 to 2000 do...

    qui affiche dans le Memo1 la valeur de l’indice i.

    Edit1 contient le n° du "i" lors de l’appui sur Interrompre.
     

    Edit2 contient le n° du "i" lors de l’appui sur Arrêter.


     

    Code proposé pour ce contrôle de flux :
     

    procedure TForm1.ButtonArretClick(Sender: TObject);
    begin
     FlagStop:=true; // flag levé
    end;
    procedure TForm1.ButtonInterruptClick(Sender: TObject);
    begin
     FlagInterrupt:=true; // flag levé
    end;
    procedure TForm1.ButtonrepriseClick(Sender: TObject);
    begin
     FlagInterrupt:=false; // flag baissé
    end;
    procedure TForm1.ButtonLancerClick(Sender: TObject);
    var i:integer;
    begin
     RAZTout;
     for i:=1 to 2000 do begin
      Memo1.lines.add(inttostr(i));
      Application.ProcessMessages;
      if FlagStop then begin
       Edit2.text:='Arrêt demandé: '+inttostr(i);
       FlagStop:=false;
       Exit
      end;
      if FlagInterrupt thenbegin
       Edit1.text:='Interruption: '+inttostr(i);
       Repeat
         Application.ProcessMessages;
       until (FlagInterrupt=false)or(FlagStop=true) ;
      end
     end;
     Edit1.text:='Fin de la boucle '
    end;

     

    2.2 Quelques explications sur le code 

    La structure générale de la boucle est la suivante :
     
    for i:=1 to 2000 dobegin
      Memo1.lines.add(inttostr(i));
      Application.ProcessMessages;
      if FlagStop then ... ;
      if FlagInterrupt then ... ;
    end ;

    L’appel à la méthode ProcessMessages libère le système en lui donnant " la main " par interruption de la boucle (le temps au système de traiter les messages en suspens comme clic de souris, clavier etc...). Si pendant l’interruption l’utilisateur n’a rien fait, la boucle continue. Si par contre l’utilisateur a clické sur le ButtonInterrupt, le système a alors eu le temps de faire exécuter (pendant l’interruption de la boucle) le gestionnaire ButtonInterruptClick qui a mis le FlagInterrupt à true. Lorsque la boucle reprend (après la fin du traitement des messages) l’instruction if FlagInterrupt then ... déroute l’exécution dans l’instruction composée qui suit le then.
     

    Il en est de même lorsque l’utilisateur a cliqué sur le ButtonArret le système a eu le temps de faire exécuter (pendant l’interruption de la boucle) le gestionnaire ButtonArretClick et a mis le FlagStop à true. Lorsque la boucle reprend (après la fin du traitement des messages) l’instruction if FlagStop then ... déroute l’exécution dans l’instruction composée qui suit le then.
     

    Traitement après le clic sur ButtonArret:
    if FlagStop then begin
      Edit2.text:='Arrêt demandé: '+inttostr(i);
      FlagStop:=false;
      Exit
    end;

    L’appel à la procédure Exit fait sortir du gestionnaire qui l’a appelé en l’occurrence la procedure TForm1.ButtonLancerClick.
     

    Traitement après le click sur ButtonInterrupt:
    if FlagInterrupt thenbegin
      Edit1.text:='Interruption: '+inttostr(i);
      repeat
        Application.ProcessMessages;
      until (FlagInterrupt=false)or(FlagStop=true) 
    end;

    Nous avons remis une boucle repeat...until qui semble être une boucle infinie, mais qui n’en est pas une (c’est une façon très classique de procéder dans ce genre de cas). Cette boucle bloque le flux d’exécution de ce programmme, mais ne bloque pas le traitement des messages systèmes par l’appel à la méthode ProcessMessages.

    Nous allons profiter du fait que l’utilisateur peut pendant que la boucle repeat...until s’exécute, cliquer soit sur le ButtonArret, soit sur le Buttonreprise. Dans l’éventualité d’un tel clic, l’un des deux flags FlagInterrupt ou FlagStop est modifié ce qui a pour effet de sortir de la boucle " infinie " repeat...until.

    Si l’utilisateur a cliqué sur le Buttonreprise, la boucle for continue son exécution comme précédemment.

    Si l’utilisateur a cliqué sur le ButtonArret, la boucle for continue son exécution pour un tour seulement jusqu'à l’instruction if FlagStop then... qui met fin à l’exécution de cette boucle.
     

    Etudiez  l’exemple comportant deux fiches dans :

    Delphi.ProcessMessages\Message2fiches
     
     
     

    3. Le contrôle de l’exécution en Visual Basic
     

    3.1. Présentation des structures de contrôle
     
    Les structures de décision
    Les fonctions de sélection
    Les structures de boucle

    Les structures de contrôle permettent de contrôler le déroulement de l'exécution d'un programme. Si elle n'est pas vérifiée par des instructions de contrôle du déroulement, la logique d'un programme parcourt ces instructions de gauche à droite, de haut en bas de manière séquentielle. La puissance et l'utilité même d'un langage de programmation orienté objet découlent de sa capacité à modifier l'ordre des instructions par des structures et des boucles.
     

    Les structures de décision
     
     
    Instruction If...Then

    La structure If...Then permet d'exécuter une ou plusieurs instructions si certaines conditions sont remplies. On peut utiliser une syntaxe monoligne :
     
    Ifcondition
    Then instruction

    ou une syntaxe multiligne en blocs :
     
    Ifcondition
    Then instructions
    End If 

     
     
     
    Instruction If...Then..Else

    Le bloc If...Then...Else permet de définir plusieurs blocs d'instructions dont un seul est exécuté :
     
    Ifcondition1
    Then [instruction block-1]
    [ElseIf condition2
    Then [instruction block-2]]... 
    [Else [instruction block-n]]

    End If


     
     
     
    Instruction Select Case

    Une instruction Select Case assure des fonctionnalités similaires à celles de l'instruction If...Then...Else, mais améliore la lisibilité du code en présence de choix multiples. Une structure Select Case n'utilise qu'une seule expression de test qui est évaluée une seule fois, au début de la structure. Visual Basic compare ensuite le résultat de cette expression aux valeurs de chaque clause Case de la structure. Si les valeurs concordent, il exécute le bloc d'instructions associé à cette clause Case :
     
    Select Case expression
    [Caseexpression1 [instruction block-1]]

    [Case expression2 [instruction block-2]]. . .

    [Case Else [instruction block-n]]

    End Select

     

    Les fonctions de sélection

    Les 3 instructions suivantes sont issues du macrolangage VBA. Ce ne sont pas des structures de décision à proprement parlé, mais elles constituent quand même des outils de décision.
     
     
    fonction IIf (...)

    IIf évalue une expression et, selon la valeur logique prise par cette expression, affecte une valeur ou une autre à une variable :
     
    Valeur = IIf (expression, ValeurSiVrai, ValeurSiFaux)

    Les 2 tableaux de lignes de code suivants sont identiques, quant au résultat :
     
    Dim x as integer

    Dim y as integer

    ...

    If x > 100 then

    y = 1
    Else
    y = 10
    End If
    Dim x as integer

    Dim y as integer

    ...

    y% = IIf ( x% > 100 , 1 , 10 )
     
     
     
     
     
     

     


     
     
     
    fonction Choose (...)

    Choose sélectionne et renvoie une valeur dans une liste d'arguments :
     
    Valeur = Choose ( Index , sélection1 [, selection2 , ... [, sélectionN]])

    Les 2 tableaux de lignes de code suivants sont identiques, quant au résultat :
     
    Dim A as String

    ...

    Select Case Index

    Case 1

    A = "Rouge"
    Case 2
    A = "Vert"
    Case 3
    A = "Bleu"
    Case Else
    A = ""
    End Select
    Dim A as String

    ...

    A = Choose (Index, "Rouge", "Vert", "Bleu")
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     

     


     
     
     
    fonction Switch (...)

    Switch évalue une liste de conditions et renvoie la valeur ou l'expression correspondant à la première condition remplie:
     
    Valeur = Switch (Expression1, Valeur1 [,Expression2, Valeur2] ... [,ExpressionN, ValeurN])

    Ainsi, les 2 tableaux de lignes de code suivants sont identiques, quant au résultat :
     
    Dim Couleur as String

    Dim A as Integer

    ...

    If Couleur = "Rouge" Then

    A = 1 
    ElseIf Couleur="Vert" Then
    A = 2
    ElseIf Couleur="Bleu" Then
    A = 3
    End If
    Dim Couleur as String

    Dim A as Integer

    ...

    A = Switch (Couleur = "Rouge", 1, _ 

    Couleur="Vert", 2, _

    Couleur="Bleu", 3)


     
     
     
     
     
     

     


     

    Les structures de boucle
     
    Instruction Do..Loop

    La boucle Do permet d'exécuter un bloc d'instructions un nombre infini de fois. Il existe plusieurs variantes de l'instruction Do...Loop, mais elles évaluent chacune une condition numérique pour déterminer si l'exécution doit être poursuivie.

    Dans les boucles Do...Loop suivantes, les instructions sont exécutées aussi longtemps que 'condition' est True (boucle do while) ou False (boucle dountil) :
     
    Do Whilecondition

    instructions

    Loop 

    Do Untilcondition

    instructions

    Loop

    Une autre variante de l'instruction Do...Loop exécute tout d'abord les instructions, puis teste la condition après chaque exécution. Cette variante garantit au moins une exécution de 'instructions' :
     
    Do 

    instructions

    Loop While condition

    Do

    instructions

    Loop Until condition


     
     
     
    Instruction For..Next

    Contrairement à la boucle Do, la boucle For inclut une variable appelée compteur dont la valeur augmente (ou diminue) à chaque itération de la boucle :
     
    Forcompteur = début To fin [Step increment]

    instructions

    Next [compteur ]


     
     
    Instruction For..Each

    Une boucle For Each...Next est semblable à une boucle For...Next, à la différence toutefois qu'elle répète un groupe d'instructions pour chaque élément d'une collection d'objets ou d'un tableau, plutôt que de répéter les instructions un certain nombre de fois. Cette boucle est utile lorsque l'on ne connaît pas le nombre d'éléments d'une collection (groupe d'objets par exemple) :
     
    For Each element In groupe

    instructions

    Next element


     

     
    3.2 utilisation des structures de contrôle
     
     
    Structures de contrôle imbriquées
    Sortie d'une structure de contrôle
    Sortie d'une procédure sub, fonction, ou property

    Structures de contrôle imbriquées

    Il est possible de placer des structures de contrôle au sein d'autres structures de contrôle (un bloc If...Then au sein d'une boucle For...Next, par exemple).

    Le nombre de niveaux d'imbrication dans les structures de contrôle est illimité en Visual Basic. L'imbrication permet de représenter des structures de décision ou des structures en boucle de manière plus lisible en mettant en retrait le corps de la structure de décision ou de la boucle.

    Dans les instructions If imbriquées, les instructions End If s'appliquent automatiquement à l'instruction If précédente la plus proche. Les structures Do...Loop fonctionnent de façon similaire, l'instruction Loop la plus imbriquée correspondant à l'instruction Do la plus imbriquée.
     

    Sortie d'une structure de contrôle
     
     
    Instruction Exit

    L'instruction EXIT permet de sortir directement d'une boucle For ou Do, ou encore d'une procédure Sub, Function ou Property.

    La syntaxe de l'instruction Exit est simple : Exit For peut apparaître autant de fois qu'il est nécessaire à l'intérieur d'une boucle For, et il en est de même pour Exit Do dans une boucle Do :
     
    For compteur = début To fin [Step increment]

    instructions

    [Exit For]

    instructions

    Next element

    Do [{While | Until} condition]

    instructions

    [Exit Do

    instructions

    Loop


     

    Remarque
    L'instruction Exit Do fonctionne avec toutes les versions de la syntaxe de la boucle. Une instruction Exit apparaît presque toujours dans une instruction If ou Select Case imbriquée dans la boucle.

     

    Sortie d'une procédure sub, fonction, ou property

    Il est possible de quitter une procédure à partir d'une structure de contrôle.
     
    La syntaxe de Exit Sub, Exit Function et de Exit Property est semblable à celle de Exit For et de Exit Do.
    Exit Sub, ExitFunction et Exit Property peuvent apparaître autant de fois qu'il le faut dans le corps de la procédure. L'exécution se poursuit par l'instruction suivant celle qui a appelé la propriété.

     
     
     

    3.3 le contrôle par le timing

    Pour temporiser l'affichage ou les traitement de son application, le programmeur peut utiliser la classe non visuelle fournit par VB6 :

    La classe Timer : 

    Elle dispose de 2 propriétés principales et n'est sensible qu'à un seul évènement :
     
    Propriété : 

    Enabled

    Renvoie ou définit une valeur qui détermine si une feuille ou un contrôle peuvent répondre aux événements générés par l'utilisateur.
    Propriété : 

    Interval

    Renvoie ou définit le nombre de millisecondes s'écoulant entre deux appels de l'événement Timer d'un contrôle Timer. 
    Evènement : 

    Timer

    Se produit lorsque l'intervalle prédéfini pour un contrôle Timer est écoulé. La fréquence de l'intervalle est stockée dans la propriété Interval du contrôle et spécifie une durée en millisecondes.

     

    Exemple :

    Le fond de Text1 clignote alternativement du jaune au blanc, toutes les 250 ms.