Page 1 sur 2

Lenteurs d'affichage des gadgets avec WindowedScreen()

Publié : lun. 16/juin/2008 12:29
par Octavius
Voici le problème : sans écran fenêtré les gadgets s'affichent immédiatement, par exemple lorsque l'on clique sur un onglet tous les gadgets correspondant s'affichent instantanément ; mais quand il y a un écran fenêtré, les gadgets sont lents à s'afficher, ils s'affichent au fur et à mesure les uns après les autres. Vous pourrez facilement constater la différence de rapidité en commentant les commandes de l'écran et des sprites. Avec ou sans le débogueur ça ne change rien.

Alors ma question est donc la suivante : comment résoudre ce problème de lenteur à l'affichage ?

Voici mon code :

Code : Tout sélectionner

InitSprite()

OpenWindow(0,0,0,860,572,"Programme",#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0))

PanelGadget(0,532,10,318,512)
AddGadgetItem(0,-1,"Panneau n°1")
ButtonGadget(1,10,10,120,25,"Bouton n°1")
ButtonGadget(2,10,45,120,25,"Bouton n°2")
ButtonGadget(3,10,80,120,25,"Bouton n°3")
AddGadgetItem(0,-1,"Panneau n°2")
ListViewGadget(4,10,10,120,70)
ButtonGadget(5,10,90,120,25,"Bouton n°4")
ButtonGadget(6,10,125,120,25,"Bouton n°5")
ButtonGadget(7,10,160,120,25,"Bouton n°6")

CreateStatusBar(0,WindowID(0))
CreateMenu(0,WindowID(0))
MenuTitle("Projet")
MenuItem(0,"Quitter")
OpenWindowedScreen(WindowID(0),10,10,512,512,0,0,0)

CreateSprite(0,128,128)
StartDrawing(SpriteOutput(0))
Circle(64,64,64,RGB(255,0,0))
StopDrawing()

For i=1 To 250
  AddGadgetItem(4,-1,"élément n°"+Str(i))
Next i

Procedure Display()
  Static X.f,Y.f,i.b,j.b
  If i=0 : X+2 : Else : X-2 : EndIf
  If j=0 : Y+0.6 : Else : Y-0.6 : EndIf
  DisplaySprite(0,X,Y)
  If X>384 : i=1 : EndIf
  If X<0 : i=0 : EndIf
  If Y>384 : j=1 : EndIf
  If Y<0 : j=0 : EndIf
EndProcedure

Repeat

Event=WaitWindowEvent(10)
Select Event
  Case #PB_Event_CloseWindow
    End
  Case #PB_Event_Menu
    EventMenu=EventMenu()
    Select EventMenu
      Case 0
        End
    EndSelect
  Case #PB_Event_Gadget
    EventGadget=EventGadget()
    Select EventGadget
      Case 1 To 3
        MessageRequester("Information","Vous avez appuyé sur le bouton n°"+Str(EventGadget))
      Case 5 To 7
        MessageRequester("Information","Vous avez appuyé sur le bouton n°"+Str(EventGadget-1))
    EndSelect
EndSelect

ClearScreen(0)

Display()

FlipBuffers()

ForEver
PS: Il n'y a dans ce code que quelques gadgets, mais la lenteur d'affichage augmente avec le nombre de gadgets à afficher, ça devient très gênant quand il y en a vraiment beaucoup...

Publié : lun. 16/juin/2008 14:12
par Octavius
D'autres tests m'ont permis de montrer que tout ce qui se passe dans la fenêtre, genre changer des textes dans des StringGadgets, mettre à jour des listes, etc. est beaucoup plus lent quand il y a l'écran fenêtré.

Je n'y connais pas grand chose, mais est-ce qu'il n'y aurait pas une histoire de thread ? Peut-être que toutes les tâches de la fenêtre sont traitées avec une priorité très basse ? Comme faire pour changer ça ?

Publié : lun. 16/juin/2008 14:47
par Backup
cela est due au flipbuffer !!

si tu le met en rem , ça pedale !!
donc la soluce serai de l'activer seulement lorsque personne ne touche au panel :)

si on touche au panel, on se reserve un peu de delay pour le temps d'affichage des gadget , mais cela bloquera l'affichage du sprite ... Normal :D

par exemple :)

