Listbox 101

I have a listbox with a list of words. When I scroll down and select one I redraw the contents making a slight change to the selected word. At the moment it selects the first word at the top after the repopulation of the listbox.
How do I get it to show the contents looking like it is in the same position as before the update?

You could retain and restore the position and selection, or you could not RemoveAllRows and only update what’s necessary.

1 Like

Hi Tim,
In Cellclicked event
me.ScrollPosition = row + ?
Puts me back to seeing the last click value at the top of the listbox but how do I know how may rows are currently displayed in the listbox on the current window so I can calc?

To restore the original scroll (if the selection isn’t at the top), retain the original ScrollPosition.

var iPos as Integer = me.ScrollPosition

me.RemoveAllRows
// Repopulate

me.ScrollPosition = iPos

You can know the number of rows with Listbox.RowCount. If you mean that you want to know how many rows tall the Listbox is,

Listbox.Height / Listbox.DefaultRowHeight

Hopefully one of those three ideas helps you solve your issue. I’m not entirely sure I’m understanding what you’re looking for. If I’m reloading a list and want it to return to the original position I use the first method.

1 Like

Thanks Tim :+1:

What I usually do is populating an array with RowIDs.
These IDs are record IDs I store in the RowTag value.

I get these IDs right before I remove all rows.

When populating the Listbox again, with data, I do two things:

  1. Check if the ID of the (new) row data is in this array. And set the RowSelectedAt to True, if it is.
  2. Set a row-index variable if the first selected row is found.

If this second variable is set, I use that to that row index variable to set the scroll position.

In a Method “PopulateList()” I usually have something like this:

// sel() is an array that will hold all RowIDs of the selected rows.
Var id, sel() As String
Var row As Integer

// lb is a listbox
If lb.SelectedRowCount = 1 Then
  
  row = lb.SelectedRowIndex
  id = lb.RowTagAt(row).StringValue
  sel = Array( id )
  
ElseIf lb.SelectedRowCount > 1 Then
  
  // iterate through the list, to get all the 
  For row = lb.SelectedRowIndex To lb.LastRowIndex
    
    // if a row is selected, add its ID to the "sel" array
    If lb.RowSelectedAt(row) Then
      id = lb.RowTagAt(row).StringValue
      sel.Add id
    End
  Next
  
End

// Now we have a collection of all the selected rows, we can clear the list.
lb.RemoveAllRows

// sRow will be the row index of the first selected row in the list.
Var sRow As Integer = -1

Var rs As RowSet = getOrders // GetOrders is a function that returns a RowSet with data from a database.
If rs.RowCount = 0 Then Return // exit when there are no rows in the RowSet

Var isSel As Boolean

For Each dRow As DatabaseRow In rs
  // get the ID for the record
  id = dRow.Column("id").StringValue
  
  // in case the id is found in the "sel" array, set the isSel variable to True
  isSel = (sel.IndexOf( id ) > -1)
  
  // Add a row to the listbox, and set it's rowID in the RowTag value
  lb.AddRow dRow.Column("OrderNumber").StringValue, dRow.Column("OrderDescription").StringValue
  row = lb.LastAddedRowIndex
  lb.RowTagAt(row) = id
  
  // Set the selection of the row
  lb.RowSelectedAt(row) = isSel
  
  // if the row is selected, and the sRow value  is still < 0, set the sRow value to the current RowIndex
  If isSel And sRow < 0 Then sRow = row
Next

// This line of code will simply set the scroll position. After this, populating the listbox is done.
' If sRow > -1 Then lb.ScrollPosition = sRow


// But lets get fancy, and set the scroll the list, so that the first selected row is in the middle of the view.
// That's why I commented-out the line of code above
Var rowHeight As Integer = lb.DefaultRowHeight
Var lbHeight As Integer = lb.Height
If lb.HasHeader Then lbHeight = lbHeight - lb.HeaderHeight

// Calculate the visible rows in the list. And get the offset, so that we can scroll to the right scroll position.
Var visibleRows As Integer = lbHeight / rowHeight
Var rowOffset As Integer
If visibleRows > rs.RowCount Then
  rowOffset = visibleRows / 2
End

// Adjust the sRow so that the first selected row appears in the middle of the list.
// But make sure it is never lower than 0… that's the Max() function is for.
sRow = Max(sRow - rowOffset, 0)

lb.ScrollPosition = sRow
2 Likes

Thanks Edwin for the input… next level :slight_smile:

Yeah, not really a 101 kind of input. Sorry about that…

The real next-level would be to not set the selected row in the middle, but keep that selected row at the same position as it was before.
Like, if the first visible selected row is the 4th from the top, scroll the list so that selected row is again at that 4th position. No matter how many rows were added or deleted before or after that row.

1 Like