Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

ACCÉLÉRATION DE LA VITESSE D'AFFICHAGE EN "GELANT" LE RAFRAÎCHISSEMENT D'UN CONTRÔLE


Information sur la source

Catégorie :Optimisation du code Niveau : Débutant Date de création : 23/12/2002 Date de mise à jour : 23/12/2002 14:31:30 Vu / téléchargé: 7 606 / 392

Note :
8,8 / 10 - par 5 personnes
8,80 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (29)
Ajouter un commentaire et/ou une note

Description

Cliquez pour voir la capture en taille normale
Généralement, lorsqu'on ajoute beaucoup d'éléments à une liste à l'aide d'une boucle et qu'on utilise DoEvents, il se produit un effet de clignotement
de la liste (à moins qu'on n'ait masqué celle-ci).

La source que je vous propose fait appel à 2 API qui permettent de "geler" et "dégeler" le rafraîchissement de cette liste ce qui accélère également le remplissage de la liste en question (voir le screenchot pour comparer l'ajout de 1000 éléments dans une ListView en utilisant les deux méthodes).

Les API en question sont InvalidateRect() et ValidateRect()  
 

Source

  • 'API pour mesurer le temps écoulé
  • Private Declare Function GetTickCount Lib "kernel32" () As Long
  • 'API permettant de "geler" la mise à jour d'un objet
  • Private Declare Sub InvalidateRect Lib "user32" (ByVal hWnd As Long, ByVal t As Long, ByVal bErase As Long)
  • Private Declare Sub ValidateRect Lib "user32" (ByVal hWnd As Long, ByVal t As Long)
  • ' 1000 éléments sont ajoutés à la ListView via une boucle rendant régulièrement la main à Windows
  • ' mais ici, on utilise 2 API permettant de "geler" et "dégeler" le rafraîchissement de la liste.
  • ' La liste "clignote" moins voire pas du tout si on annule la ligne (=>)
  • Private Sub Command2_Click()
  • Dim nStart As Long
  • Dim i As Integer
  • nStart = GetTickCount()
  • ListView1.View = 3
  • ListView1.ListItems.Clear
  • For i = 1 To 1000
  • ListView1.ListItems.Add , , "Chaîne " & CStr(i)
  • '-- En validant la région, il n'y aura pas de génération d'un message WM_PAINT
  • ValidateRect ListView1.hWnd, 0&
  • '-- "Rafraîchit" la liste
  • '(=>) Essayez également en désactivant cette ligne...
  • If (i Mod 10) = 0 Then InvalidateRect ListView1.hWnd, 0&, 0&
  • '-- Autorise le multi-tâche
  • DoEvents
  • Next i
  • InvalidateRect ListView1.hWnd, 0&, 0&
  • MsgBox Str(GetTickCount() - nStart) & " ms", vbOKOnly, "Avec optimisation :"
  • End Sub
'API pour mesurer le temps écoulé
Private Declare Function GetTickCount Lib "kernel32" () As Long

'API permettant de "geler" la mise à jour d'un objet
Private Declare Sub InvalidateRect Lib "user32" (ByVal hWnd As Long, ByVal t As Long, ByVal bErase As Long)
Private Declare Sub ValidateRect Lib "user32" (ByVal hWnd As Long, ByVal t As Long)
'   1000 éléments sont ajoutés à la ListView via une boucle rendant régulièrement la main à Windows
'   mais ici, on utilise 2 API permettant de "geler" et "dégeler" le rafraîchissement de la liste.
'   La liste "clignote" moins voire pas du tout si on annule la ligne (=>)

Private Sub Command2_Click()
    
    Dim nStart As Long
    Dim i As Integer
    
    nStart = GetTickCount()
    ListView1.View = 3
    
    ListView1.ListItems.Clear
        
    For i = 1 To 1000
        ListView1.ListItems.Add , , "Chaîne " & CStr(i)
            
        '-- En validant la région, il n'y aura pas de génération d'un message WM_PAINT
        ValidateRect ListView1.hWnd, 0&
            
        '-- "Rafraîchit" la liste
'(=>) Essayez également en désactivant cette ligne...
        If (i Mod 10) = 0 Then InvalidateRect ListView1.hWnd, 0&, 0&
            
        '-- Autorise le multi-tâche
        DoEvents
    Next i
    
    InvalidateRect ListView1.hWnd, 0&, 0&
    MsgBox Str(GetTickCount() - nStart) & " ms", vbOKOnly, "Avec optimisation :"

End Sub  

Conclusion

'============================
PS: Encore une source qui n'est pas de moi mais... vous connaissez la chanson...

Cette source est extraite d'un article de Xavier LECLERCQ consacré à l'optimisation du code en VB paru dans la revue "Programmez!" du mois de Novembe 2000 (n° 26)  
 

Fichier Zip

Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

Commentaires et avis

signaler à un administrateur
Commentaire de MyC le 23/12/2002 10:59:56

Je ne sais pas si tu as vu ma question dans le forum ou si tu lis dans mes pensées, mais c'est exactement ce qu'il me fallait. Un grand merci à toi (10/10, même si cette source n'est pas de toi, car c'est une très bonne contribution) !

signaler à un administrateur
Commentaire de MyC le 23/12/2002 12:35:25

Peux-tu me dire à quoi sert cette ligne : "If (i Mod 10) = 0 Then InvalidateRect ListView1.hWnd, 0&, 0&", car comme j'ai mis cette ligne en commentaire comme il est suggéré dans le code, et au lieu de 15751 ms, en vue grandes icônes, avec 1000 items, et avec cette ligne, cela se fait en 99 ms avec les mêmes propriétés mais avec la ligne en commentaire et sans le moindre petit clignotement. Alors j'aimerai savoir, si est est obligatoire dans certains cas et sinon à quoi sert-elle ? Merci d'avance pour ta réponse, et encore bravo pour cette source très utile !  

signaler à un administrateur
Commentaire de PROGRAMMIX le 23/12/2002 12:55:54

Comme tu as pû le voir, cette API est également utilisée après la boucle et sert à rafraîchir la liste.

La ligne de code peut être traduit de la manière suivante :
     If (i Mod 10) = 0 signifie que toutes les 10 boucles...
     Then InvalidateRect... on redessine la ListView1
Ainsi et suivant les PC, le clignotement peut encore apparaître mais à une moindre fréquence...

Effectivement, en supprimant cette ligne de code, on accélère encore le temps de réalisation de la boucle puisque qu'on ne la redessine plus (ce qui se faisait 1000/10=100 fois)

signaler à un administrateur
Commentaire de FPatrick le 23/12/2002 15:27:32

Bonjour tout d'abord.
Si tu mets la liste ou les controles dans un picturebox et que tu rends invisible ce picturebox lors d'un chargement , la vitesse de chargement et d'affichage est considérablement augmenté (remarqué plusieurs fois dans mes applications) . Par contre on charge un controle donc de la mémoire , a voir ....
Merci d'avance pour tes commentaires....

signaler à un administrateur
Commentaire de peug le 23/12/2002 17:21:44

La ligne "ValidateRect ListView1.hWnd, 0&" doit se trouver en dehors de la boucle For ! non ?

signaler à un administrateur
Commentaire de BFR le 23/12/2002 17:49:05

'-FIGER L'AFFICHAGE DU LISTVIEW,TREEVIEW ETC...***************************************
  Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Long) As Long
  Public Const WM_SETREDRAW = &HB
