We have detected that cookies are not enabled on your browser. Please enable cookies to ensure the proper experience.
Results 1 to 3 of 3
  1. #1
    Join Date
    Mar 2007
    Posts
    1,191

    ListBox:Sort() causes index errors

    Using the ListBox:Sort() method causes issues with the listbox's internal indexes for its elements so that other methods like RemoveItemAt() and ClearItems() no longer function properly. I first noticed this when, after sorting a listbox control, I called ClearItems and would sometimes have items still displayed in the listbox even though GetItemCount() returned 0 and the items were no longer controllable. I did a bit of research and realized that even using RemoveItemAt() would leave ghost items because it seemed to be leaving a gap in the internal list of indexes so that calling GetItem() for that index returned nil and one of the legitimate items became unaccessible.

    An example of this can be seen with the following code segments:
    Code:
    local index;
    local items={"duidei","dfaho","oubo","avoaleb","coabfe","dubso","oaiubd","aldfhu","fsouhde"}
    itemList=Turbine.UI.ListBox()
    for index=1,#items do
     local tmpItem=Turbine.UI.Label()
     local tmpVal=items[index]
     tmpItem:SetParent(itemList)
     tmpItem:SetSize(100,20)
     tmpItem:SetText("val="..tostring(tmpVal).." orig_index="..tostring(index) )
     tmpItem.index=index
     itemList:AddItem(tmpItem)
    end
    Turbine.Shell.WriteLine("before removal")
    for index=1,itemList:GetItemCount() do
      if itemList:GetItem(index) == nil then
         Turbine.Shell.WriteLine("item at:"..tostring(index).." is nil")
      else
         Turbine.Shell.WriteLine("item at:"..tostring(index).." orig_index="..tostring(itemList:GetItem(index).index))
      end
    end
    itemList:RemoveItemAt(5)
    Turbine.Shell.WriteLine("after removal")
    for index=1,itemList:GetItemCount() do
      if itemList:GetItem(index) == nil then
         Turbine.Shell.WriteLine("item at:"..tostring(index).." is nil")
      else
         Turbine.Shell.WriteLine("item at:"..tostring(index).." orig_index="..tostring(itemList:GetItem(index).index))
      end
    end
    Using this code works correctly, the entry at index 5 is removed.
    But, by adding a sort and removing the item at index 5:
    Code:
    local index;
    local items={"duidei","dfaho","oubo","avoaleb","coabfe","dubso","oaiubd","aldfhu","fsouhde"}
    itemList=Turbine.UI.ListBox()
    for index=1,#items do
     local tmpItem=Turbine.UI.Label()
     local tmpVal=items[index]
     tmpItem:SetParent(itemList)
     tmpItem:SetSize(100,20)
     tmpItem:SetText("val="..tostring(tmpVal).." orig_index="..tostring(index) )
     tmpItem.index=index
     itemList:AddItem(tmpItem)
    end
    Turbine.Shell.WriteLine("before sort")
    for index=1,itemList:GetItemCount() do
      if itemList:GetItem(index) == nil then
         Turbine.Shell.WriteLine("item at:"..tostring(index).." is nil")
      else
         Turbine.Shell.WriteLine("item at:"..tostring(index).." orig_index="..tostring(itemList:GetItem(index).index))
      end
    end
    itemList:Sort(function(elem1,elem2) if elem1:GetText()<elem2:GetText() then return true end end)
    Turbine.Shell.WriteLine("before removal")
    for index=1,itemList:GetItemCount() do
      if itemList:GetItem(index) == nil then
         Turbine.Shell.WriteLine("item at:"..tostring(index).." is nil")
      else
         Turbine.Shell.WriteLine("item at:"..tostring(index).." orig_index="..tostring(itemList:GetItem(index).index))
      end
    end
    itemList:RemoveItemAt(5)
    Turbine.Shell.WriteLine("after removal")
    for index=1,itemList:GetItemCount() do
      if itemList:GetItem(index) == nil then
         Turbine.Shell.WriteLine("item at:"..tostring(index).." is nil")
      else
         Turbine.Shell.WriteLine("item at:"..tostring(index).." orig_index="..tostring(itemList:GetItem(index).index))
      end
    end
    we get a nil item at index 3 which contained the entry that was ORIGINALLY (before the sort) at index 5. Somehow, the sort is not updating the internal index of the entry so the wrong entry is getting removed and is leaving an inaccessible entry.

  2. #2
    Join Date
    May 2009
    Posts
    176
    Quote Originally Posted by Garan View Post
    Using the ListBox:Sort() method causes issues with the listbox's internal indexes for its elements so that other methods like RemoveItemAt() and ClearItems() no longer function properly. I first noticed this when, after sorting a listbox control, I called ClearItems and would sometimes have items still displayed in the listbox even though GetItemCount() returned 0 and the items were no longer controllable. I did a bit of research and realized that even using RemoveItemAt() would leave ghost items because it seemed to be leaving a gap in the internal list of indexes so that calling GetItem() for that index returned nil and one of the legitimate items became unaccessible.

    An example of this can be seen with the following code segments:
    Code:
    local index;
    local items={"duidei","dfaho","oubo","avoaleb","coabfe","dubso","oaiubd","aldfhu","fsouhde"}
    itemList=Turbine.UI.ListBox()
    for index=1,#items do
     local tmpItem=Turbine.UI.Label()
     local tmpVal=items[index]
     tmpItem:SetParent(itemList)
     tmpItem:SetSize(100,20)
     tmpItem:SetText("val="..tostring(tmpVal).." orig_index="..tostring(index) )
     tmpItem.index=index
     itemList:AddItem(tmpItem)
    end
    Turbine.Shell.WriteLine("before removal")
    for index=1,itemList:GetItemCount() do
      if itemList:GetItem(index) == nil then
         Turbine.Shell.WriteLine("item at:"..tostring(index).." is nil")
      else
         Turbine.Shell.WriteLine("item at:"..tostring(index).." orig_index="..tostring(itemList:GetItem(index).index))
      end
    end
    itemList:RemoveItemAt(5)
    Turbine.Shell.WriteLine("after removal")
    for index=1,itemList:GetItemCount() do
      if itemList:GetItem(index) == nil then
         Turbine.Shell.WriteLine("item at:"..tostring(index).." is nil")
      else
         Turbine.Shell.WriteLine("item at:"..tostring(index).." orig_index="..tostring(itemList:GetItem(index).index))
      end
    end
    Using this code works correctly, the entry at index 5 is removed.
    But, by adding a sort and removing the item at index 5:
    Code:
    local index;
    local items={"duidei","dfaho","oubo","avoaleb","coabfe","dubso","oaiubd","aldfhu","fsouhde"}
    itemList=Turbine.UI.ListBox()
    for index=1,#items do
     local tmpItem=Turbine.UI.Label()
     local tmpVal=items[index]
     tmpItem:SetParent(itemList)
     tmpItem:SetSize(100,20)
     tmpItem:SetText("val="..tostring(tmpVal).." orig_index="..tostring(index) )
     tmpItem.index=index
     itemList:AddItem(tmpItem)
    end
    Turbine.Shell.WriteLine("before sort")
    for index=1,itemList:GetItemCount() do
      if itemList:GetItem(index) == nil then
         Turbine.Shell.WriteLine("item at:"..tostring(index).." is nil")
      else
         Turbine.Shell.WriteLine("item at:"..tostring(index).." orig_index="..tostring(itemList:GetItem(index).index))
      end
    end
    itemList:Sort(function(elem1,elem2) if elem1:GetText()<elem2:GetText() then return true end end)
    Turbine.Shell.WriteLine("before removal")
    for index=1,itemList:GetItemCount() do
      if itemList:GetItem(index) == nil then
         Turbine.Shell.WriteLine("item at:"..tostring(index).." is nil")
      else
         Turbine.Shell.WriteLine("item at:"..tostring(index).." orig_index="..tostring(itemList:GetItem(index).index))
      end
    end
    itemList:RemoveItemAt(5)
    Turbine.Shell.WriteLine("after removal")
    for index=1,itemList:GetItemCount() do
      if itemList:GetItem(index) == nil then
         Turbine.Shell.WriteLine("item at:"..tostring(index).." is nil")
      else
         Turbine.Shell.WriteLine("item at:"..tostring(index).." orig_index="..tostring(itemList:GetItem(index).index))
      end
    end
    we get a nil item at index 3 which contained the entry that was ORIGINALLY (before the sort) at index 5. Somehow, the sort is not updating the internal index of the entry so the wrong entry is getting removed and is leaving an inaccessible entry.
    Just checked in a change that should hopefully fix this.

  3. #3
    Thurallor, Warden of Landroval

 

 

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  

This form's session has expired. You need to reload the page.

Reload