Listview (listicon) with groups freezes

Just starting out? Need help? Post your questions and find answers here.
Fenix
Enthusiast
Enthusiast
Posts: 102
Joined: Wed May 07, 2003 1:45 am
Location: Germany

Listview (listicon) with groups freezes

Post by Fenix »

Hi,

I'm trying to setup a listview using groups. And it seems to work, but after leaving the procedure which assigns the listview items to groups the program just hangs. Also the listview doesn't update (no groups are shown, only a blank window). Tested using PB 5.21LTS, x64, unicode.

Here's the code:

Code: Select all

Procedure MainviewShowGrouped(hWnd.i, iColumn.i)
  ; --- groups the items of a listview
  ; ---
  ; --- Parameter:
  ; --- hWnd.i            = window (listview) handle
  ; --- iColumn.i         = column to group by
  
  Protected iNumberOfEntries.i
  Protected iGroupFound.i           ; used to determine if a group already exits -> true, then no new group is added
  Protected iCounter.i
  Protected sItem.s                 ; holds the item text 
  
  Protected _lvitem.LVITEM
  Protected _lvgroup.LVGROUP

  Protected NewList sGrouplist.s()  ; stores the different groups we use

  
  SendMessage_(hWnd, #LVM_ENABLEGROUPVIEW , #True, 0)
  
  _lvGroup\cbSize = SizeOf(LVGROUP)
  _lvGroup\mask   = #LVGF_HEADER | #LVGF_GROUPID | #LVGF_ALIGN | #LVGF_STATE     ; set fields of the LVGROPU structure that are to be used later on
  _lvgroup\state  = #LVGS_COLLAPSIBLE
  
  
  ; -> build the Grouplist
  iNumberOfEntries = SendMessage_(hWnd, #LVM_GETITEMCOUNT, #Null, #Null) - 1
  Debug "Entries = " + iNumberOfEntries
  
  Protected *Buffer
  *Buffer = AllocateMemory(512)
  If Not (*Buffer)
    ProcedureReturn 
  EndIf
  
  _lvitem\mask        = #LVIF_TEXT
  _lvitem\iSubItem    = iColumn
  _lvitem\pszText     = *Buffer
  _lvitem\cchTextMax  = 255
  
  For iCounter = 0 To iNumberOfEntries
    SendMessage_(hWnd, #LVM_GETITEMTEXT, iCounter, @_lvitem)
    sItem = PeekS(_lvitem\pszText)
    Debug "BuildGroups/sItem = " + sItem
    
    ResetList(sGrouplist())
    While NextElement(sGrouplist())
      iGroupFound = #False
      If sGrouplist() = sItem
        iGroupFound = #True
        Break
      EndIf
    Wend
    If Not iGroupFound
      AddElement(sGrouplist())
      sGrouplist() = sItem
    EndIf
  Next
  Debug "# of groups = " +ListSize(sGrouplist())
  
  ; --- set  groups
  iCounter = 0
  
  ResetList(sGrouplist())
  While NextElement(sGrouplist())
    _lvgroup\pszHeader = @sGrouplist()
    _lvgroup\cchHeader = Len(sGrouplist())
    _lvgroup\iGroupId  = iCounter
    _lvgroup\uAlign    = #LVGA_HEADER_LEFT
    SendMessage_(hWnd, #LVM_INSERTGROUP, 0, @_lvgroup)      ; wParam = Index where the group is being added (-1 -> at the end) // lParam = Pointer to LVGROUP
    iCounter + 1
  Wend
  

  ; --- assign the lv items to the groups
  For iCounter = 0 To iNumberOfEntries
    FillMemory(@_lvitem, SizeOf(LVITEM))                ; clear the structure
    _lvitem\mask        = #LVIF_TEXT                    ; get the text of the cell
    _lvitem\iSubItem    = iColumn
    _lvitem\pszText     = *Buffer
    _lvitem\cchTextMax  = 255
    SendMessage_(hWnd, #LVM_GETITEMTEXT, iCounter, @_lvitem)
    sItem = PeekS(_lvitem\pszText)
    Debug "Assign items to groups/sItem = " + sItem
    
    ResetList(sGrouplist())
    While NextElement(sGrouplist())
      If sItem = sGrouplist()
        Break
      EndIf
    Wend
    
    FillMemory(@_lvitem, SizeOf(LVITEM))                ; clear the structure
    _lvitem\mask     = #LVIF_GROUPID                    ; set item to specific group
    _lvitem\iItem    = iCounter
    _lvitem\iGroupId = ListIndex(sGrouplist()) 
    Debug "SendMessage/setitem = " + SendMessage_(hWnd, #LVM_SETITEM, #Null, @_lvitem)
  Next
  
  FreeMemory(*Buffer)
  
EndProcedure



OpenWindow(99, 200, 200, 300, 300, "LV Group")
handleLV = ListIconGadget(#PB_Any, 0, 0, 300, 300, "Column 0", 50, #PB_ListIcon_GridLines | #PB_ListIcon_FullRowSelect)

For iCounter = 1 To 3
  AddGadgetColumn(handleLV, iCounter, "Column " + Str(iCounter), 50)
Next

For iCounter = 1 To 5
  AddGadgetItem(handleLV, -1, "Column 0 / " + Str(iCounter) + Chr(10) + "1" + Chr(10) + "Column 2 / " + Str(iCounter) + Chr(10) + "Column 3 / " + Str(iCounter) + Chr(10))
Next

For iCounter = 6 To 10
  AddGadgetItem(handleLV, -1, "Column 0 / " + Str(iCounter) + Chr(10) + "2" + Chr(10) + "Column 2 / " + Str(iCounter) + Chr(10) + "Column 3 / " + Str(iCounter) + Chr(10))
Next

MainviewShowGrouped(GadgetID(handleLV), 1)
Debug "left procedure"

Repeat 
Until WaitWindowEvent() = #PB_Event_CloseWindow
Any idea why the program stops to respond?

Greetz,
Fenix
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Listview (listicon) with groups freezes

Post by srod »

Seems to be a bug with ListView groups and gridlines. Remove the grid lines and it all seems to work here. PB custom draws the grid lines and so there is probably a problem with PB's message handling here. If you confirm this then post a bug report.

You have a problem though assigning titles to your groups.

sGrouplist() is not actually giving you the address of the character buffer of the string, but a pointer to a .STRING structure.

Use the following :

Code: Select all

  ResetList(sGrouplist())
  While NextElement(sGrouplist())
    *ptr.STRING = @sGrouplist()
    _lvgroup\pszHeader = @*ptr\s
    _lvgroup\cchHeader = Len(sGrouplist())+2
    _lvgroup\iGroupId  = iCounter
    _lvgroup\uAlign    = #LVGA_HEADER_LEFT
    SendMessage_(hWnd, #LVM_INSERTGROUP, 0, @_lvgroup)      ; wParam = Index where the group is being added (-1 -> at the end) // lParam = Pointer to LVGROUP
    iCounter + 1
  Wend
I may look like a mule, but I'm not a complete ass.
Fenix
Enthusiast
Enthusiast
Posts: 102
Joined: Wed May 07, 2003 1:45 am
Location: Germany

Re: Listview (listicon) with groups freezes

Post by Fenix »

Thanks srod :D
srod wrote:Seems to be a bug with ListView groups and gridlines. Remove the grid lines and it all seems to work here. PB custom draws the grid lines and so there is probably a problem with PB's message handling here. If you confirm this then post a bug report.
Same here too: With gridlines the program freezes, without it works fine. Gonna post a bug report for that.
srod wrote:You have a problem though assigning titles to your groups.

sGrouplist() is not actually giving you the address of the character buffer of the string, but a pointer to a .STRING structure.

Use the following :

Code: Select all

  ResetList(sGrouplist())
  While NextElement(sGrouplist())
    *ptr.STRING = @sGrouplist()
    _lvgroup\pszHeader = @*ptr\s
    _lvgroup\cchHeader = Len(sGrouplist())+2
    _lvgroup\iGroupId  = iCounter
    _lvgroup\uAlign    = #LVGA_HEADER_LEFT
    SendMessage_(hWnd, #LVM_INSERTGROUP, 0, @_lvgroup)      ; wParam = Index where the group is being added (-1 -> at the end) // lParam = Pointer to LVGROUP
    iCounter + 1
  Wend
Works now. Well, it stops freezing but I can't see the groups. The list's empty :!: :?:
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Listview (listicon) with groups freezes

Post by srod »

Works fine here (am using PB x86 mind).

Wouldn't bother with a bug report since you are using API here, i.e. groups are not a supported feature of PB listicons. :)

**EDIT : whoops, try the following :

Code: Select all

  ResetList(sGrouplist())
  While NextElement(sGrouplist())
    *ptr.STRING = @sGrouplist()
    _lvgroup\pszHeader = @*ptr\s
    _lvgroup\cchHeader = Len(*ptr\s)+2
    _lvgroup\iGroupId  = iCounter
    _lvgroup\uAlign    = #LVGA_HEADER_LEFT
    SendMessage_(hWnd, #LVM_INSERTGROUP, 0, @_lvgroup)      ; wParam = Index where the group is being added (-1 -> at the end) // lParam = Pointer to LVGROUP
    iCounter + 1
  Wend
I may look like a mule, but I'm not a complete ass.
Fenix
Enthusiast
Enthusiast
Posts: 102
Joined: Wed May 07, 2003 1:45 am
Location: Germany

Re: Listview (listicon) with groups freezes

Post by Fenix »

srod wrote:Works fine here (am using PB x86 mind).

Wouldn't bother with a bug report since you are using API here, i.e. groups are not a supported feature of PB listicons. :)
Okay, I trashed the post :)

I compiled the code with and without unicode, but it's still a no show. Although I checked the items after creating the groups and assigning them to it (I added the following code just before FreeMemory(*Buffer)).

Code: Select all

  _lvitem\mask        = #LVIF_TEXT
  _lvitem\iSubItem    = iColumn
  _lvitem\pszText     = *Buffer
  _lvitem\cchTextMax  = 255
  
  For iCounter = 0 To iNumberOfEntries - 1
    SendMessage_(hWnd, #LVM_GETITEMTEXT, iCounter, @_lvitem)
    sItem = PeekS(_lvitem\pszText)
    Debug "sItem after grouping = " + sItem
  Next
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Listview (listicon) with groups freezes

Post by srod »

Confirmed... a no show with PB 5.21LTS x64.

Looking...
I may look like a mule, but I'm not a complete ass.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Listview (listicon) with groups freezes

Post by srod »

Seems to be a structure / structure alignments problem...
I may look like a mule, but I'm not a complete ass.
Fenix
Enthusiast
Enthusiast
Posts: 102
Joined: Wed May 07, 2003 1:45 am
Location: Germany

Re: Listview (listicon) with groups freezes

Post by Fenix »

srod wrote:Seems to be a structure / structure alignments problem...
Hm... odd. I'm using the structure delivered by PB. There's an alignment padding in it.

What'S curios, ist, that I found a working example (http://www.purebasic.fr/english/viewtop ... icon+group) that compiles fine unter x64 :|

It's not that different from my code. It enables the groupview first, then builds the groups and finally assigns the items to those groups...
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Listview (listicon) with groups freezes

Post by srod »

The following works here :

Code: Select all

Structure LVGROUP1  Align #PB_Structure_AlignC
  cbSize.l
  mask.l
  *pszHeader
  cchHeader.l
  *pszFooter
  cchFooter.l
  iGroupId.l
  stateMask.l
  state.l
  uAlign.l
  *pszSubtitle
  cchSubtitle.l
  *pszTask
  cchTask.l
  *pszDescriptionTop
  cchDescriptionTop.l
  *pszDescriptionBottom
  cchDescriptionBottom.l
  iTitleImage.l
  iExtendedImage.l
  iFirstItem.l
  cItems.l
  *pszSubsetTitle
  cchSubsetTitle.l
EndStructure

Procedure MainviewShowGrouped(hWnd.i, iColumn.i)
  ; --- groups the items of a listview
  ; ---
  ; --- Parameter:
  ; --- hWnd.i            = window (listview) handle
  ; --- iColumn.i         = column to group by
  
  Protected iNumberOfEntries.i
  Protected iGroupFound.i           ; used to determine if a group already exits -> true, then no new group is added
  Protected iCounter.i
  Protected sItem.s                 ; holds the item text 
  
  Protected _lvitem.LVITEM
  Protected _lvgroup.LVGROUP1

  Protected NewList sGrouplist.s()  ; stores the different groups we use

  
  SendMessage_(hWnd, #LVM_ENABLEGROUPVIEW , #True, 0)
  
  _lvGroup\cbSize = SizeOf(LVGROUP1)
  _lvGroup\mask   = #LVGF_HEADER | #LVGF_GROUPID | #LVGF_ALIGN | #LVGF_STATE     ; set fields of the LVGROPU structure that are to be used later on
  _lvgroup\state  = #LVGS_COLLAPSIBLE
  
  
  ; -> build the Grouplist
  iNumberOfEntries = SendMessage_(hWnd, #LVM_GETITEMCOUNT, #Null, #Null) - 1
  Debug "Entries = " + iNumberOfEntries
  
  Protected *Buffer
  *Buffer = AllocateMemory(512)
  If Not (*Buffer)
    ProcedureReturn 
  EndIf
  
  _lvitem\mask        = #LVIF_TEXT
  _lvitem\iSubItem    = iColumn
  _lvitem\pszText     = *Buffer
  _lvitem\cchTextMax  = 255
  
  For iCounter = 0 To iNumberOfEntries
    SendMessage_(hWnd, #LVM_GETITEMTEXT, iCounter, @_lvitem)
    sItem = PeekS(_lvitem\pszText)
    Debug "BuildGroups/sItem = " + sItem
    
    ResetList(sGrouplist())
    While NextElement(sGrouplist())
      iGroupFound = #False
      If sGrouplist() = sItem
        iGroupFound = #True
        Break
      EndIf
    Wend
    If Not iGroupFound
      AddElement(sGrouplist())
      sGrouplist() = sItem
    EndIf
  Next
  Debug "# of groups = " +ListSize(sGrouplist())
  
  ; --- set  groups
  iCounter = 0
  
  ResetList(sGrouplist())
  While NextElement(sGrouplist())
    *ptr.STRING = @sGrouplist()
    _lvgroup\pszHeader = @"TEST!"
    _lvgroup\cchHeader = 7
    _lvgroup\iGroupId  = iCounter
    _lvgroup\uAlign    = #LVGA_HEADER_LEFT
Debug    SendMessage_(hWnd, #LVM_INSERTGROUP, 0, @_lvgroup)      ; wParam = Index where the group is being added (-1 -> at the end) // lParam = Pointer to LVGROUP
    iCounter + 1
  Wend
  

  ; --- assign the lv items to the groups
  For iCounter = 0 To iNumberOfEntries
    FillMemory(@_lvitem, SizeOf(LVITEM))                ; clear the structure
    _lvitem\mask        = #LVIF_TEXT                    ; get the text of the cell
    _lvitem\iSubItem    = iColumn
    _lvitem\pszText     = *Buffer
    _lvitem\cchTextMax  = 255
    SendMessage_(hWnd, #LVM_GETITEMTEXT, iCounter, @_lvitem)
    sItem = PeekS(_lvitem\pszText)
    Debug "Assign items to groups/sItem = " + sItem
    
    ResetList(sGrouplist())
    While NextElement(sGrouplist())
      If sItem = sGrouplist()
        Break
      EndIf
    Wend
    
    FillMemory(@_lvitem, SizeOf(LVITEM))                ; clear the structure
    _lvitem\mask     = #LVIF_GROUPID                    ; set item to specific group
    _lvitem\iItem    = iCounter
    _lvitem\iGroupId = ListIndex(sGrouplist()) 
    Debug "SendMessage/setitem = " + SendMessage_(hWnd, #LVM_SETITEM, #Null, @_lvitem)
  Next
  
  FreeMemory(*Buffer)
  
EndProcedure



OpenWindow(99, 200, 200, 300, 300, "LV Group")
handleLV = ListIconGadget(#PB_Any, 0, 0, 300, 300, "Column 0", 50)

For iCounter = 1 To 3
  AddGadgetColumn(handleLV, iCounter, "Column " + Str(iCounter), 50)
Next

For iCounter = 1 To 5
  AddGadgetItem(handleLV, -1, "Column 0 / " + Str(iCounter) + Chr(10) + "1" + Chr(10) + "Column 2 / " + Str(iCounter) + Chr(10) + "Column 3 / " + Str(iCounter) + Chr(10))
Next

For iCounter = 6 To 10
  AddGadgetItem(handleLV, -1, "Column 0 / " + Str(iCounter) + Chr(10) + "2" + Chr(10) + "Column 2 / " + Str(iCounter) + Chr(10) + "Column 3 / " + Str(iCounter) + Chr(10))
Next

MainviewShowGrouped(GadgetID(handleLV), 1)
Debug "left procedure"

Repeat 
Until WaitWindowEvent() = #PB_Event_CloseWindow
I may look like a mule, but I'm not a complete ass.
Fenix
Enthusiast
Enthusiast
Posts: 102
Joined: Wed May 07, 2003 1:45 am
Location: Germany

Re: Listview (listicon) with groups freezes

Post by Fenix »

Works fine here too. Thanks again, srod! :D

As far as I understand the Align token, it means, that each element of the structure get's aligned to the C standard? But in the PB defined structure are paddings as well. Why don't they work?
Is it possible, that other PB defined structures (at least the WinAPI one's) need that aligning too?

Greetz,
Fenix
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Listview (listicon) with groups freezes

Post by srod »

Well, the problem fields are the two string fields which need to be 8-byte aligned as all other fields are defined to be 32-bit, even on x64.

You could use the following which should work on both platforms :

Code: Select all

Structure LVGROUP1  
  cbSize.l
  mask.l
  *pszHeader
  cchHeader.l
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64 
    pad1.l
  CompilerEndIf
  *pszFooter
  cchFooter.l
  iGroupId.l
  stateMask.l
  state.l
  uAlign.l
EndStructure
I may look like a mule, but I'm not a complete ass.
Fenix
Enthusiast
Enthusiast
Posts: 102
Joined: Wed May 07, 2003 1:45 am
Location: Germany

Re: Listview (listicon) with groups freezes

Post by Fenix »

srod wrote:Well, the problem fields are the two string fields which need to be 8-byte aligned as all other fields are defined to be 32-bit, even on x64.
Okay, than I know where to look at, if I encouter a bug and strings in a structure are involved.
Learning by doing :)
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Listview (listicon) with groups freezes

Post by srod »

Yes if something runs ok in x86, but fails in x64 then the first place to look is usually integer variables; make sure they are large enough to accommodate whatever values might be thrown into them. After this, look carefully at structures. In particular, a crash on x64 could well be due to the fact that some structure is too small and some API function is then attempting to write beyond that chunk of memory because it is expecting a larger structure etc. Structure fields defined as .l when they should be .i are the usual culprit. Beyond this (as with LV_GROUP), then look at the alignment and padding etc.

With your code as soon as I saw the crash on x64, I just knew it had to be a structure issue. :)

It's all good fun. :)
I may look like a mule, but I'm not a complete ass.
Post Reply