'-FIGER L'AFFICHAGE DU LISTVIEW,TREEVIEW***************************************



'-Je désactive l'affichage du contrôle
  lRet = SendMessage(ListView1.hwnd, WM_SETREDRAW, False, 0&)

'-J'active l'affichage du contrôle
  lRet = SendMessage(ListView1.hwnd, WM_SETREDRAW, True, 0&)

signaler à un administrateur
Commentaire de PROGRAMMIX le 23/12/2002 18:24:19

Réponse BFR

Je ne sais pas... Je n'ai pas essayé en mettant la fonction en dehors de la boucle...

Est-ce là une autre méthode que tu proposes ??

signaler à un administrateur
Commentaire de Billou le 23/12/2002 22:10:44

super ce code mercie 10/10

arrrrrrrrrrrgggggggghhhhhhhh burk burk win 98 :-)))))))) ^^

++

signaler à un administrateur
Commentaire de BFR le 24/12/2002 13:56:20

en reponse:
il  fige l'affichage du controle au début de ta procedure
puis le défige à la fin,cette API permet d'ajouter des élements à un EX:listview sans provoquer l'affichage de chaque élément il n'y à pas besoin de boucle il faut le mettre au début de la procédure puis à la fin
est-ce clair ?
A++

signaler à un administrateur
Commentaire de Zeroc00l le 25/06/2003 22:35:38

Franchement... C'est cool !
V'est le petit truc dégueulasse dans les applis que tout le monde avaient envie de virer ! je vais reprendre ce qu'a dit MyC:
"même si cette source n'est pas de toi" , "c'est une très bonne contribution".

Et en plus ca accélère le code. ^_^