Code : Tout sélectionner

  Declare Display()
  
  
  InitSprite()
  #Gadget=1000
  
  OpenWindow(0,0,0,860,572,"Programme",#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0))
  
  PanelGadget(0,532,10,318,512) 
    AddGadgetItem(0,-1,"Panneau n°1") 
    ButtonGadget(1,10,10,120,25,"Bouton n°1")
    ButtonGadget(2,10,45,120,25,"Bouton n°2")
    ButtonGadget(3,10,80,120,25,"Bouton n°3")
    AddGadgetItem(0,-1,"Panneau n°2")
    ListViewGadget(4,10,10,120,70)
    ButtonGadget(5,10,90,120,25,"Bouton n°4")
    ButtonGadget(6,10,125,120,25,"Bouton n°5")
    ButtonGadget(7,10,160,120,25,"Bouton n°6") 
    CreateStatusBar(0,WindowID(0))
    CreateMenu(0,WindowID(0))
    MenuTitle("Projet")
    MenuItem(0,"Quitter")
    
    
    For i=1 To 250
      AddGadgetItem(4,-1,"élément n°"+Str(i))
    Next i
    
    OpenWindowedScreen(WindowID(0),10,10,512,512,0,0,0) 
    CreateSprite(0,128,128)
    StartDrawing(SpriteOutput(0))
      Circle(64,64,64,RGB(255,0,0))
    StopDrawing()
    
  
    Repeat  
        panel=-1
      event=WaitWindowEvent(10)
      Select event
        Case #PB_Event_CloseWindow
          End
        Case #PB_Event_Menu
          EventMenu=EventMenu()
          Select EventMenu
            Case 0
              End
          EndSelect
        Case #PB_Event_Gadget
          EventGadget=EventGadget()
          Select EventGadget
            Case 1 To 3
              MessageRequester("Information","Vous avez appuyé sur le bouton n°"+Str(EventGadget))
            Case 5 To 7
              MessageRequester("Information","Vous avez appuyé sur le bouton n°"+Str(EventGadget-1)) 
          EndSelect 
           Delay(100)
          panel=GetGadgetState(0)   
         
    EndSelect 
    ClearScreen(0) 
    
    If panel=-1
    Display()  
      FlipBuffers(1) 
    EndIf 
    ForEver
    
    
    
    
    Procedure Display()
      Static X.f,Y.f,i.b,j.b
      If i=0 : X+2 : Else : X-2 : EndIf
      If j=0 : Y+0.6 : Else : Y-0.6 : EndIf
      DisplaySprite(0,X,Y)
      If X>384 : i=1 : EndIf
      If X<0 : i=0 : EndIf
      If Y>384 : j=1 : EndIf
      If Y<0 : j=0 : EndIf
    EndProcedure
    
    
    
    

Publié : lun. 16/juin/2008 14:54
par Backup
[Reedit] le code ci dessus :)

Publié : lun. 16/juin/2008 19:21
par Octavius
Oui ça résout en partie le problème. En fait "cliquer sur un onglet" n'est qu'un seul des événements qui peut se produire qui nécessite de traiter une tâche de la fenêtre. Par exemple, si je dois mettre à jour une série de StringGadget, la mise à jour est ralentie, et il faudrait que je fasse un système pour gérer tous les événements possible et stopper le FlipBuffers() à chaque fois... Ce n'est pas très satisfaisant.

J'ai pensé peut-être jouer avec SetFrameRate() et/ou SetFrameRefresh(), mais je n'arrive à rien en mettant des valeurs au hasard. Vous auriez une idée ?

Publié : lun. 16/juin/2008 19:27
par comtois
C'est pour faire un jeu ou un éditeur ??

Code : Tout sélectionner

InitSprite()

OpenWindow(0,0,0,860,572,"Programme",#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0))

PanelGadget(0,532,10,318,512)
AddGadgetItem(0,-1,"Panneau n°1")
ButtonGadget(1,10,10,120,25,"Bouton n°1")
ButtonGadget(2,10,45,120,25,"Bouton n°2")
ButtonGadget(3,10,80,120,25,"Bouton n°3")
AddGadgetItem(0,-1,"Panneau n°2")
ListViewGadget(4,10,10,120,70)
ButtonGadget(5,10,90,120,25,"Bouton n°4")
ButtonGadget(6,10,125,120,25,"Bouton n°5")
ButtonGadget(7,10,160,120,25,"Bouton n°6")

CreateStatusBar(0,WindowID(0))
CreateMenu(0,WindowID(0))
MenuTitle("Projet")
MenuItem(0,"Quitter")
OpenWindowedScreen(WindowID(0),10,10,512,512,0,0,0)

CreateSprite(0,128,128)
StartDrawing(SpriteOutput(0))
Circle(64,64,64,RGB(255,0,0))
StopDrawing()

For i=1 To 250
  AddGadgetItem(4,-1,"élément n°"+Str(i))
Next i

Procedure Display()
  Static X.f,Y.f,i.b,j.b
  If i=0 : X+2 : Else : X-2 : EndIf
  If j=0 : Y+0.6 : Else : Y-0.6 : EndIf
  DisplaySprite(0,X,Y)
  If X>384 : i=1 : EndIf
  If X<0 : i=0 : EndIf
  If Y>384 : j=1 : EndIf
  If Y<0 : j=0 : EndIf
EndProcedure

Repeat

Event=WindowEvent()
Select Event
  Case 0
    Delay(1)
    ClearScreen(0)
    Display()
    FlipBuffers()
    
  Case #PB_Event_CloseWindow
    End
  Case #PB_Event_Menu
    EventMenu=EventMenu()
    Select EventMenu
      Case 0
        End
    EndSelect
  Case #PB_Event_Gadget
    EventGadget=EventGadget()
    Select EventGadget
      Case 1 To 3
        MessageRequester("Information","Vous avez appuyé sur le bouton n°"+Str(EventGadget))
      Case 5 To 7
        MessageRequester("Information","Vous avez appuyé sur le bouton n°"+Str(EventGadget-1))
    EndSelect
EndSelect

ForEver

Publié : lun. 16/juin/2008 19:30
par Octavius
Un éditeur!

Merci comtois, ton astuce fonctionne parfaitement bien! Je n'aurais jamais pensé faire un "Case 0" pour WindowEvent() ! :idea:

Publié : lun. 16/juin/2008 19:41
par Backup
Octavius a écrit :Un éditeur!

Merci comtois, ton astuce fonctionne parfaitement bien! Je n'aurais jamais pensé faire un "Case 0" pour WindowEvent() ! :idea:
oui ! moi non plus :)

