JavaFX - Detect & highlight TableColumn being dragged onto

前端 未结 1 1112
伪装坚强ぢ
伪装坚强ぢ 2021-01-15 19:12

What\'s the best way to discover which TableColumn (in a TableView) that a DragEvent occurred?

I\'d like to be able to highlight (ex. change the background color t

相关标签:
1条回答
  • 2021-01-15 20:12

    To do this, you need to register drag listeners with each cell that cause the column to update its style when the cells are dragged over. I would do this using an ObjectProperty to represent the current "drop target column" (i.e. column over which dragging is occurring), and both observe it and update it from the cells. To access the cells, you need a cell factory.

    The following method will add such support to a column. It also respects any functionality defined in a previously-attached cell factory:

    private <S,T> void configureDropTargetColumn(TableColumn<S,T> column, ObjectProperty<TableColumn<?,?>> dropTarget) {
    
        Callback<TableColumn<S,T>, TableCell<S,T>> currentCellFactory = column.getCellFactory() ;
    
        column.setCellFactory(tc -> {
            TableCell<S,T> cell = currentCellFactory.call(tc);
            dropTarget.addListener((obs, oldColumn, newColumn) -> 
                    cell.pseudoClassStateChanged(PseudoClass.getPseudoClass("drop-target"), newColumn==column));
            cell.setOnDragEntered(e -> dropTarget.set(column));
            cell.setOnDragExited(e -> dropTarget.set(null));
            return cell ;
        });
    }
    

    Here's a SSCCE using the usual "contact table" example:

    import java.util.Arrays;
    import java.util.List;
    import java.util.function.Function;
    
    import javafx.application.Application;
    import javafx.beans.property.ObjectProperty;
    import javafx.beans.property.SimpleObjectProperty;
    import javafx.beans.property.SimpleStringProperty;
    import javafx.beans.property.StringProperty;
    import javafx.beans.value.ObservableValue;
    import javafx.css.PseudoClass;
    import javafx.geometry.Pos;
    import javafx.scene.Scene;
    import javafx.scene.control.Label;
    import javafx.scene.control.TableCell;
    import javafx.scene.control.TableColumn;
    import javafx.scene.control.TableView;
    import javafx.scene.input.ClipboardContent;
    import javafx.scene.input.Dragboard;
    import javafx.scene.input.TransferMode;
    import javafx.scene.layout.BorderPane;
    import javafx.stage.Stage;
    import javafx.util.Callback;
    
    public class TableColumnDropTargetExample extends Application {
    
        @Override
        public void start(Stage primaryStage) {
            TableView<Person> table = new TableView<>();
            table.getColumns().add(column("First Name", Person::firstNameProperty));
            table.getColumns().add(column("Last Name", Person::lastNameProperty));
            table.getColumns().add(column("Email", Person::emailProperty));
    
            ObjectProperty<TableColumn<?,?>> dropTargetColumn = new SimpleObjectProperty<>();
    
            table.getColumns().forEach(col -> configureDropTargetColumn(col, dropTargetColumn));
    
            table.getItems().addAll(createData());
    
            Label label = new Label("Drag me");
            label.getStyleClass().add("drag-source");
    
            label.setOnDragDetected(e -> {
                Dragboard db = label.startDragAndDrop(TransferMode.COPY_OR_MOVE);
                ClipboardContent cc = new ClipboardContent();
                cc.putString(label.getText());
                db.setContent(cc);
            });
            label.setOnDragDone(e -> dropTargetColumn.set(null));
    
            BorderPane root = new BorderPane(table);
            root.setTop(label);
            BorderPane.setAlignment(label, Pos.CENTER);
    
            Scene scene = new Scene(root, 800, 600);
            scene.getStylesheets().add("style.css");
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        private <S,T> void configureDropTargetColumn(TableColumn<S,T> column, ObjectProperty<TableColumn<?,?>> dropTarget) {
    
            Callback<TableColumn<S,T>, TableCell<S,T>> currentCellFactory = column.getCellFactory() ;
    
            column.setCellFactory(tc -> {
                TableCell<S,T> cell = currentCellFactory.call(tc);
                dropTarget.addListener((obs, oldColumn, newColumn) -> 
                        cell.pseudoClassStateChanged(PseudoClass.getPseudoClass("drop-target"), newColumn==column));
                cell.setOnDragEntered(e -> dropTarget.set(column));
                cell.setOnDragExited(e -> dropTarget.set(null));
                return cell ;
            });
        }
    
        private static <S,T> TableColumn<S,T> column(String text, Function<S, ObservableValue<T>> property) {
            TableColumn<S,T> col = new TableColumn<>(text);
            col.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
            return col ;
        }
    
        private List<Person> createData() {
            return Arrays.asList(
                    new Person("Jacob", "Smith", "jacob.smith@example.com"),
                    new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
                    new Person("Ethan", "Williams", "ethan.williams@example.com"),
                    new Person("Emma", "Jones", "emma.jones@example.com"),
                    new Person("Michael", "Brown", "michael.brown@example.com")     
            );
        }
    
        public static class Person {
            private final StringProperty firstName = new SimpleStringProperty();
            private final StringProperty lastName = new SimpleStringProperty();
            private final StringProperty email = new SimpleStringProperty();
    
    
            public Person(String firstName, String lastName, String email) {
                setFirstName(firstName);
                setLastName(lastName);
                setEmail(email);
            }
    
    
            public final StringProperty firstNameProperty() {
                return this.firstName;
            }
    
    
    
            public final String getFirstName() {
                return this.firstNameProperty().get();
            }
    
    
    
            public final void setFirstName(final String firstName) {
                this.firstNameProperty().set(firstName);
            }
    
    
    
            public final StringProperty lastNameProperty() {
                return this.lastName;
            }
    
    
    
            public final String getLastName() {
                return this.lastNameProperty().get();
            }
    
    
    
            public final void setLastName(final String lastName) {
                this.lastNameProperty().set(lastName);
            }
    
    
    
            public final StringProperty emailProperty() {
                return this.email;
            }
    
    
    
            public final String getEmail() {
                return this.emailProperty().get();
            }
    
    
    
            public final void setEmail(final String email) {
                this.emailProperty().set(email);
            }
    
    
    
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    and the stylesheet:

    .table-cell:drop-target {
        -fx-background-color: -fx-background ;
        -fx-background: yellow ;
        -fx-border-color: -fx-table-cell-border-color -fx-table-cell-border-color transparent transparent ;
    }
    .drag-source {
        -fx-font-size: 18 ;
        -fx-padding: 10 ;
    }
    
    0 讨论(0)
提交回复
热议问题