[TUTO] Barre de chargement et Mélanger des valeurs

Informations pour bien débuter en PureBasic
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

[TUTO] Barre de chargement et Mélanger des valeurs

Message par Le Soldat Inconnu »

Salut,

Juste un petit tuto pour montrer comment faire une barre de chargement.

Mon exemple est basé sur un code qui va mélanger une liste de valeur contenu dans une liste chainée.

La barre de chargement :
La première chose à ne pas perdre de vue est qu'un chargement n'est pas la pour faire joli :)
Sa fonction est de faire patienter pendant une opération longue.
Par exemple :
- Le chargement de fichiers volumineux
- Des calculs préliminaires. Ils est parfois utile pour optimiser un code de délocaliser un calcul complexe hors de la boucle et de stocker les résultats dans une liste chainée ou un tableau. Un bon exemple est celui d'une fonction F(x) très complexe dont les seul valeur utilisée sont comprises entre 0 et 1000 (en valeurs entières). Le cacul de chaque valeur peut être fait avant la boucle du programme ce qui optimise la vitesse de votre code.
- etc ...

Mélanger des valeurs
Le principe que j'utilise est différent d'un Random(), il ne s'agit pas générer des valeurs aléatoires mais de mettre des valeurs dans le désordre.
Ceci peut-être utile par exemple pour mélanger un jeux de carte.
On a une liste d'élement définis et on veut mettre ces éléments dans le désordre.
Cette façon de faire n'est certainement pas unique. Si vous avez une autre méthode, poster la :wink:

Le code :

Code : Tout sélectionner

Ecran_Largeur = 200 ; dimension de la fenêtre
Ecran_Hauteur = 100

;{- On crée la fenêtre
If OpenWindow(0, 0, 0, Ecran_Largeur, Ecran_Hauteur, #PB_Window_BorderLess | #PB_Window_ScreenCentered, "LSI") = 0
  End
EndIf
;}

;{- On ouvre l'openscreen
If InitSprite() = 0
  MessageRequester("Erreur", "Impossible d'initialiser la souris ,le clavier ou l'écran. Vérifiez la présence de DirectX 7 ou supérieur.", 0)
  End
EndIf

If OpenWindowedScreen(WindowID(), 0, 0, Ecran_Largeur, Ecran_Hauteur, 1, 0, 0) = 0
  MessageRequester("Erreur", "Impossible d'ouvrir l'écran.", 0)
  End
EndIf

; Premier affichage
ClearScreen(0, 0, 0)
FlipBuffers()

;}

; Dans cet exemple, je vais chargé une liste avec des valeur de 1 à 5000 et je vais les mettre dans le désordre
; Cette action est différente d'un Random(5000) car j'obtiens toute les valeurs de 1 à 5000 dans le désordre

;- On charge une liste de points
NewList Temp_Liste.l()
NewList Liste.l()

For n = 1 To 5000 ; on rempli la liste chainée avec des valeur de 1 à 5000
  AddElement(Temp_Liste())
  Temp_Liste() = n
Next

;- On met les points dans le désordre
NbTotal = CountList(Temp_Liste()) ; On compte le nombre d'élément de la liste
Nb = NbTotal ; Les variables n et Nb vont servir pour la boucle
n = NbTotal

; Si j'avais effectué cette action normalment, je n'aurai mis qu'une boucle de 1 à 5000 car j'ai 5000 point à mettre dans le désordre
; Mais je veux afficher une barre de chargement
; Faire un affichage à chaque tour de boucle est trop gourmand (5000 affichage à 50 image/s donne 100 secondes alors que le chargement prend 1 secondes sans affichage)
; Je découpe donc ma bouble en plusieurs morceau et au milieu de ces morceaux, je fais de l'affichage
; Les boucles repeat until situé ci-dessous ont ce but

Repeat ; Boucle d'affichage
  n - 200
  
  Repeat ; Boucle de traitement
  
    ; Cette partie du code permet de mettre les valeurs dans le désordre.
    Nb - 1 ; Je décompte un élément car je vais le traité ci-dessous
    AddElement(Liste()) ; J'ajoute un élement dans la liste final
    SelectElement(Temp_Liste(), Random(Nb)) ; Je choisit un élément au hazard dans la liste temporaire
    Liste() = Temp_Liste() ; Je le copie dans la liste final
    DeleteElement(Temp_Liste()) ; Je supprime cet élément de la liste temporaire
    
  Until Nb = 0 Or Nb < n ; On quitte cette boucle tous les 200 ou dès qu'il n'y a plus d'élément
  ; Le compteur n me sert à sortir de la boucle de traitement pour passer à la boucle d'affichage
  ; Quand je fais n - 200 plus haut, il faut attendre que nb est chuté de 300 pour sortir de la boucle de traitement
  ; 200 est en fait la fréquence de rafraichissement de la barre de progression
  ; Le compteur Nb décompte les éléments restant à traiter
  
  ClearScreen(0, 0, 0) ; j'efface l'écran
  
  ; J'affiche la barre de chargement
  StartDrawing(ScreenOutput())
  
    ; Cette distance représente la progression du chargement
    Longueur = (Ecran_Largeur - 2 - 2) * (NbTotal - Nb) / NbTotal
    ; (NbTotal - Nb) / NbTotal est le pourcentage accompli
    ; (Ecran_Largeur - 2 - 2) est la largeur de l'écran. 
    ; Le premier - 2, c'est pour laisser un pixel de bordure à gauche et à droite
    ; Le deuxième -2, c'est pour prendre en compte la taille du carré blanc de largeur 3 (donc 2 pixels de plus que le pixel d'origine en haut à gauche du carré)
    
    ; Ensuite j'affiche un carré blanc tous les 5 pixels dans la longueur calculée précédement
    ; Pour cela, j'utilse une boucle for avec un pas de 5
    For nn = 1 To Longueur Step 5
      Box(nn, Ecran_Hauteur - 3, 3, 2, $FFFFFF) ; Dessine un carré blanc
    Next
    
  StopDrawing()
  
  FlipBuffers()