Publié : lun. 16/juin/2008 20:28
par Ollivier
Merci Comtois !

Publié : lun. 16/juin/2008 21:54
par Ouaf-Ouaf
Whaa.. J'savais pas qu'on pouvait utiliser les gadgets dans un windowedScreen *bave*
Parfait pour un editeur en effet :P

Publié : lun. 16/juin/2008 22:47
par Octavius
Le seul petit bémol c'est qu'à cause de WindowEvent() le programme devient gourmand en temps CPU (chez moi environ 45% avec le dernier code donné par comtois).

Je cherche donc un moyen d'optimiser cela.

Pour l'instant je n'ai pas trouvé une meilleure solution que d'augmenter le temps de Delay(), par exemple : Delay(1000/60) pour avoir au maximum 60 boucles par seconde. Ce n'est pas très élégant mais ça a l'air de fonctionner.

EDIT: J'ai remarqué un autre truc, lorsque la souris est capturée par l'écran avec InitMouse() et ReleaseMouse(#False), l'événement Event=0 ne se produit plus : la commande Debug permet de montrer que le programme boucle sur l'événement Event=512 (je ne sais pas à quoi correspond cette constante). Il faut donc modifier "Case 0" en "Case 0,512" si le programme doit gérer une souris.

Publié : mar. 17/juin/2008 3:07
par Ollivier
Je vais ptêt dire une mauvaise mais je préfère la dire quand même au cas où ça marche : WaitWindowEvent(1000/60), ça donne quoi ?

Si ça donne rien de bon, tu peux mettre un timer en CallBack aussi.

Et pour la souris, j'ai proscrit ReleaseMouse(). C'est une instruction à la c... qui m'a valu plusieurs heures de tests pour la faire tourner. Elle a quelque chose d'irréversible.
Résultat : je mixe les 2 systèmes de saisie de la souris GetCursorPos_() pour la partie windows, gadget, menu et compagnie et ExamineMouse() pour la partie graphique (pour choper les MouseDelta essentiellement).

Le programme est . Les 2 procédures qui peuvent t'intéresser WorldMenu() et ExploreWorld() (c'est l'une des procédures «graphiques» appelées par WorldMenu() ) pour voir comment je jongle même s'il n'y a de simultanéïté (je ne fais rien bouger en graphique pendant que tu accèdes au menu). Je ne sais si ça t'aidera plus...

Publié : mar. 17/juin/2008 8:55
par comtois
Le seul petit bémol c'est qu'à cause de WindowEvent() le programme devient gourmand en temps CPU (chez moi environ 45% avec le dernier code donné par comtois).
Essaye d'augmenter le Delay() , en mettant 10 par exemple.

Publié : mar. 17/juin/2008 13:11
par Octavius
Avec WaitWindowEvent(1000/60) les animations sont trop saccadées, Delay(1000/60) fonctionne mieux. Je vais garder cette solution je pense, ça me fait redescendre à 0-2% de temps CPU. :)

Je ne comprends pas ton problème Ollivier avec ReleaseMouse(), chez moi ça fonctionne parfaitement bien, j'arrive bien à m'en servir sans problème.

Publié : mar. 17/juin/2008 13:14
par Backup
Octavius a écrit :Avec WaitWindowEvent(1000/60) les animations sont trop saccadées, Delay(1000/60) fonctionne mieux.
autant faire un Delay(16) alors :D