Page 1 sur 1

listIcongadget() et removegadgetitem()

Publié : jeu. 31/août/2017 8:25
par blendman
Salut

Toujours pour mon application (level editor 2D), j'utilise une listviewgadget pour afficher une liste des sprites de mon niveau (avec des options pour en afficher certains ou pas).

Le problème, c'est lorsque je supprime un sprite, je mets à jour cette liste avec removeGadgetItem(), et là, bam, ça me fait un trou dans ma liste (lignes vides) :

Image


Vous savez comment je peux résoudre ça ?

Au départ, j'effaçais tous les éléments et je recréais la liste en fonction de la liste de sprites, mais le problème, c'est que sur des maps contenant des centaines voire milliers de sprites, c'est beaucoup trop long de recréer les gadgetitem dès que je supprime un sprite.

Un code pour illustrer le problème :

Code : Tout sélectionner

If OpenWindow(0,0,0,270,140,"ListViewGadget",#PB_Window_SystemMenu | #PB_Window_ScreenCentered) 
  ListIconGadget(0,10,10,250,120,"",250)
  If LoadImage(0, #PB_Compiler_Home+"Examples\Sources\Data\File.bmp")     ; changez le chemin/fichier contenant votre image 32x32 pixel
    SetGadgetAttribute(0, #PB_ListIcon_DisplayMode, #PB_ListIcon_SmallIcon)
    For a=1 To 12
      AddGadgetItem (0,-1,"Elément "+Str(a)+" de la boîte à liste",ImageID(0))   ; défini le contenu de la boîte de liste
    Next
  EndIf
  RemoveGadgetItem(0,2)
  RemoveGadgetItem(0,4)
  RemoveGadgetItem(0,5)
  RemoveGadgetItem(0,7)
  
  ; SetGadgetState(0,9)    ; sélectionne le dixième élément (la numérotation commmence à 0)
  Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
EndIf
j'avais testé en faisant ça quand je supprime un element :
SetGadgetAttribute(0, #PB_ListIcon_DisplayMode, #PB_ListIcon_LargeIcon)
SetGadgetAttribute(0, #PB_ListIcon_DisplayMode, #PB_ListIcon_SmallIcon)

Mais le problème, c'est que si j'ai plusieurs centaines de sprites, c'est aussi extrêmement long à recalculer...

Une idée de ce que je pourrais faire pour éviter ces lignes vides ?


EDIT :
bon, en utilisant TreeGadget() à la place, je n'ai plus ce problème.
Donc, finalement, je vais utiliser un TreeGadget() au lieu d'un LIstIconGadget(), en plus, je pourrais ajouter des dossier pour les types de sprites si besoin :)
c'te classe :D

Cependant, si vous avez une technique avec les listIconGadget() ça m'intéresse ;)

Par contre, visiblement, on ne peut pas changer la taille des icones (imageID()) des treegadgets avec AddgadgetItem() ?

Re: listIcongadget() et removegadgetitem()

Publié : jeu. 31/août/2017 12:35
par boby

Code : Tout sélectionner

Structure sprites
  name.s
  img.l
EndStructure
Global NewList sprites.sprites()
Declare RemoveListItem(List liste.sprites(),item)

If OpenWindow(0,0,0,270,140,"ListViewGadget",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ListIconGadget(0,10,10,250,120,"",250)
  If LoadImage(0, #PB_Compiler_Home+"Examples\Sources\Data\File.bmp")     ; changez le chemin/fichier contenant votre image 32x32 pixel
    SetGadgetAttribute(0, #PB_ListIcon_DisplayMode, #PB_ListIcon_SmallIcon)
    For a = 0 To 12
      AddElement(sprites())
      sprites()\name = "Elément "+Str(a)+" de la boîte à liste"
      sprites()\img = ImageID(0)
    Next a
  EndIf
  RemoveListItem(sprites(),2)
  RemoveListItem(sprites(),4)
  RemoveListItem(sprites(),5)
  RemoveListItem(sprites(),7)
 
  ; SetGadgetState(0,9)    ; sélectionne le dixième élément (la numérotation commmence à 0)
  Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
EndIf

Procedure RemoveListItem(List liste.sprites(),item)
  SelectElement(liste(),item)
  DeleteElement(liste())
  ClearGadgetItems(0)
  ForEach liste()
    AddGadgetItem(0,-1,liste()\name,liste()\img)
  Next
EndProcedure
A adapter selon tes besoins

Re: listIcongadget() et removegadgetitem()

Publié : jeu. 31/août/2017 14:53
par blendman
Merci boby ;)
C'est ce que je faisais au départ, mais quand on a plusieurs centaines de sprites, ça devient vite très lent (pour la listicongadget), alors qu'avec le treegadget, plus besoin d'actualiser la liste et de combler les lignes vides ;).

Re: listIcongadget() et removegadgetitem()

Publié : ven. 01/sept./2017 13:01
par Shadow

Re: listIcongadget() et removegadgetitem()

Publié : ven. 01/sept./2017 20:02
par El Papounet
Si tu es sous Windows tu peux essayer d'ajouter après la suppression de tes items le code suivant:

Code : Tout sélectionner

SendMessage_(GadgetID(0), #LVM_ARRANGE, #LVA_ALIGNTOP, 0)
Ou sinon, toujours après la suppression:

Code : Tout sélectionner

SetGadgetAttribute(0, #PB_ListIcon_DisplayMode, #PB_ListIcon_List)
SetGadgetAttribute(0, #PB_ListIcon_DisplayMode, #PB_ListIcon_SmallIcon)

Re: listIcongadget() et removegadgetitem()

Publié : mar. 05/sept./2017 9:04
par Mesa
Sous Windows, pour accelerer un listicon, on peut faire comme ça (c'est très efficace):

Code : Tout sélectionner

EnableExplicit

Define EventID
Define a
Define StartTime
Define ElapsedTime

If OpenWindow(0,0,0,500,400,"Window",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
  ListIconGadget(1,10,10,480,380,"",400,0)
  SendMessage_(GadgetID(1),#WM_SETREDRAW,0,0) ; le gadget n'est pas redessiné après un changement

  StartTime = ElapsedMilliseconds()

  For a=1 To 10000
    AddGadgetItem(1,-1,"Item "+Str(a),0,0)
  Next

  SendMessage_(GadgetID(1),#WM_SETREDRAW,1,0) ; on redessine

  ElapsedTime = ElapsedMilliseconds()-StartTime
 
  MessageRequester("",Str(ElapsedTime)+" ms. après 10.000 entrées.",0)
 
  Repeat
    EventID=WaitWindowEvent()
    If EventID = #PB_Event_CloseWindow
      End
    EndIf
  ForEver
EndIf

Code : Tout sélectionner

If OpenWindow(0,0,0,270,140,"ListViewGadget",#PB_Window_SystemMenu | #PB_Window_ScreenCentered) 
  ListIconGadget(0,10,10,250,120,"",250)
  If LoadImage(0, #PB_Compiler_Home+"Examples\Sources\Data\File.bmp")     ; changez le chemin/fichier contenant votre image 32x32 pixel
    SetGadgetAttribute(0, #PB_ListIcon_DisplayMode, #PB_ListIcon_SmallIcon)
    For a=1 To 12
      AddGadgetItem (0,-1,"Elément "+Str(a)+" de la boîte à liste",ImageID(0))   ; défini le contenu de la boîte de liste
    Next
  EndIf
  SendMessage_(GadgetID(0),#WM_SETREDRAW,0,0) ; le gadget n'est pas redessiné après un changement
  RemoveGadgetItem(0,2)
  RemoveGadgetItem(0,4)
  RemoveGadgetItem(0,5)
  RemoveGadgetItem(0,7)
  ; 	SendMessage_(GadgetID(0), #LVM_ARRANGE, #LVA_ALIGNLEFT, 0); bug sous xp
  ;astuce de El Papounet http://www.purebasic.fr/french/viewtopic.php?f=1&t=16915&p=195008#p195008
  SetGadgetAttribute(0, #PB_ListIcon_DisplayMode, #PB_ListIcon_List)
  SetGadgetAttribute(0, #PB_ListIcon_DisplayMode, #PB_ListIcon_SmallIcon)
  SendMessage_(GadgetID(0),#WM_SETREDRAW,1,0) ; on redessine
  ;SetGadgetState(0,9)    ; sélectionne le dixième élément (la numérotation commmence à 0)
  Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
EndIf
M.

Re: listIcongadget() et removegadgetitem()

Publié : mar. 05/sept./2017 9:26
par Kwai chang caine
Je sais pas si ça peut t'aider, mais autrement tu as aussi la ListIcon virtuelle 8)
Un truc de dingue au niveau de la rapidité, je l'utilise souvent pour les très longues listes...c'est imbattable. 8O
En fait le tableau est intimement lié à la ListIcon, des que tu modifies le tableau la ListIcon le reproduit..truc de ouf
Le seul bémol, c'est que certaines fonctions de PB sur les ListIcons ne fonctionnent plus :|

Pour gérer ta ListIcon, tu dois désaprendre tout ce que tu as appris

Image

et ne travailler QUE avec le tableau "myItems()" :mrgreen:

Code du grand RASHAD (4e code)
http://www.purebasic.fr/english/viewtop ... 05#p403305

Code : Tout sélectionner

#ItemCount = 35000

#LVSICF_NOINVALIDATEALL = 1
#LVN_ODCACHEHINT = #LVN_FIRST - 13

Global Dim myItems.s(#ItemCount,1)

Procedure WinCallback(hwnd, msg, wParam, lParam)
  result = #PB_ProcessPureBasicEvents
  Select msg
    Case #WM_NOTIFY
      *pnmh.NMHDR = lParam
      Select *pnmh\code
        Case #LVN_ODCACHEHINT
          result = 0
        Case #LVN_GETDISPINFO                ;
          *pnmlvdi.NMLVDISPINFO = lParam
          If *pnmlvdi\item\mask & #LVIF_TEXT
            *pnmlvdi\item\pszText = @myItems(*pnmlvdi\item\iItem,*pnmlvdi\item\iSubItem)
            SetGadgetText(1,Str(#ItemCount))
          EndIf
               ;
      EndSelect
  EndSelect
  ProcedureReturn result
EndProcedure
;
If OpenWindow(0, 0, 0, 300, 430, "Virtual ListIconGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  SetWindowCallback(@WinCallback())
  Licon = ListIconGadget(0,5,5,290,390,"Name",50,#LVS_OWNERDATA)
  StringGadget(1,5,405,85,20,"")
  SendMessage_(Licon, #LVM_SETITEMCOUNT, #ItemCount, #LVSICF_NOINVALIDATEALL)
  AddGadgetColumn(0,2,"Address",300)
  For i=0 To #ItemCount
    myItems(i,0) = Str(i)
    myItems(i,1) = "PureBasic Road, BigTown, CodeCity"
  Next i
 
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf

Re: listIcongadget() et removegadgetitem()

Publié : mar. 05/sept./2017 10:41
par Marc56
sur des maps contenant des centaines voire milliers de sprites, c'est beaucoup trop long de recréer les gadgetitem dès que je supprime un sprite
Il y a une raison.
Les gadgets ne sont pas conçus pour faire du stockage mais pour afficher une quantité limitée de données stockée dans une liste, un tableau, une map.
Quand cette quantité dépasse quelques centaines, il faut filtrer.
Dans tous les cas, penser à l'utilisateur final qui en informatique, a horreur de prendre l’ascenseur :mrgreen:

Re: listIcongadget() et removegadgetitem()

Publié : mar. 05/sept./2017 14:31
par Kwai chang caine
Marco a écrit : a horreur de prendre l’ascenseur
Et qu'est ce que ce serait si c'était l'escalier :?

Re: listIcongadget() et removegadgetitem()

Publié : mer. 06/sept./2017 13:05
par Mesa
@Blendman
C'est un bug que tu peux mettre sur le forum anglais, car ce qui marche sans icones ne marche pas avec, et il n'y a pas de raison.


Code : Tout sélectionner

If OpenWindow(0,0,0,270,340,"ListViewGadget",#PB_Window_SystemMenu | #PB_Window_ScreenCentered) 
  ListIconGadget(0,10,10,250,120,"",250)
  ListIconGadget(1,10,150,250,120,"",250)
  If LoadImage(0, #PB_Compiler_Home+"Examples\Sources\Data\File.bmp") 
    SetGadgetAttribute(0, #PB_ListIcon_DisplayMode, #PB_ListIcon_SmallIcon)
    For a=1 To 12
      AddGadgetItem (0,-1,"Elément "+Str(a)+" de la boîte à liste",ImageID(0)) 
      AddGadgetItem (1,-1,"Elément "+Str(a)+" de la boîte à liste") 
    Next
  EndIf
  
  RemoveGadgetItem(0,2)
  RemoveGadgetItem(0,4)
  RemoveGadgetItem(0,5)
  RemoveGadgetItem(0,7)
  
  RemoveGadgetItem(1,2)
  RemoveGadgetItem(1,4)
  RemoveGadgetItem(1,5)
  RemoveGadgetItem(1,7)
  
  
  Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
EndIf
M.