Problems related to TableView of JavaFX

preface

Recently, I started to write a student management system, involving the use of TableView. I also have some experience and ideas. I want to record and share them (in fact, I'm trying to use html web pages instead of the interface), which is more for learning.

Let's first look at what's in TableView

In the IDEA, press and hold Ctrl, and then click the TableView keyword. The keyword will automatically follow up to its definition. We can see what's in it first.

You will see its two constructors first:

// First constructor
public TableView() {
    this(FXCollections.<S>observableArrayList());
}

// Second constructor
public TableView(ObservableList<S> items) {
    getStyleClass().setAll(DEFAULT_STYLE_CLASS);
    setAccessibleRole(AccessibleRole.TABLE_VIEW);

    // we quite happily accept items to be null here
    setItems(items);

    // install default selection and focus models
    // it's unlikely this will be changed by many users.
    setSelectionModel(new TableViewArrayListSelectionModel<S>(this));
    setFocusModel(new TableViewFocusModel<S>(this));

    // we watch the columns list, such that when it changes we can update
    // the leaf columns and visible leaf columns lists (which are read-only).
    getColumns().addListener(weakColumnsObserver);

    // watch for changes to the sort order list - and when it changes run
    // the sort method.
    getSortOrder().addListener((ListChangeListener<TableColumn<S, ?>>) c -> {
        doSort(TableUtil.SortEventType.SORT_ORDER_CHANGE, c);
    });

    // We're watching for changes to the content width such
    // that the resize policy can be run if necessary. This comes from
    // TreeViewSkin.
    getProperties().addListener(new MapChangeListener<Object, Object>() {
        @Override
        public void onChanged(Change<? extends Object, ? extends Object> c) {
            if (c.wasAdded() && SET_CONTENT_WIDTH.equals(c.getKey())) {
                if (c.getValueAdded() instanceof Number) {
                    setContentWidth((Double) c.getValueAdded());
                }
                getProperties().remove(SET_CONTENT_WIDTH);
            }
        }
    });

    isInited = true;
}

You can have a general look, but the most important thing is to be clear: TableView maintains a type fxcollections< S > collection of observablearraylist. Where < s > represents the user-defined type.

You can also see how to add listeners to a Table:

getProperties().addListener(new MapChangeListener<Object, Object>() {
    @Override
    public void onChanged(Change<? extends Object, ? extends Object> c) {
        if (c.wasAdded() && SET_CONTENT_WIDTH.equals(c.getKey())) {
            if (c.getValueAdded() instanceof Number) {
                setContentWidth((Double) c.getValueAdded());
            }
            getProperties().remove(SET_CONTENT_WIDTH);
        }
    }
});

In short, you will see many very interesting things. I won't elaborate here. You can read them yourself if you are interested. It is very helpful to understand the TableView control. You can better understand its operation principle and mechanism.

Practical application

Let's take a look at the actual application. The official has given a very detailed document. Fortunately, we have found a website that translates it into a better version of Chinese. We can link it directly. There are some simple applications:

Simple application: http://www.javafxchina.net/blog/2015/04/doc03_tableview/
Official documents: http://docs.oracle.com/javafx/2/ui_controls/table-view.htm

Two data forms of TableView columns:

One is to maintain the tablecolumn < Person, String > type of the class. Each data of the column is a class (here is a Person class), and the String type corresponds to the column name. The mapping needs to be set as follows:

col.setCellValueFactory(
new PropertyValueFactory<Person, String>("firstName"));    // Column name corresponding to firstName

The other is to maintain the tablecolumn < Map, string > type of Map. Each data in the column is a Map. This is required when setting up the mapping:

col.setCellValueFactory(new MapValueFactory(colName));        // colName corresponds to the character type column name```

Table editable:

You can add a TextFieldTableCell as in the official document, and then add the response function:

// Set CellFactory and fill in a TextField column
col.setCellFactory(TextFieldTableCell.<Map>forTableColumn());
// Set function for editing response
col.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<Map, String>>() {
    @Override public void handle(TableColumn.CellEditEvent<Map, String> t) {
    System.out.println("Change detected"); 
    // Here, modify and maintain the corresponding settings into the ObservableList collection of TableView
    }
});

Adding or deleting rows is the same operation. You can directly modify the collection maintained by TableView.

Add column, delete column