8/10  +1/10 (pour l'originalité ) + 1/10 (Source apparement unique )

donc un piti 10/10

-={[ ZeroCool ]}=-

P.S. : Je kiffe le "Quelle touche.exe" sur ton bureau :D mdr !

signaler à un administrateur
Commentaire de olid le 21/07/2003 03:45:18

Heu...une question idiote ?!!!

Les deux API zappliquent que pour les listview ? :o|

Moins idiot... à quoi zert les autres arguments (où tas mis &0) de zes fonctions API ? :o.

Merzi pour la réponse ;op

signaler à un administrateur
Commentaire de PROGRAMMIX le 21/07/2003 10:25:58

>Réponse à olid
- Je pense que l'on peut utiliser les API pour d'autres contrôles que le ListView puisqu'en fait on demande à Windows de "redessiner" ou non le contrôle ;
- En ce qui concerne les arguments, je ne connais pas leur utilité (je rappelle que c'est une astuce qui émane Xavier LECLERCQ) et je ne me suis pas "amusé" à les changer pour voir les conséquences (je ne suis pas du genre téméraire).

Voilà une réponse qui ne répond pas vraiment à tes attentes, mais c'est tout ce que je peux faire...

signaler à un administrateur
Commentaire de olid le 21/07/2003 12:53:00

Merzi....tas répondu à la principale ! ;o)

Zetais pô temeraire nan plus pour ezzayer avec d'autres controles (qui ont un evenment paint) !!! :o|

Je pense pouvoir tester avec Picturebox et les menus... je vous dis quoi si jamais zà plante grave l'ordi ! :op

signaler à un administrateur
Commentaire de BFR le 21/07/2003 16:15:29

Effectivement j'ai déja essayé avec un richtexbox et ça marche
A++

signaler à un administrateur
Commentaire de babboss le 19/08/2003 04:16:49

c super comme source
merci a toi :)

signaler à un administrateur
Commentaire de FrostByte le 13/09/2003 17:55:57

Vous allez peut-être me rire au nez, mais peut-on geler un ensemble de controle durant le redimenssionement d'un formulaire si oui, pourriez vous m'indiquer la methode !!

signaler à un administrateur
Commentaire de PROGRAMMIX le 13/09/2003 19:04:57

Je n'ai jamais testé...  
En fait, je ne vois pas très bien ce que tu veux obtenir...
Mais personnellement, je me dis qu'au lieu de geler tous les contrôles de ta Form, tu peux peut-être geler celle-ci...

signaler à un administrateur
Commentaire de FrostByte le 14/09/2003 01:10:04

Je m'explique :
quand un formulaire contient beaucoup de composants, et, que tu dois tous les redimmensionner lors de l'evenement form_resize, tu as un effet (qui se nomme "flickering" je crois) qui fait que les controles clignotent lors du redimensionnement, ma question était peut-on essayer de bloquer cet effet "flickering" avec ta technique de gele grâce à la fonction Freeze et ainsi ne pas utiliser de subterfuge (voir ssubtimer6.dll voir l'exemple de steve mc mahon www.vbaccelerator.com), et donc de pvoir redimmensionner sans cet effet !! si tu as trvé la reponse ou une autre technique mail moi !!

signaler à un administrateur
Commentaire de PROGRAMMIX le 14/09/2003 08:37:39

Pourquoi ne ferais-tu pas l'expérience puisque, je suppose, que tu as déjà une Form prête à être testée ?
Si cela marche ou nécessite l'une ou l'autre modif, tu pourras nous en faire part...

signaler à un administrateur
Commentaire de FrostByte le 14/09/2003 11:18:49

ouais logik, je vais essayer mais geler bcp de controles sa va pas ralentier la becane ?

signaler à un administrateur
Commentaire de FrostByte le 14/09/2003 11:42:19

ouais logik, je vais essayer mais geler bcp de controles sa va pas ralentier la becane ? je viens de tester et bah rien à faire !! sous xp sa marche pas !!

signaler à un administrateur
Commentaire de Kike le 28/11/2003 12:36:52

alors
avec optimisation 310ms
sans optimisation 11600ms
moi 40 ms
On rend la liste invisible au début du remplissage et on la ré affiche en fin.
simple et sans effet clipping
Voici le code (pour les débutants)
rajouter un bouton "command 3 " et le code suivant

Private Sub Command3_Click()
    
    Dim nStart As Long
    Dim i As Integer
    
    'Démarre le "chrono"
    nStart = GetTickCount()
    ListView1.Visible = False
    'Pour un affichage de type "Report"
    ListView1.View = 3
    
    'Efface la liste
    ListView1.ListItems.Clear
    
    'Boucle pour ajouter 1000 éléments
    For i = 1 To 1000
        ListView1.ListItems.Add , , "Chaîne " & CStr(i)
        
        '-- Rend la main à Windows
        DoEvents
    Next i
    ListView1.Visible = True
    MsgBox Str(GetTickCount() - nStart) & " ms", vbOKOnly, "Sans optimisation :"

End Sub


signaler à un administrateur
Commentaire de bab22333 le 11/03/2005 20:53:45

