Range Selection
Range selection allows Excel-like range selection of cells. Range selections are useful for visually highlighting data, copying data to the Clipboard, or for doing aggregations using the Status Bar.
Selecting Ranges
Range Selection is enabled using the following grid option EnableRangeSelection=true. When enabled, ranges can be selected in the following ways:
- Mouse Drag: Click the mouse down on a cell and drag and release the mouse over another cell. A range will be created between the two cells and clear any existing ranges.
- Ctrl & Mouse Drag: Holding Ctrl key while creating a range using mouse drag outside an existing range will create a new range selection and keep any existing ranges.
- Shift & Click: Clicking on one cell to focus that cell, then holding down Shift while clicking another cell, will create a range between both cells.
- Shift & Arrow Keys: Focusing a cell and then holding down Shift and using the arrow keys will create a range starting from the focused cell.
- Ctrl & Shift & Arrow Keys: Focusing a cell and then holding down Ctrl + Shift and using the arrow keys will create a range starting from the focused cell to the last cell in the direction of the Arrow pressed.
Range Deselection
It is possible to deselect part of existing ranges in the following ways:
- Ctrl & Mouse Drag: Holding Ctrl and dragging a range starting within an existing range will cause any cells covered by the new range to be deselected.
- Ctrl & Click: Holding Ctrl and clicking a cell will deselect just that cell.
Note that deselecting part of a range can split the range into multiple ranges, since individual ranges have the limitation of being rectangular.
The example below demonstrates simple range selection. Ranges can be selected in all the ways described above.
use ::BBjGridExWidget/BBjGridExWidget.bbj::BBjGridExWidgetuse ::BBjGridExWidget/GxClientModels.bbj::GxClientRowModeluse com.basiscomponents.db.ResultSetuse com.basiscomponents.bc.SqlQueryBCdeclare auto BBjTopLevelWindow wnd!wnd! = BBjAPI().openSysGui("X0").addWindow(10,10,800,600,"Checkbox Selection")wnd!.setCallback(BBjAPI.ON_CLOSE,"byebye")gosub mainprocess_eventsmain:  declare SqlQueryBC sbc!  declare ResultSet rs!  declare BBjGridExWidget grid!  sbc! = new SqlQueryBC(BBjAPI().getJDBCConnection("CDStore"))  rs! = sbc!.retrieve("SELECT * FROM CDINVENTORY")  grid! = new BBjGridExWidget(wnd!,100,0,0,800,600)  grid!.getOptions().setEnableRangeSelection(1)  grid!.getOptions().setSuppressRowClickSelection(1)  grid!.setData(rs!)returnbyebye:bye
Suppress Multi Range Selection
By default multiple ranges can be selected. To restrict range selection to a single range, even if the Ctrl key is held down, enable the following grid options: SuppressMultiRangeSelection=true.
grid!.getOptions().setSuppressMultiRangeSelection(1)
Range Selection Changed Event
The BBjGridExWidget::ON_GRID_RANGE_SELECTION_CHANGED is fired when a the grid's range selection is changed.
grid!.setCallback(grid!.ON_GRID_RANGE_SELECTION_CHANGED(), "handleChanged")
Range Selection API
The following methods are available on the BBjGridExWidget class for managing range selection.
| Method | Description | 
|---|---|
| getRangeSelections() | This will return back a BBjVector of GxClientRangeSelectionModelobjects | 
| addRangeSelection(GxClientAddRangeSelectionModel model!) | Add new range selection | 
| addRangeSelection(BBjString columns! , BBjNumber start! , BBjNumber end!) | Add new range selection | 
| clearRangeSelection() | Clears the selected range. | 
Example: Advanced Range Selection
The example below demonstrates a more complex range selection scenario. The example listens for the ON_GRID_RANGE_SELECTION_CHANGED and
re-create the BBjGridExWidget statusbar in BBj.
use ::BBjGridExWidget/BBjGridExWidget.bbj::BBjGridExWidgetuse ::BBjGridExWidget/GxStatusBar.bbj::GxStatusBarAggregationComponentuse ::BBjGridExWidget/GxClientModels.bbj::GxClientRangeSelectionModeluse ::BBjGridExWidget/GxClientModels.bbj::GxClientColumnModeluse ::BBjGridExWidget/GxClientModels.bbj::GxClientAddRangeSelectionModeluse com.basiscomponents.db.ResultSetuse com.basiscomponents.bc.SqlQueryBCuse java.sql.Typesuse java.util.ArrayListuse java.util.Collectionsuse java.util.Randomdeclare auto BBjTopLevelWindow wnd!wnd! = BBjAPI().openSysGui("X0").addWindow(10,10,800,600,"Range Selection Demo")wnd!.setCallback(BBjAPI.ON_CLOSE,"byebye")wnd!.setCallback(BBjAPI.ON_RESIZE,"resize")aggTemplate! = "Average : %s - Count : %s - Min : %s - Max : %s - Sum : %s"statusbar! = wnd!.addStatusBar(98,$8000$)vector! = bbjapi().makeVector()vector!.add(150)vector!.add(65535)statusbar!.setSegments(vector!)statusbar!.setTextAt(0, "Aggregation done with BBj")statusbar!.setAlignmentAt(0,statusbar!.LEFT)statusbar!.setTextAt(1, String.format(aggTemplate!,0,0,0,0,0))statusbar!.setAlignmentAt(1,statusbar!.LEFT)onRandomRange! = wnd!.addButton(99,10,10,150,25,"Add Random Range")onRandomRange!.setCallback(BBjAPI.ON_BUTTON_PUSH,"onRandomRange")clearRange! = wnd!.addButton(100,180,10,150,25,"Clear Ranges")clearRange!.setCallback(BBjAPI.ON_BUTTON_PUSH,"onClearRange")gosub mainprocess_eventsrem /**rem  * Retrieve the data from the database and configure the gridrem  */main:  declare BBjGridExWidget grid!  declare SqlQueryBC sbc!  declare ResultSet rs!  sbc! = new SqlQueryBC(BBjAPI().getJDBCConnection("CDStore"))  rs! = sbc!.retrieve("SELECT TITLE , COST , RETAIL , ONHAND FROM CDINVENTORY")  grid! = new BBjGridExWidget(wnd!,101, 0 , 50 , 800 , 530)  REM   Set to true to enable Range Selection  grid!.getOptions().setEnableRangeSelection(1)  REM   Allow users to move between cells using arrow keys instead of rows  grid!.getOptions().setNavigationBehavior(grid!.GRID_NAVIGATION_BEHAVIOUR_NEXT_CELL())  REM   Disable row selection on row click  grid!.getOptions().setSuppressRowClickSelection(1)  REM  Attach the aggregation component to the grid's built-in statusbar.  REM  The component provides aggregations on the selected range.  grid!.getStatusbar().addComponent(new GxStatusBarAggregationComponent("right"))  REM  Here we add a range selection to the grid by defining the columns which are included  REM  in the range and the start and end row's index/id  grid!.addRangeSelection("COST,RETAIL" , 2, 6)  REM listen to the grid range selection event so we can build our own statusbar in BBj  grid!.setCallback(grid!.ON_GRID_RANGE_SELECTION_CHANGED(),"onRangeSelectionChange")  grid!.setFitToGrid()  grid!.getSidebar().setHiddenByDefault(1)  grid!.setData(rs!)  REM  align columns of type number to the right to get better presentation  grid!.getColumn("COST").setAlignment(BBjGridExWidget.GRID_ALIGN_RIGHT() , 1)  grid!.getColumn("RETAIL").setAlignment(BBjGridExWidget.GRID_ALIGN_RIGHT() , 1)  grid!.getColumn("ONHAND").setAlignment(BBjGridExWidget.GRID_ALIGN_RIGHT() , 1)returnonRangeSelectionChange:  declare auto GxClientRangeSelectionModel currentRange!  declare auto GxClientColumnModel column!  REM vector of ranges  ranges! = grid!.getRangeSelections()  IF (ranges!.size() = 0) THEN      statusbar!.setTextAt(1, String.format(aggTemplate!,0,0,0,0,0))      return  FI  rangesLength! = ranges!.size() - 1  sum!          = 0  count!        = 0  min!          = 0  max!          = 0  average!      = 0  values!       = new ArrayList()  rem we start by looping over all ranges  FOR rangeIndex! = 0 TO rangesLength!      currentRange!   = ranges!.get(rangeIndex!)      rows!           = currentRange!.getRows()      rowsLength!     = rows!.size() - 1      columns!        = currentRange!.getColumns()      columnsLength!  = columns!.size() - 1      count!          = count! + (columns!.size() * rows!.size())      FOR rowIndex! = 0 TO rowsLength!          FOR columnsIndex! = 0 TO columnsLength!              column! = columns!.get(columnsIndex!)              type!   = column!.getType()              SWITCH (type!)                  CASE Types.BIGINT                  CASE Types.BIT                  CASE Types.DECIMAL                  CASE Types.DOUBLE                  CASE Types.FLOAT                  CASE Types.INTEGER                  CASE Types.NUMERIC                  CASE Types.NUMERIC                  CASE Types.TINYINT                      row!   = rows!.get(rowIndex!).asDataRow()                      value! = num(row!.getField(column!.getName()).getValue())                      sum!   = sum! + value!                      values!.add(value!)                      BREAK                  CASE DEFAULT                      BREAK              SWEND          NEXT columnsIndex!      NEXT rowIndex!  NEXT rangeIndex!  IF (values!.size() > 0) THEN      min!      = Collections.min(values!)      max!      = Collections.max(values!)      average!  = sum! / values!.size()  FI  statusbar!.setTextAt(1, String.format(aggTemplate!, round(average!), count!, round(min!), round(max!), round(sum!)))returnrem /**rem  * Add a random add range modelrem  */onRandomRange:    declare GxClientAddRangeSelectionModel addModel!    REM  list of columns which can be included in the range    columns! = new ArrayList()    columns!.add("COST")    columns!.add("RETAIL")    columns!.add("ONHAND")    REM number of columns include with the random generated range    numberOfColumns! = rnd(3)    rand! = new Random()    rangeColumns! = new ArrayList()    FOR index = 0 TO numberOfColumns!     randomIndex! = rand!.nextInt(columns!.size())     rangeColumns!.add(columns!.get(randomIndex!))     columns!.remove(randomIndex!)    NEXT index    addModel! =  new GxClientAddRangeSelectionModel()    addModel!.setColumns(rangeColumns!)    addModel!.setStart(str(rnd(10)))    addModel!.setEnd(str(rnd(10)))    grid!.clearRangeSelection()    grid!.addRangeSelection(addModel!)returnrem /**rem  * We clear all range selectionsrem  */onClearRange:    grid!.clearRangeSelection()returnresize:  ev! = BBjAPI().getLastEvent()  w=ev!.getWidth()  h=ev!.getHeight()  grid!.setSize(w,h - 50)returnbyebye:bye