JavaFX TableView, aktive CheckBoxen limitieren

Veröffentlicht von

Hier ein Beispiel-Code, wo man ein Limit an selected CheckBoxen, in einem TableView festlegen kann.

Funktion
  • wenn das Limit an aktiven Checkboxen erreicht wurde, wird ein Alert angezeigt und alle andern Checkboxen im TableView werden auf disable gesetzt
  • wenn in der ObservableList des TableView, mehr Items auf „true“ gesetzt sind, als das Limit zulässt, werden die letzten Einträge in der ObservableList auf „false“ gesetzt
Code

DemoMaxChecked.java

import java.util.HashMap;
import java.util.function.Consumer;

import javafx.application.Application;
import javafx.beans.property.SimpleLongProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.CheckBox;
import javafx.scene.control.DialogPane;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
 
public class DemoMaxChecked extends Application {

	// Config
	private int maxChecked = 4;
	
	private TableView<DemoUserModel> table;
	private SimpleLongProperty activeUserProperty = new SimpleLongProperty();

	private HashMap<String, Boolean> dontShowAgain = new HashMap<String, Boolean>();
	
	@Override
	public void start(Stage mainStage) {
		mainStage.setTitle("JavaFX-Table");
 
		ObservableList<DemoUserModel> data =FXCollections.observableArrayList(
 	         new DemoUserModel("1", "Inge", true ),
 	         new DemoUserModel("2", "Jens", false ),
 	         new DemoUserModel("3", "Klaus", true ),
 	         new DemoUserModel("4", "Sven", true ),
 	         new DemoUserModel("5", "Patrick", true ),
 	         new DemoUserModel("6", "Ben", true ),
 	         new DemoUserModel("7", "Eddy", true ),
 	         new DemoUserModel("8", "Maik", true ),
 	         new DemoUserModel("9", "Rudi", false ),
 	         new DemoUserModel("10", "Daniel", true ),
 	         new DemoUserModel("11", "Rainer", false ),
 	         new DemoUserModel("12", "Rene", true ),
 	         new DemoUserModel("13", "Thorsten", true ));
          
		this.table = new TableView<>();
		table.setEditable(true);  
 
		TableColumn<DemoUserModel, String> col1 = new TableColumn<>("ID");
		col1.setCellValueFactory(new PropertyValueFactory<DemoUserModel, String>("id"));

		TableColumn<DemoUserModel, String> col2 = new TableColumn<>("User");
		col2.setCellValueFactory(new PropertyValueFactory<DemoUserModel, String>("userName"));
 
		TableColumn<DemoUserModel, Boolean> col3 = new TableColumn<>("Activate");
		col3.setCellValueFactory(new PropertyValueFactory<>("userActivate"));
		col3.setCellFactory(column -> new TableCellCheckboxAktiviert<>(this));

		table.getColumns().addAll(col1, col2, col3);
		table.setItems(data);

		// Shows a Alert when user maximum is reached
		activeUserProperty.addListener((ov, oldVal, newVal) -> {	
			boolean isAlertAgain = dontShowAgain.size() == 0 
					? true : dontShowAgain.get("KEY_AUTO_EXIT");
			if (newVal == Long.valueOf(maxChecked) && isAlertAgain) {
				showAlert();
			}			
		});

		Button buttonAddUser = new Button("Add User");
		buttonAddUser.setOnAction(e -> addUser());
      
		Button buttonDelUser = new Button("Delete User");
		buttonDelUser.setOnAction(e -> delUser());
 
		HBox hBoxButtons = new HBox(buttonAddUser, buttonDelUser);
		hBoxButtons.setSpacing(10);
		hBoxButtons.setAlignment(Pos.CENTER);
		
		Label labelActiveUser = new Label();
		labelActiveUser.textProperty().bind(activeUserProperty.asString());
		Label labelActiveUserMax = new Label("/" + maxChecked + " User");
		
		HBox hBoxActiveUser = new HBox(labelActiveUser, labelActiveUserMax);
		hBoxActiveUser.setSpacing(0);
		hBoxActiveUser.setPadding(new Insets(0, 5, -8, 0)); // (top/right/bottom/left)
		hBoxActiveUser.setAlignment(Pos.BOTTOM_RIGHT);
      
		VBox root = new VBox(hBoxButtons, hBoxActiveUser, table);
		root.setSpacing(10);
      
		Scene scene = new Scene(root, 500, 500);
		mainStage.setScene(scene);
		mainStage.show();
	}
 
	private void addUser() {
		String userID = table.getItems().size() + 1 + "";
		table.getItems().add(new DemoUserModel(userID, "Max", false ));
	}

	private void delUser() {
		DemoUserModel item = table.getSelectionModel().getSelectedItem();
		if (item != null) {
			table.getItems().remove(item);
		}		
	}
	
	public void showAlert() {
		Alert alert = createAlertWithOptOut(AlertType.CONFIRMATION, "Exit", null, 
                   "You can only select a maximum of " + maxChecked + "!", "Do not show again", 
                   param -> dontShowAgain.put("KEY_AUTO_EXIT", param ? false : true), ButtonType.OK);
	     if (alert.showAndWait().filter(t -> t == ButtonType.OK).isPresent()) {
	    	 alert.close();
	     }
	}
        