Until Nb = 0 ; on quitte cette boucle dès qu'il n'y a plus d'élément

Delay(250) ; Ce delay n'est pas obligatoire, il permet simplement de montrer que le chargement st finit, c'est juste pour l'esthétique.


; Le programe principale

ResetList(Liste()) ; on initiaise la liste des valeurs

FontID = LoadFont(0, "Tahoma", 8) ; On charge une police

SetFrameRate(5) ; on affiche 5 images par seconde

Repeat
  ClearScreen(0, 0, 0)
  
  ; On affiche les valeurs qui ont été mises dans le désordre
  
  If NextElement(Liste()) ; Si il existe un élément suivant dans la liste
    StartDrawing(ScreenOutput()) ; On affiche la valeur
      DrawingFont(FontID)
      DrawingMode(1)
      FrontColor(255, 255, 255)
      Locate(5, 5)
      DrawText(Str(Liste()))
    StopDrawing()
  EndIf
  
  FlipBuffers()
  Delay(1)
  
  Event = WindowEvent()
Until Event = #PB_Event_CloseWindow Or Event = #WM_LBUTTONUP
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
kerkael
Messages : 97
Inscription : mer. 03/sept./2008 21:08

Message par kerkael »

Bonjour,

Le code est apparemment un peu ancien et la version actuelle de PB ne l'interprète pas immédiatement.

Il faut désormais préciser que le format des couleurs est en RGB sur plusieurs commandes :
ClearScreen(RGB(0, 0, 0))

La commande de placement Locate est incluse par ses coordonnées dans le draw :

Code : Tout sélectionner

Locate(5, 5)
DrawText(Str(Liste()))
à remplacer par

Code : Tout sélectionner

;Locate(5, 5)
DrawText(5,5,Str(Liste()))
Et aussi, en début de programme, le titre de la fenêtre de la commande openWindow n'est plus à cette place, de même que l'appel d'OpenWindowedScreen s'attend à recevoir le numéro de la fenêtre parente, soit WindowID(0) au lieu de simplement WindowID()

Je vous redonne le code complet corrigé pour du copier-coller.

Sinon ce code est formidable et particulièrement utile. Si on le compare au Tuto donné plus tôt sur le tirage des 3 carrés de couleur proposé par Dobro, il est parfait.
Ici au bout de 5000 tirages vous aurez exactement eu toutes les cartes tirées. Dans le tuto des tableaux, le tirage aléatoire vous donnera effectivement les 3 cartes/carrés, mais vous pourriez avoir à effectuer un nombre illimité de tirages pour enfin arriver à la troisième carte.
Sur 3 cartes ça se terminera bien assez tôt, mais imaginez ce que cela donnerait sur 5000 cartes.M'enfin, c'était un tuto sur les tableaux, pas sur les tirages aléatoires.

Code : Tout sélectionner

Code corrigé :Ecran_Largeur = 200 ; dimension de la fenêtre
Ecran_Hauteur = 100

