Search code examples
javajavafxtableviewfxmltablecolumn

Hide TableColumns of TableView through CheckBox on separate Window


I have a window written in fxml with a TableView and a few TableColumns and other stuff. I am trying to create a function in the controller to this window, that enables the user to select which columns to display via a set of checkboxes on a separate window. This Window would be a child window of the HealthCheckTab. It would have a button that once pressed would get the state of all Checkboxes and would invoke a function in HealthcheckTab that updates the Tableview making the unwanted columns not visible.

This is the window with the TableView (Extract)

                        </TitledPane>
                        <TitledPane fx:id="classificationNumbers" animated="false"
                            text="HealthCheck Classification Numbers">
                            <content>
                                <ScrollPane fitToHeight="true" fitToWidth="true"
                                    hbarPolicy="ALWAYS" maxHeight="1.7976931348623157E308"
                                    maxWidth="1.7976931348623157E308" pannable="true">
                                    <content>
                                        <TableView fx:id="HcTable" editable="true"
                                            maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
                                            minWidth="-Infinity" tableMenuButtonVisible="true">
                                            <columns>
                                                <TableColumn fx:id="colId" editable="false"
                                                    maxWidth="-Infinity" minWidth="40.0" prefWidth="-1.0" text="ID" />
                                                <TableColumn fx:id="colName" editable="false"
                                                    maxWidth="1.7976931348623157E308" minWidth="60.0"
                                                    prefWidth="-1.0" text="Name" />
                                                <TableColumn fx:id="colVal" maxWidth="1.7976931348623157E308"
                                                    minWidth="55.0" prefWidth="-1.0" text="Value" />
                                                <TableColumn fx:id="colDescrCn" editable="false"
                                                    maxWidth="1.7976931348623157E308" minWidth="90.0"
                                                    prefWidth="-1.0" text="Comment (CN)" />
                                                <TableColumn fx:id="colDatatype" editable="false"
                                                    maxWidth="1.7976931348623157E308" minWidth="80.0"
                                                    prefWidth="-1.0" text="Datatype" />
                                                <TableColumn fx:id="colTool" maxWidth="1.7976931348623157E308"
                                                    minWidth="50.0" prefWidth="-1.0" text="Tool" visible="false" />
                                                <TableColumn fx:id="colPrio" editable="false"
                                                    maxWidth="1.7976931348623157E308" minWidth="60.0"
                                                    prefWidth="-1.0" text="Priority" />
                                                <TableColumn fx:id="colScope" maxWidth="1.7976931348623157E308"
                                                    minWidth="50.0" prefWidth="-1.0" text="Scope" visible="false" />
                                                <TableColumn fx:id="colAvg" editable="false"
                                                    maxWidth="1.7976931348623157E308" minWidth="50.0"
                                                    prefWidth="-1.0" text="AVG" visible="false" />
                                                <TableColumn fx:id="colMin" maxWidth="1.7976931348623157E308"
                                                    minWidth="50.0" prefWidth="-1.0" text="MIN" visible="false" />
                                                <TableColumn fx:id="colRelComp" prefWidth="122.0"
                                                    text="Relative Comparable" />
                                            </columns>
                                        </TableView>
                                    </content>
                                </ScrollPane>
                            </content>
                        </TitledPane>
                    

This is the controller (Extract)

    @FXML
    private TreeView<String> HCTree;
    @FXML
    private TableView<Map> HcTable;

    @FXML
    private TableColumn<Map, String> colId;
    @FXML
    private TableColumn<Map, String> colName;
    @FXML
    private TableColumn<Map, String> colVal;
    @FXML
    private TableColumn<Map, String> colDescrCn;
    @FXML
    private TableColumn<Map, String> colDatatype;
    @FXML
    private TableColumn<Map, String> colTool;
    @FXML
    private TableColumn<Map, String> colPrio;
    @FXML
    private TableColumn<Map, String> colScope;
    @FXML
    private TableColumn<Map, String> colAvg;
    @FXML
    private TableColumn<Map, String> colMin;
    @FXML
    private TableColumn<Map, String> colRelComp;



    // -----------------------------------------------------------------------------------------------
    // REFRESH TABLE
    // -----------------------------------------------------------------------------------------------

    public void refreshTable() {
        System.out.println("apply");
        colScope.setVisible(true);
        //colId.setVisible(false);
    

    }

Separate window (Extract)

@FXML
    private void handleApplyViewOptions() {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("HealthCheckTab.fxml"));
            Stage stage = new Stage(StageStyle.DECORATED);
            stage.setScene(new Scene(loader.load()));
            HealthCheckTabController controller = loader.<HealthCheckTabController> getController();
            controller.refreshTable();
        } catch (IOException e) {
            java.lang.System.err.println(e.getStackTrace());
        }
        Stage stage = (Stage) btnApply.getScene().getWindow();
        stage.close();
    }