This requires not only deleting the data in the set, but also deleting the corresponding data from the Columns set in the table. Maybe you will add some judgment in the deletion and addition to ensure the correctness of the operation:

table.getColumns().add(tempCol);        // The newly added columns are displayed in the list
table.getColumns().remove(index);          // Delete column at index position

Monitor column changes

You can choose to use getproperties () as in the source file AddListener to complete listening. You can also add a ListChangeListener:

// Set the listener for table to listen for changes in the column
table.getColumns().addListener(new ListChangeListener() {
    @Override
    public void onChanged(Change c) {
        c.next();                   // Accept the change, otherwise an error will be reported

        // Handle events after column drag
        if (c.wasRemoved()) {
            // Define a collection that holds the current column sorting
            List<TableColumn<ObservableList<Map>, String>> newList =
                    new ArrayList<>(table.getColumns());
            // Define a collection that holds the original column sort
            List<TableColumn<ObservableList<Map>, String>> oldList =
                    new ArrayList<>(c.getList());
            // Related operations
        }   // end if: the drag event has been processed
    }
});
TableView TableColumn column
Building a table mainly includes TableView,TableColumn,ObservableList and Bean
Add column
table.getColumns().addAll(firstNameCol, lastNameCol, emailCol); 
ObservableList stores data
Add data
table.setItems(ObservableList)
observableList usually contains stored beans
The column is associated with the Bean to obtain the value.
Establish the relationship between the column and the Bean, and establish the relationship with the Bean through the cell value factory.
RoomIdCol.setCellValueFactory(new PropertyValueFactory<Person, String>("RoomIdCol"))
It doesn't need to know what Bean you passed here. It only needs to reflect "RoomIdCol" into a getRoomIdCol() method to get the value in the Bean. Therefore, the name of the Bean attribute definition does not need to be the same as it, but only needs to have a getRoomIdCol() method.
firstNameCol.setCellValueFactory
    (new Callback<TableColumn.CellDataFeatures<Person, String>, 
     ObservableValue<String>>() {  
         @Override  
         public ObservableValue<String> call(CellDataFeatures<Person, String> arg0) {          
             // return new  
             // 	SimpleStringProperty(arg0.getValue(),"sd",arg0.getValue().getFirstName());  
             // //bean, bean name, value  
             return new SimpleStringProperty(arg0.getValue().getFirstName());   
             // In this way, you can not establish the mapping relationship between value and object.  
         }  
});
arg0.getValue() is equal to the person here. If you observablelist Add (list), then arg0 GetValue () equals list.
SimpleStringProperty(arg0.getValue(),"sd",arg0.getValue().getFirstName()); 
This means arg0 GetValue () is your observablelist Add, "sd" gets the name of the bean, arg0 getValue(). Getfirstname () is the value you want to get for this column. If it is a list, arg0 getValue(). Get (J) assigns a value to each row of the column.
The cell can store not only text, but also other nodes:
firstNameCol.setCellFactory(new Callback<TableColumn<Person, String>, TableCell<Person, String>>() {  
    @Override  
    public TableCell<Person, String> call( // Cell content  
    TableColumn<Person, String> arg0) {  
       return new TableCell<Person, String>() {                @Override  
         protected void updateItem(final String str,boolean arg1) {        
              super.updateItem(str, arg1);  
         if (arg1) {                            setText(null);  
        setGraphic(null);  
          else {                                 setText(str);  
                  setGraphic(new CheckBox());  
        }  
          }  
       }  
}); 
Like TreeCell, you can reconstruct the cell.
lastNameCol.setCellFactory(TextFieldTableCell.forTableColumn());
There are some default constructs, so you don't need to go to new TableCell yourself
//TableColumn three methods for setting sort 
firstNameCol.setSortNode(new Text("a")); // The default is the small icon triangle on the header, which can be changed 
firstNameCol.setSortable(true); // Set sortable 
firstNameCol.setSortType(SortType.DESCENDING);//Set lifting sequence 
To include multiple columns in a column, you can call getcolumns () of tablecolumn setAll(TableColumn…);
        firstNameColumn = new TableColumn<Person, String>("First");  
        firstNameColumn.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));  
//        firstNameColumn.setCellFactory(TextFieldCellFactory.<Person>forTableColumn());  
  
        lastNameColumn = new TableColumn<Person, String>("Last");  
        lastNameColumn.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));  
