Class VFXGridState<T, C extends VFXCell<T>>
VFXGrid in a specific moment in time. In other words, each and
every state is given by a unique combination of the grid's properties (in terms of values).
The state carries four important pieces of information:
1) The range of rows to display
2) The range of columns to display
3) The cells that are currently in the viewport
4) A flag that indicates whether cells have changed since the last state
Note: the combination of 1 and 2 determines the point 3, so the items to display from VFXGrid.itemsProperty()
VFXGrid's "infrastructure", the state was one of the first classes to be written since
it is crucial to display the needed items. When you already have a good and stable example to look at
(in my case VFXList) it's only natural to try and follow it as much as possible. Other than adding another
IntegerRange variable (rows and columns), there's nothing new here compared to VFXListState.
However, because we have two ranges, an issue arises on how to store the cells; we can't map indexes to cells right,
we would have to store them by [r, c] coordinates right?
Actually, we can, and the concept I'm going to explain here is crucial and used pretty much everywhere in the
grid's "infrastructure". To be clear, yes, we could create a wrapper class to represent a coordinate, but that would
mean that the specialized data structure IndexBiMap.StateMap could not be used. We would need to adapt it to use our
Coordinate class, which inevitably would lead to code duplication.
To begin with, the grid's underlying data structure is one dimensional, a plain and simple ObservableList.
This means that item 0 is in the cell at coordinates [0, 0], item 1 would be at coordinates [0, 1] and so on.
Of course, it also depends on the number of columns and rows.
The important thing to notice here is that essentially what the grid implicitly does is converting a position from the list to a pair of coordinates. Well, we can also do the opposite, starting from the two ranges, we can get the corresponding position in the list for each pair of coordinates.
Linear Index: A linear index refers to a single integer value used to access an element in a one-dimensional array or a multidimensional array that has been flattened into a one-dimensional sequence. In other words, it's a way to map the element's position in the array to a single integer. For example, in a 1D array, linear indexing is straightforward: each element has a unique linear index corresponding to its position in the array. However, in a multidimensional array, elements can be indexed using linear indexing by treating the array as if it were one long sequence of elements, often following a row-major or column-major order.
Subscripts: Subscripts are used to refer to the indices of individual dimensions in a multidimensional array. Each dimension of the array has its own subscript. For example, in a 2D array, you might have subscripts (i, j), where 'i' refers to the row index and 'j' refers to the column index. The conversion from a pair of coordinates to a linear index is done by the utilityGridUtils.subToInd(int, int, int).
This strategy brings two main consequences:
1) the cells are still stored in a IndexBiMap.StateMap, but the index used in the mapping is the linear index.
Which means that if you want to get the coordinates, you'll have to convert them back using GridUtils.indToSub(int, int).
2) this is the first time in my Java developer career I use labels to break out of loops. You see when you use two nested
for loops to iterate over the rows and columns ranges, it may happen that the resulting linear index is non-existing
in the list. In other words, the linear index is greater than itemsNum - 1. In such cases, it's useless to
continue the iterations. By placing the label above the external loop, we are able to immediately break out of the
nested loop, and as you may guess, this is indeed a nice performance optimization. An example of when this may
happen is in case of incomplete rows/columns.
outer_loop:
for (rIdx : rowsRange) {
for (cIdx : columnsRange) {
...
...
if (...) break outer_loop;
}
}
- See Also:
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final VFXGridStateSpecial instance ofVFXGridStateused to indicate that no cells can be present in the viewport at a certain time. -
Constructor Summary
ConstructorsConstructorDescriptionVFXGridState(VFXGrid<T, C> grid, io.github.palexdev.mfxcore.base.beans.range.IntegerRange rowsRange, io.github.palexdev.mfxcore.base.beans.range.IntegerRange columnsRange) -
Method Summary
Modifier and TypeMethodDescriptionprotected voidConverts the given row and column indexes to a linear index and delegates toaddCell(int, Object, VFXCell).protected voidDelegates toaddCell(int, Object, VFXCell).protected voidAdds the given cell to theIndexBiMap.StateMapof this state object.protected voiddispose()Disposes this state object by: caching all the cells (VFXCellsCache.cache(Collection)), and then clearing theIndexBiMap.StateMapby callingIndexBiMap.clear().protected IndexBiMap.StateMap<T, C> getCells()protected SequencedMap<Integer, C> io.github.palexdev.mfxcore.base.beans.range.IntegerRangegetGrid()getNodes()io.github.palexdev.mfxcore.base.beans.range.IntegerRangebooleanbooleanisEmpty()protected CremoveCell(int index) Removes a cell from theIndexBiMap.StateMapfor the given linear index.protected CremoveCell(int rIndex, int cIndex) Delegates toremoveCell(int)by first converting the given row and column indexes to a linear index.protected CremoveCell(T item) Removes a cell from theIndexBiMap.StateMapfor the given item.protected voidsetCellsChanged(boolean cellsChanged) intsize()
-
Field Details
-
INVALID
Special instance ofVFXGridStateused to indicate that no cells can be present in the viewport at a certain time. The reasons can be many, for example, no cell factory, invalid range, width/height <= 0, etc...This and
isEmpty()are two total different things!!
-
-
Constructor Details
-
VFXGridState
-
-
Method Details
-
addCell
Converts the given row and column indexes to a linear index and delegates toaddCell(int, Object, VFXCell). -
addCell
Delegates toaddCell(int, Object, VFXCell). -
addCell
Adds the given cell to theIndexBiMap.StateMapof this state object. -
removeCell
Delegates toremoveCell(int)by first converting the given row and column indexes to a linear index. -
removeCell
Removes a cell from theIndexBiMap.StateMapfor the given linear index. If the cell is not found, the next attempt is to remove it by the item at the given linear index in theVFXGrid.itemsProperty(). -
removeCell
Removes a cell from theIndexBiMap.StateMapfor the given item. -
dispose
protected void dispose()Disposes this state object by: caching all the cells (VFXCellsCache.cache(Collection)), and then clearing theIndexBiMap.StateMapby callingIndexBiMap.clear().- See Also:
-
getGrid
-
getRowsRange
public io.github.palexdev.mfxcore.base.beans.range.IntegerRange getRowsRange()- Returns:
- the range of rows to display
-
getColumnsRange
public io.github.palexdev.mfxcore.base.beans.range.IntegerRange getColumnsRange()- Returns:
- the range of columns to display
-
getCells
- Returns:
- the map containing the cells
- See Also:
-
getCellsByIndex
- Returns:
- the map containing the cells by their index
-
getCellsByItem
-
getCellsByIndexUnmodifiable
- Returns:
- the map containing the cells by their index, unmodifiable
-
getCellsByItemUnmodifiable
-
getNodes
- Returns:
- converts the cells' map to a list of nodes by calling
VFXCell.toNode()on each cell
-
size
public int size()- Returns:
- the number of cells in the
IndexBiMap.StateMap
-
isEmpty
public boolean isEmpty()- Returns:
- whether the
IndexBiMap.StateMapis empty - See Also:
-
haveCellsChanged
public boolean haveCellsChanged()- Returns:
- whether the cells have changed since the last state. This is used to indicate if more or less cells are present in this state compared to the old one. Used by the default skin to check whether the viewport has to update its children or not.
- See Also:
-
setCellsChanged
protected void setCellsChanged(boolean cellsChanged) - See Also:
-