16 janvier 2014

Afficher en mode console un compteurs de progression

Pour debugger des programmes de type Batch, on utilise souvent la console. Quand on veut savoir ou en est un programme cela peut être utile. Quand ce programme boucle, afficher la progression ligne à ligne devient vite illisible.

Voici un exemple c# de code pour mettre en place un compteur de type : Traitement en cours 44 sur 123 et de faire bouger la valeur sans "polluer" l'affichage de la console.

Tout l'intérêt du truc est dans la méthode et les propriétés suivantes de l'objet Console :

  •    Console.SetCursorPosition(x, y) : Place le curseur en X, Y sur la console
  •   Console.CursorLeft : Renvoie la position X du curseur de la console
  •   Console.CursorTop : Renvoie la position Y du curseur de la console

Pour que cela fonctionne bien il faut s'assurer que la console ne scrolle pas = que l'affichage ne dépasse pas le nombre de lignes du buffer de la console. Dans ce cas, une solution est d'effacer la console avant d'utiliser le truc. Avec ce bout de code le tour est joué :
if (Console.CursorTop > Console.BufferHeight)
{
  Console.Clear();
}


Enjoy

 using System;

namespace ConsoleApplication1
{
  /// <summary>
  /// Programme de démo : pour afficher en mode console un ou plusieurs compteurs
  /// </summary>
  public class Program
  {
    /// <summary>
    /// Point d'entré du programme
    /// </summary>
    /// <param name="args">Les arguments de la ligne de commande</param>
    public static void Main(string[] args)
    {
      int max = 100000;
      Console.WriteLine("Programme de tests : pour afficher en mode console un ou plusieurs compteurs");
      Console.WriteLine();
      InfoCompteur pt = PrintCompteur("En cours : ", 0, max);
      Console.WriteLine();
      InfoCompteur pt2 = PrintCompteur("Traité : ", 0, max);
      Console.WriteLine();

      for (int i = 1; i <= max; i++)
      {
        PrintXY(pt, i);
        PrintXY(pt2, i);
       
        if ((i % 5000) == 0)
        { // Afficher du texte arbitrairement tout au long de la boucle
          Console.WriteLine("Coucou " + i.ToString());
        }
      }

      Console.WriteLine("--- Appuyez sur une touche pour quitter ---");
      Console.ReadKey();
    }

    /// <summary>
    /// Démarre un compteur de type : [txt] xxx sur yyy
    /// </summary>
    /// <param name="txt">Texte à afficher avant le compteur</param>
    /// <param name="value">Valeur initiale du compteur</param>
    /// <param name="count">Nombre d'éléments total</param>
    /// <returns>Les informations sur le compteur en cours à utiliser pour les prochains appels</returns>
    private static InfoCompteur PrintCompteur(string txt, int value, int count)
    {
      Console.Write(txt);
      int x = Console.CursorLeft;
      int y = Console.CursorTop;
      int le = count.ToString().Length;
      string fmt = string.Format("{{0,{0}}}", le);
      Console.Write(fmt, value);
      Console.WriteLine(" sur " + count.ToString());
      return new InfoCompteur(x, y, le);
    }

    /// <summary>
    /// Continue = affiche une nouvelle valeur pour un compteur de type : [txt] xxx sur yyy
    /// </summary>
    /// <param name="p">Les informations sur le compteur en cours</param>
    /// <param name="value">La nouvelle valeur</param>
    private static void PrintXY(InfoCompteur p, int value)
    {
      int x = Console.CursorLeft;
      int y = Console.CursorTop;

      Console.SetCursorPosition(p.X, p.Y);
      string fmt = string.Format("{{0,{0}}}", p.Size);
      Console.WriteLine(fmt, value);
      Console.SetCursorPosition(x, y);
    }

    /// <summary>
    /// Infos sur un compteur
    /// </summary>
    private class InfoCompteur
    {
      /// <summary>
      /// Initialise une nouvelle instance de la classe <see cref="InfoCompteur" />.
      /// </summary>
      /// <param name="x">Coordonnée X du curseur</param>
      /// <param name="y">Coordonnée Y du curseur</param>
      /// <param name="size">Taille du champ compteur</param>
      public InfoCompteur(int x, int y, int size)
      {
        this.X = x;
        this.Y = y;
        this.Size = size;
      }

      /// <summary>
      /// Coordonnée X du curseur
      /// </summary>
      public int X { get; set; }

      /// <summary>
      /// Coordonnée Y du curseur
      /// </summary>
      public int Y { get; set; }

      /// <summary>
      /// Taille du champ compteur
      /// </summary>
      public int Size { get; set; }
    }
  }
}

Aucun commentaire:

Enregistrer un commentaire