;{- On crée la fenêtre
If OpenWindow(0, 0, 0, Ecran_Largeur, Ecran_Hauteur, "LSI",#PB_Window_BorderLess | #PB_Window_ScreenCentered) = 0
  End
EndIf
;}

;{- On ouvre l'openscreen
If InitSprite() = 0
  MessageRequester("Erreur", "Impossible d'initialiser la souris ,le clavier ou l'écran. Vérifiez la présence de DirectX 7 ou supérieur.", 0)
  End
EndIf

If OpenWindowedScreen(WindowID(0), 0, 0, Ecran_Largeur, Ecran_Hauteur, 1, 0, 0) = 0

  MessageRequester("Erreur", "Impossible d'ouvrir l'écran.", 0)
  End
EndIf

; Premier affichage
ClearScreen(RGB(0, 0, 0))
FlipBuffers()

;}

; Dans cet exemple, je vais chargé une liste avec des valeur de 1 à 5000 et je vais les mettre dans le désordre
; Cette action est différente d'un Random(5000) car j'obtiens toute les valeurs de 1 à 5000 dans le désordre

;- On charge une liste de points
NewList Temp_Liste.l()
NewList Liste.l()

For n = 1 To 5000 ; on rempli la liste chainée avec des valeur de 1 à 5000
  AddElement(Temp_Liste())
  Temp_Liste() = n
Next

;- On met les points dans le désordre
NbTotal = CountList(Temp_Liste()) ; On compte le nombre d'élément de la liste
Nb = NbTotal ; Les variables n et Nb vont servir pour la boucle
n = NbTotal

; Si j'avais effectué cette action normalment, je n'aurai mis qu'une boucle de 1 à 5000 car j'ai 5000 point à mettre dans le désordre
; Mais je veux afficher une barre de chargement
; Faire un affichage à chaque tour de boucle est trop gourmand (5000 affichage à 50 image/s donne 100 secondes alors que le chargement prend 1 secondes sans affichage)
; Je découpe donc ma bouble en plusieurs morceau et au milieu de ces morceaux, je fais de l'affichage
; Les boucles repeat until situé ci-dessous ont ce but

Repeat ; Boucle d'affichage
  n - 200
 
  Repeat ; Boucle de traitement
 
    ; Cette partie du code permet de mettre les valeurs dans le désordre.
    Nb - 1 ; Je décompte un élément car je vais le traité ci-dessous
    AddElement(Liste()) ; J'ajoute un élement dans la liste final
    SelectElement(Temp_Liste(), Random(Nb)) ; Je choisit un élément au hazard dans la liste temporaire
    Liste() = Temp_Liste() ; Je le copie dans la liste final
    DeleteElement(Temp_Liste()) ; Je supprime cet élément de la liste temporaire
   
  Until Nb = 0 Or Nb < n ; On quitte cette boucle tous les 200 ou dès qu'il n'y a plus d'élément
  ; Le compteur n me sert à sortir de la boucle de traitement pour passer à la boucle d'affichage
  ; Quand je fais n - 200 plus haut, il faut attendre que nb est chuté de 300 pour sortir de la boucle de traitement
  ; 200 est en fait la fréquence de rafraichissement de la barre de progression
  ; Le compteur Nb décompte les éléments restant à traiter
 
  ClearScreen(RGB(0, 0, 0)) ; j'efface l'écran
 
  ; J'affiche la barre de chargement
  StartDrawing(ScreenOutput())
 
    ; Cette distance représente la progression du chargement
    Longueur = (Ecran_Largeur - 2 - 2) * (NbTotal - Nb) / NbTotal
    ; (NbTotal - Nb) / NbTotal est le pourcentage accompli
    ; (Ecran_Largeur - 2 - 2) est la largeur de l'écran.
    ; Le premier - 2, c'est pour laisser un pixel de bordure à gauche et à droite
    ; Le deuxième -2, c'est pour prendre en compte la taille du carré blanc de largeur 3 (donc 2 pixels de plus que le pixel d'origine en haut à gauche du carré)
   
    ; Ensuite j'affiche un carré blanc tous les 5 pixels dans la longueur calculée précédement
    ; Pour cela, j'utilse une boucle for avec un pas de 5
    For nn = 1 To Longueur Step 5
      Box(nn, Ecran_Hauteur - 3, 3, 2, $FFFFFF) ; Dessine un carré blanc
    Next
   
  StopDrawing()
 
  FlipBuffers()
Until Nb = 0 ; on quitte cette boucle dès qu'il n'y a plus d'élément

Delay(250) ; Ce delay n'est pas obligatoire, il permet simplement de montrer que le chargement st finit, c'est juste pour l'esthétique.


; Le programe principale

ResetList(Liste()) ; on initiaise la liste des valeurs

FontID = LoadFont(0, "Tahoma", 8) ; On charge une police

SetFrameRate(5) ; on affiche 5 images par seconde

Repeat
  ClearScreen(RGB(0, 0, 0))
 
  ; On affiche les valeurs qui ont été mises dans le désordre
 
  If NextElement(Liste()) ; Si il existe un élément suivant dans la liste
    StartDrawing(ScreenOutput()) ; On affiche la valeur
      DrawingFont(FontID)
      DrawingMode(1)
      FrontColor(RGB(255, 255, 255))
      ;Locate(5, 5)
      DrawText(5,5,Str(Liste()))
    StopDrawing()
  EndIf
 
  FlipBuffers()
  Delay(1)
 
  Event = WindowEvent()
Until Event = #PB_Event_CloseWindow Or Event = #WM_LBUTTONUP
kerkael
Messages : 97
Inscription : mer. 03/sept./2008 21:08

Message par kerkael »

Le sujet PureBasic Index du Forum -> Jeux -> pour 50 entitées détaille la commande Swap pour un réel mélange de tableau.
Répondre