The refreshTable function does not hide the Scope Column at all. I don't know why...


Solution

  • You are loading a new copy of the UI defined in HealthCheckTab.fxml and calling refreshTable on the controller for that UI (which is never displayed).

    Probably an easier approach for this is to register an onHidden handler with the dialog you create, and call refreshTable when the dialog is hidden.

    Here is a SSCCE:

    Main.fxml:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.scene.layout.BorderPane?>
    <?import javafx.scene.control.TableView?>
    <?import javafx.scene.control.TableColumn?>
    <?import javafx.scene.layout.HBox?>
    <?import javafx.scene.control.Button?>
    <?import javafx.geometry.Insets?>
    
    <BorderPane fx:controller="MainController" xmlns:fx="http://javafx.com/fxml/1">
        <center>
            <TableView >
                <columns>
                    <TableColumn fx:id="nameColumn" text="Name" />
                    <TableColumn fx:id="optionalColumn" text="Data" />
                </columns>
            </TableView>
        </center>
        <bottom>
            <HBox alignment="CENTER">
                <Button text="Configure View" onAction="#showViewOptions" />
                <padding>
                    <Insets top="5" left="5" bottom="5" right="5"/>
                </padding>
            </HBox>
        </bottom>
    </BorderPane>
    

    MainController.java:

    import java.io.IOException;
    
    import javafx.fxml.FXML;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.scene.control.TableColumn;
    import javafx.stage.Stage;
    
    public class MainController {
    
        @FXML
        private TableColumn<Void, Void> nameColumn ;
        @FXML
        private TableColumn<Void, Void> optionalColumn ;
    
        @FXML
        private void showViewOptions() throws IOException {
            FXMLLoader loader = new FXMLLoader(ViewOptionsController.class.getResource("ViewOptions.fxml"));
            Parent root = loader.load();
            ViewOptionsController controller = loader.getController();
            controller.setOptionalColumnVisible(optionalColumn.isVisible());
            Scene scene = new Scene(root);
            Stage stage = new Stage();
            stage.setScene(scene);
            stage.initOwner(nameColumn.getTableView().getScene().getWindow());
            stage.setOnHidden(e -> {
                refreshTable(controller.isOptionalColumnVisible());
            });
            stage.show();
        }
    
        private void refreshTable(boolean showOptionalColumn) {
            optionalColumn.setVisible(showOptionalColumn);
        }
    }
    

    ViewOptions.fxml:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.scene.layout.VBox?>
    <?import javafx.scene.control.CheckBox?>
    <?import javafx.scene.control.Button?>
    <?import javafx.geometry.Insets?>
    
    <VBox fx:controller="ViewOptionsController" spacing="5" alignment="center" xmlns:fx="http://javafx.com/fxml/1">
        <CheckBox text="Show Data Column" fx:id="optionalColumnVisibleCheckBox" />
        <Button text="OK" onAction="#close" />
        <padding>
            <Insets top="5" left="5" right="5" bottom="5"/>
        </padding>
    </VBox>
    

    ViewOptionsController.java:

    import javafx.beans.property.BooleanProperty;
    import javafx.fxml.FXML;
    import javafx.scene.control.CheckBox;
    
    public class ViewOptionsController {
    
        @FXML
        private CheckBox optionalColumnVisibleCheckBox ;
    
        public BooleanProperty optionalColumnVisibleProperty() {
            return optionalColumnVisibleCheckBox.selectedProperty();
        }
    
        public final boolean isOptionalColumnVisible() {
            return optionalColumnVisibleProperty().get();
        }
    
        public final void setOptionalColumnVisible(boolean optionalColumnVisible) {
            optionalColumnVisibleProperty().set(optionalColumnVisible);
        }
    
        @FXML
        private void close() {
            optionalColumnVisibleCheckBox.getScene().getWindow().hide();
        }
    }
    

    Application class:

    import java.io.IOException;
    
    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.stage.Stage;
    
    public class HideColumnsFromDialog extends Application {
    
        @Override
        public void start(Stage primaryStage) throws IOException {
            Parent root = FXMLLoader.load(MainController.class.getResource("Main.fxml"));
            Scene scene = new Scene(root, 600, 600);
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    As an aside, note that the functionality you are implementing here is built in to the table view already: you can use

    <TableView fx:id="HcTable" tableMenuButtonVisible="true" ... >
    

    and the table will show a button that shows a drop-down menu, from which the user can choose which columns are visible.