je voudrais pas trop critiquer mais meme avec ces api, ça clignote quand meme ... bcq moins, certes, mais c'est pas parfait.

il y a pas moyen d'empecher complément le clignotement ??

signaler à un administrateur
Commentaire de papipsycho le 19/03/2005 03:10:13

apre modif du code joptien 32 ms !!!!!!

Private Sub Command2_Click()
    
    Dim nStart As Long
    Dim n As Integer
    Dim i As Integer
    nStart = GetTickCount()
    ListView1.View = 3
    n = 1000
    ListView1.ListItems.Clear
        
    For i = 1 To n
        ListView1.ListItems.Add , , "Chaîne " & CStr(i)
            
        '-- En validant la région, il n'y aura pas de génération d'un message WM_PAINT
        ValidateRect ListView1.hWnd, 0&
            
        '-- "Rafraîchit" la liste
'(=>) Essayez également en désactivant cette ligne...
        If (i Mod n) = 0 Then InvalidateRect ListView1.hWnd, 0&, 0&
            
        '-- Autorise le multi-tâche
        DoEvents
    Next i
    
    InvalidateRect ListView1.hWnd, 0&, 0&
    MsgBox Str(GetTickCount() - nStart) & " ms", vbOKOnly, "Avec optimisation :"

End Sub

signaler à un administrateur
Commentaire de papipsycho le 19/03/2005 03:11:23

jai oublier

aven modif 210ms
apre modif 32ms

signaler à un administrateur
Commentaire de cavo789 le 29/09/2006 09:41:42

Merci pour tout vos conseils.

signaler à un administrateur
Commentaire de Arcanis le 22/11/2006 11:47:44

Salut à tous,

D'abord bravo pour cette source. L'optimisation via les API est toujours bon à prendre !!!
J'aimerais toutefois vous demander conseil. J'ai développé un éditeur de texte en vb qui permet des modifs de masse sur fichier(s), et j'ai fait l'erreur de choisir un objet listview comme zone de reception du fichier.
Après de nombreuses fonctionnalités ajoutées, je me suis rendu compte d'un manque de performances. En effet, à la base le programme devait servir à ouvrir de petits fichiers.
Maintenant, il est utilisé pour des fichiers dépassant les 300 000 lignes...........
Autant dire que ma listview en prend un coup à chaque manipulation. Pour optimiser, j'ai opté pour la méthode "on cache la listview" ce qui permet un énorme gain de puissance.
Toutefois, d'après vous, vaut il mieux utilisé cette api ou ma méthode de "cache-cache" ???

Merci d'avance pour vos réponses...

PS : épargnez moi les conseils du style "utilise plutôt une textbox", c'est impossible. Autant jeter à la poubelle 2 ans de dev... Je DOIS maintenir la listview...

Arcanis

signaler à un administrateur
Commentaire de PROGRAMMIX le 22/11/2006 12:24:10

Arcanis,

Aucune idée...
Il me semble qu'avec la méthode "cache-cache", il y a un effet de clignotement qui peut être désagréable (c'est du moins ce que j'ai pu observer sur mes premiers essais du genre et de vieux pc).

Le mieux serait de faire une copie de ton projet, de remplacer le cache-cache par les API et de comparer.

C'est hélas, tout ce que je peux dire, vu que je ne suis pas un expert en API et que je n'ai plus touché à VB depuis un bon moment.

Bien à toi,

Programmix

signaler à un administrateur
Commentaire de Arcanis le 22/11/2006 14:09:29

Programmix,

Merci de ta réponse. J'ai essayé de mon coté d'utiliser la méthode "cache-cache" sur ton projet. Je passe à 20ms......... En revanche, au lieu d'obtenir un effet de clignotement, j'ai plutôt un effet d'interrupteur (jour/nuit). C'est sans doute dûe à ma machine qui est assez performante (sur mon lieu de travail :-) ).

Je peux en revanche justifier mon choix sur mon projet d'éditeur de texte. Le projet doit permettre une gestion multi-fenêtre à l'interieur de l'appli (avec une fenêtre MDI et des fenêtres filles). Donc lors d'une modification de masse sur un fichier, il est intéressant de voir sur lequel on travaille, surtout quand tous les fichiers sont modifiés les uns après les autres par le même traitement (modif séquentielle de chaque fichier en fait...).
Donc je vais essayé ton api pour essayer de grapiller quelques centièmes...

Je vais également essayé ton projet à plus grande échelle (100 000, 300 000 lignes à remplir) pour voir... Peut être qu'à cette échelle, elle est plus rapide...

Encore merci et a+

Arcanis

Ajouter un commentaire



Nos sponsors

Sondage...

CalendriCode

Juillet 2009
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Comparez les prix Nouvelle version

Photothèque Nouveau !



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 0,530 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.