	private Alert createAlertWithOptOut(AlertType type, String title, String headerText, 
            String message, String optOutMessage, Consumer<Boolean> optOutAction, 
            ButtonType... buttonTypes) {
    	Alert alert = new Alert(type);
    	Node graphic = alert.getDialogPane().getGraphic();
    	alert.getDialogPane().applyCss();
    	alert.setDialogPane(new DialogPane() {
    		@Override
    		protected Node createDetailsButton() {
    			CheckBox optOut = new CheckBox();
    			optOut.setText(optOutMessage);
    			optOut.setOnAction(e -> optOutAction.accept(optOut.isSelected()));
    			return optOut;
    		}
    	});
    	alert.getDialogPane().getButtonTypes().addAll(buttonTypes);
    	alert.getDialogPane().setContentText(message);
    	alert.getDialogPane().setExpandableContent(new Group());
    	alert.getDialogPane().setExpanded(true);
    	alert.getDialogPane().setGraphic(graphic);
    	alert.setTitle(title);
    	alert.setHeaderText(headerText);
    	return alert;
    }
	
    // Getter
    public int getMaxChecked() {return maxChecked;}
    public SimpleLongProperty activeUserProperty() {return activeUserProperty;}
    public HashMap<String, Boolean> getDontShowAgain() {return dontShowAgain;}
    
    public static void main(String[] args) {
	    launch(args);
    }
}Code-Sprache: JavaScript (javascript)

TableCellCheckboxAktiviert.java

import javafx.application.Platform;
import javafx.beans.property.SimpleLongProperty;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.control.CheckBox;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableRow;
import javafx.scene.layout.HBox;

public class TableCellCheckboxAktiviert<T> extends TableCell<DemoUserModel, Boolean> {

    private int maxChecked;
	private SimpleLongProperty activeUserProperty;

	private DemoMaxChecked demoMaxChecked;
	
	public TableCellCheckboxAktiviert(DemoMaxChecked demoMaxChecked) {   		
    	this.demoMaxChecked = demoMaxChecked;
    	this.maxChecked = demoMaxChecked.getMaxChecked();
    	this.activeUserProperty = demoMaxChecked.activeUserProperty();
    }
    
    @Override
    protected void updateItem(Boolean item, boolean empty) {
        super.updateItem(item, empty);
        Platform.runLater(() -> {  
	        TableRow<DemoUserModel> row = (TableRow<DemoUserModel>) getTableRow();
	        
	        if (row == null || row.getItem() == null) {
	        	setText(null);
	        	setGraphic(null);
			} else {
				System.out.println("updateItem -> ID[" 
						+ row.getItem().getID() + "], User[" + row.getItem().getUserName() + "]");			
				DemoUserModel rowItem = row.getItem();			
	
	            CheckBox checkBox = rowItem.getCheckBox();
	            
	            HBox hBox = new HBox();
	            hBox.setAlignment(Pos.CENTER);
	        	hBox.getChildren().add(checkBox);
	        	
	        	setText(null);
	        	setGraphic(hBox);	
	        	
	        	// Select Row if CheckBox clicked
	        	getTableView().requestFocus();
	        	getTableView().getSelectionModel().select(row.getItem());     	
	        	getTableView().getFocusModel().focus(
	        			getTableView().getSelectionModel().getSelectedIndex());
	        	
	        	// limit Activate users to a maximum
	       		ObservableList<DemoUserModel> items = getTableView().getItems();           		
	    		long countAktiveBenutzer = items.stream().filter(b -> b.isUserActivate()).count();
	    		
	    		if (countAktiveBenutzer == maxChecked) {
	    			items.stream().filter(b -> !b.isUserActivate())
	    				.forEach(e -> e.getCheckBox().setDisable(true));	
				} else {
					items.stream().filter(b -> !b.isUserActivate())
						.forEach(e -> e.getCheckBox().setDisable(false));
				}
	    		
	    		// remove selection if more than maximum
	    		while (countAktiveBenutzer > maxChecked) {  		
	    			// get last selected checkBox
	    			DemoUserModel lastSelected = items.stream().filter(b -> b.isUserActivate())
	    					.reduce((first, second) -> second).orElse(null); 
	   			
	    			// remove selection from last selected checkBox
	    			lastSelected.getCheckBox().setSelected(false); 
	    			
	    			System.out.println("remove selection by -> ID[" 
	    					+ lastSelected.getID() + "], User[" + lastSelected.getUserName() + "]");
	    			
	    			countAktiveBenutzer = items.stream().filter(b -> b.isUserActivate()).count();
				}
	    		
	    		// Update labelActiveUser    		 			  		
		    	activeUserProperty.set(getTableView().getItems().stream()
		    		.filter(b -> b.isUserActivate()).count());
			} 
        });
    }
}Code-Sprache: JavaScript (javascript)

DemoUserModel

import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.control.CheckBox;

public class DemoUserModel {

    private SimpleStringProperty id;
    private SimpleStringProperty userName;
    private SimpleBooleanProperty userActivate; 
	
    private CheckBox checkBox;


    public DemoUserModel(String id, String userName, boolean userActivate) {

	this.id = new SimpleStringProperty(id);
	this.userName = new SimpleStringProperty(userName);
	this.userActivate = new SimpleBooleanProperty(userActivate);

	this.checkBox = new CheckBox();		
	checkBox.setSelected(userActivate);		
	checkBox.selectedProperty().addListener((ov, olaVal, newVal) -> setUserActivate(newVal));
    }

    // Properteis
    public ReadOnlyStringProperty idProperty() {return id;}
    public ReadOnlyStringProperty userNameProperty() {return userName;}
    public ReadOnlyBooleanProperty userActivateProperty() {return userActivate;}

    // Getter
    public String getID(){ return id.get();}
    public String getUserName(){ return userName.get();}
    public boolean isUserActivate(){ return userActivate.get();}
	
    public CheckBox getCheckBox() {return checkBox;}

    // Setter
    public void setID(String id){ this.id.set(id);}
    public void setUserName(String userName){this.userName.set(userName);}
    public void setUserActivate(boolean userActivate){ this.userActivate.set(userActivate);}	
}Code-Sprache: JavaScript (javascript)