//        lastNameColumn.setCellFactory(TextFieldCellFactory.<Person>forTableColumn());  
  
        nameColumn = new TableColumn<Person, String>("Name");  
        nameColumn.getColumns().setAll(firstNameColumn, lastNameColumn); 
There are obvious horizontal lines between the cells of table, which can be removed through css.
Remove horizontal lines
.table-view .table-row-cell {  
    -fx-background-insets: 0;  
} 
If you want to remove the vertical line without data at the same time
.table-row-cell:empty .table-cell {  
    -fx-border-width: 0px;  
}  
If you want to operate on rows, you can use setRowFactory. Double click the row as follows
tableView.setRowFactory(new Callback<TableView<T>, TableRow<T>>() {  
            @Override  
            public TableRow<T> call(TableView<T> param) {  
                return new TableRowControl();  
            }  
        });  
class TableRowControl extends TableRow<T> {  
  
        public TableRowControl() {  
            super();  
            this.setOnMouseClicked(new EventHandler<MouseEvent>() {  
                @Override  
                public void handle(MouseEvent event) {  
                    if (event.getButton().equals(MouseButton.PRIMARY)  
                            && event.getClickCount() == 2  
                            && TableRowControl.this.getIndex() < tableView.getItems().size()) {  
                          //doSomething  
                    }  
                }  
            });  
        }  
    }  
Insert data into the table. The data in the table is displayed according to your itemlist. The order of the data in the list is the same as that of the table. If you add a new piece of data, add it directly to the list. The list provides adding by location, so the table display is adding by location.
tableView.getItems().add(selectedRow, newRecord);  
newRecord is a new object with no assignment.
Custom tablecells generally override the updateItem method. If you need to edit, you can override startEdit and cancelEdit
@Override  
      public void startEdit() {      
          if (!this.getTableRow().isVisible()) {  
              return;  
          }  
          super.startEdit();  
  
          if (checkBox == null) {  
              createCheckBox();  
          }  
          setText(null);  
          setGraphic(checkBox);  
      }  
  
      @Override  
      public void cancelEdit() {  
          super.cancelEdit();  
          setText(getItem().toString());  
          setGraphic(null);  
      }  
You can see that once you click the edit status, the contents in the cell will be changed. As soon as you leave the editor, change to the content in the original cell. In this way, the string can be displayed, and a control, such as calendar, can be made during editing.
Gets the selected TableColumn
table.getSelectionModel().getSelectedCells().get(0).getTableColumn() 
table's own method can filter columns, that is, only which columns are displayed
table.setTableMenuButtonVisible(true);  
When set to true, a plus sign column will appear, which can filter the column
By default, only one row can be selected in table. If you want to select multiple rows, set SelectionMode. At this time, you can listen to the selected multiple rows.
ListChangeListener<Person> indicesListener = new   ListChangeListener<Person>() {  
           @Override public void onChanged(Change<? extends Person> c) {  
               while (c.next()) {  
                  
                   selectionUpdated(c.getAddedSubList(), c.getRemoved());  
               }  
           }  
       };  
       tableView.getSelectionModel().getSelectedItems().addListener(indicesListener);  
       tableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);  
tableView.getSelectionModel() gets an abstract class SelectionModel, which has two subclasses: multipleselectionmodel and singleselectionmodel. They mainly handle selection events. You can see their methods:
getSelectedIndex()   
getSelectedItem()   
selectedIndexProperty()   
selectedItemProperty()
Gets the selected item and index. One is to get its value, and the other is to get the encapsulated attribute for bind change.
select(int index)   
select(T obj)   
selectFirst()   
selectLast()   
...  
clearSelection()   
clearSelection(int index) 
These methods are selected by operation.
setSelectionMode(SelectionMode.MULTIPLE);  
selectIndices(int index, int... indices)   
selectRange(int start, int end)   
MultipleSelectionModel provides multiple selection function and some methods of multiple selection.
select(int row, TableColumn<S,?> column)   
selectAboveCell()   
selectBelowCell()  
selectLeftCell()   
selectRightCell()    
setCellSelectionEnabled(boolean value)  
TableView.TableViewSelectionModel inherits MultipleSelectionModel and mainly provides some methods for the selected events of table.

Keywords: Java

Added by XeroXer on Sat, 15 Jan 2022 01:56:18 +0200