ListBox
A column of rows the user picks from: a JList showing one row per item, reporting what the user selects.
Items are declarative data. By default each row renders its item's toString; supply itemContent to render an arbitrary composable cell per row (a Row of an icon, labels, ...). Selection is declared with selectedIndices and reported through onSelectionChange, expressed as the general multi-select shape so one component covers all of SelectionMode's modes. Place it in a org.jetbrains.compose.swing.components.layout.ScrollPane to scroll:
ScrollPane {
content {
ListBox(items = rows, selectedIndices = sel, onSelectionChange = { sel = it }) { row ->
FlowPanel { Label(row.icon); Label(row.name) }
}
}
}onSelectionChange reports the user's selection changes only, once per settled change - so dragging across rows produces one callback at the end rather than one per row crossed, and rendering new items produces none. A declared selection is the composition's state and is re-applied on every pass: it survives an items change (an index the current items no longer cover is dropped), and a user change the caller does not adopt does not stand. Undeclared, the selection is the user's alone - never imposed, and kept across an items change all the same; where the new items are too few to hold it, the rows that fall outside them leave the selection and onSelectionChange reports what is left of it.
layoutOrientation decides how the cells are laid out: a single column, or wrapped into as many columns or rows as the space the list is given allows. A wrapping list draws far more cells at once, and a list sizes itself by measuring them - one measurement per row through the renderer, and with a composable itemContent each of those is a cell stamped through a nested composition. Declaring a prototypeCellValue collapses that to a single measurement every cell is sized by; fixedCellWidth and fixedCellHeight state a size outright and spare it even that one.
Parameters
the items to display
the SwingModifier applied to the underlying component
the selected row indices the caller declares; null - the default - leaves the selection to the user
callback invoked when the user settles on a new selection
how many rows/ranges may be selected; MULTIPLE_INTERVAL_SELECTION - the default - lets the user select any number of ranges
how many rows the list asks a viewport to make room for; 8 is the default. Under VERTICAL_WRAP it is the number of rows a column holds before the cells wrap into the next one. Under HORIZONTAL_WRAP the list takes its column count from it and then fits the items into as few rows as those columns need, which can come out below the count asked for
whether the cells form a single column or wrap into columns or rows; VERTICAL - the default - is the single column
an item measured once, through the same renderer the rows use, to size every cell; null - the default - measures each row for itself
the width in pixels of every cell; -1 - the default - takes the width from prototypeCellValue, or from each row's own measurement where no prototype is declared
the height in pixels of every cell; -1 - the default - takes the height from prototypeCellValue, or from each row's own measurement where no prototype is declared
optional composable cell rendered per row against a ListItemScope; null keeps the default toString rendering
See also
A ListBox driven by a raw ListSelectionListener instead of an onSelectionChange lambda. The listener sees the adjusting events of a drag as well as the settled one, and is notified of the user's selection changes only; the latest declared instance is the one notified, so the listener may be declared inline.
Parameters
the items to display
the listener notified of the user's selection changes
the SwingModifier applied to the underlying component
the selected row indices the caller declares; null - the default - leaves the selection to the user
how many rows/ranges may be selected; MULTIPLE_INTERVAL_SELECTION - the default - lets the user select any number of ranges
how many rows the list asks a viewport to make room for; 8 is the default. Under VERTICAL_WRAP it is the number of rows a column holds before the cells wrap into the next one. Under HORIZONTAL_WRAP the list takes its column count from it and then fits the items into as few rows as those columns need, which can come out below the count asked for
whether the cells form a single column or wrap into columns or rows; VERTICAL - the default - is the single column
an item measured once, through the same renderer the rows use, to size every cell; null - the default - measures each row for itself
the width in pixels of every cell; -1 - the default - takes the width from prototypeCellValue, or from each row's own measurement where no prototype is declared
the height in pixels of every cell; -1 - the default - takes the height from prototypeCellValue, or from each row's own measurement where no prototype is declared
optional composable cell rendered per row against a ListItemScope; null keeps the default toString rendering
See also
A ListBox driven by a caller-owned ListModel instead of a declarative items list. The model is installed as-is and observed only: the library never mutates it, so element changes are the caller's responsibility. Selection is declared with selectedIndices and reported through onSelectionChange, and survives a model swap whether declared or not.
ScrollPane {
content {
ListBox(model = myModel, selectedIndices = sel, onSelectionChange = { sel = it })
}
}onSelectionChange reports the user's selection changes only, once per settled change - so dragging across rows produces one callback at the end rather than one per row crossed, and installing a new model produces none. A declared selection is the composition's state and is re-applied on every pass, so a user change the caller does not adopt does not stand; undeclared, the selection is the user's alone and is never imposed - where the new model is too short to hold it, the rows that fall outside it leave the selection and onSelectionChange reports what is left of it.
Parameters
the caller-owned list model to display; installed as-is and never mutated
the SwingModifier applied to the underlying component
the selected row indices the caller declares; null - the default - leaves the selection to the user
callback invoked when the user settles on a new selection
how many rows/ranges may be selected; MULTIPLE_INTERVAL_SELECTION - the default - lets the user select any number of ranges
how many rows the list asks a viewport to make room for; 8 is the default. Under VERTICAL_WRAP it is the number of rows a column holds before the cells wrap into the next one. Under HORIZONTAL_WRAP the list takes its column count from it and then fits the items into as few rows as those columns need, which can come out below the count asked for
whether the cells form a single column or wrap into columns or rows; VERTICAL - the default - is the single column
an item measured once, through the same renderer the rows use, to size every cell; null - the default - measures each row for itself
the width in pixels of every cell; -1 - the default - takes the width from prototypeCellValue, or from each row's own measurement where no prototype is declared
the height in pixels of every cell; -1 - the default - takes the height from prototypeCellValue, or from each row's own measurement where no prototype is declared
optional composable cell rendered per row against a ListItemScope; null keeps the default toString rendering
See also
A model-driven ListBox driven by a raw ListSelectionListener instead of an onSelectionChange lambda. The listener sees the adjusting events of a drag as well as the settled one, and is notified of the user's selection changes only; the latest declared instance is the one notified, so the listener may be declared inline.
The model is installed as-is and observed only: the library never mutates it, and the selection survives a model swap whether declared or not.
Parameters
the caller-owned list model to display; installed as-is and never mutated
the listener notified of the user's selection changes
the SwingModifier applied to the underlying component
the selected row indices the caller declares; null - the default - leaves the selection to the user
how many rows/ranges may be selected; MULTIPLE_INTERVAL_SELECTION - the default - lets the user select any number of ranges
how many rows the list asks a viewport to make room for; 8 is the default. Under VERTICAL_WRAP it is the number of rows a column holds before the cells wrap into the next one. Under HORIZONTAL_WRAP the list takes its column count from it and then fits the items into as few rows as those columns need, which can come out below the count asked for
whether the cells form a single column or wrap into columns or rows; VERTICAL - the default - is the single column
an item measured once, through the same renderer the rows use, to size every cell; null - the default - measures each row for itself
the width in pixels of every cell; -1 - the default - takes the width from prototypeCellValue, or from each row's own measurement where no prototype is declared
the height in pixels of every cell; -1 - the default - takes the height from prototypeCellValue, or from each row's own measurement where no prototype is declared
optional composable cell rendered per row against a ListItemScope; null keeps the default toString rendering
See also
A ListBox driven by a ListState instead of a declared selectedIndices and an onSelectionChange lambda. The state owns the selection: the rows it holds are what the list shows selected, the user's own selecting is written back into it, and it is where a row is revealed from.
val state = rememberListState()
ScrollPane {
ListBox(items = rows, state = state, modifier = SwingModifier.viewport())
}
Label("Selected: ${state.selectedIndices.size}")Parameters
the items to display
the hoistable selection state the list applies and reports into; see ListState
the SwingModifier applied to the underlying component
how many rows/ranges may be selected; MULTIPLE_INTERVAL_SELECTION - the default - lets the user select any number of ranges
how many rows the list asks a viewport to make room for; 8 is the default. Under VERTICAL_WRAP it is the number of rows a column holds before the cells wrap into the next one. Under HORIZONTAL_WRAP the list takes its column count from it and then fits the items into as few rows as those columns need, which can come out below the count asked for
whether the cells form a single column or wrap into columns or rows; VERTICAL - the default - is the single column
an item measured once, through the same renderer the rows use, to size every cell; null - the default - measures each row for itself
the width in pixels of every cell; -1 - the default - takes the width from prototypeCellValue, or from each row's own measurement where no prototype is declared
the height in pixels of every cell; -1 - the default - takes the height from prototypeCellValue, or from each row's own measurement where no prototype is declared
optional composable cell rendered per row against a ListItemScope; null keeps the default toString rendering
See also
A model-driven ListBox driven by a ListState instead of a declared selectedIndices and an onSelectionChange lambda. The state owns the selection: the rows it holds are what the list shows selected, the user's own selecting is written back into it, and it is where a row is revealed from.
The model is installed as-is and observed only: the library never mutates it, so element changes are the caller's responsibility, and the selection survives a model swap.
Parameters
the caller-owned list model to display; installed as-is and never mutated
the hoistable selection state the list applies and reports into; see ListState
the SwingModifier applied to the underlying component
how many rows/ranges may be selected; MULTIPLE_INTERVAL_SELECTION - the default - lets the user select any number of ranges
how many rows the list asks a viewport to make room for; 8 is the default. Under VERTICAL_WRAP it is the number of rows a column holds before the cells wrap into the next one. Under HORIZONTAL_WRAP the list takes its column count from it and then fits the items into as few rows as those columns need, which can come out below the count asked for
whether the cells form a single column or wrap into columns or rows; VERTICAL - the default - is the single column
an item measured once, through the same renderer the rows use, to size every cell; null - the default - measures each row for itself
the width in pixels of every cell; -1 - the default - takes the width from prototypeCellValue, or from each row's own measurement where no prototype is declared
the height in pixels of every cell; -1 - the default - takes the height from prototypeCellValue, or from each row's own measurement where no prototype is declared
optional composable cell rendered per row against a ListItemScope; null keeps the default toString rendering