6 Replies Latest reply: Jan 5, 2013 6:05 PM by 966041 RSS

    My own MenuItem in table show/hide column menu

    qwerty1
      Does anyone know if/how I can add an extra MenuItem into that menu that allows to show/hide column in the table? Any way to get more control over that things?

      Appreciate any help !
        • 1. Re: My own MenuItem in table show/hide column menu
          biochemistry43
          How you built your menu?

          with Java code?
          FXML coded?
          • 2. Re: My own MenuItem in table show/hide column menu
            qwerty1
            I don't build the menu. It's a standard JavaFx functionality that allows to show/hide columns from the menu available by "+" on the right hand side of the table column header

            TableView table = new TableView();//create table
            table.setTableMenuButtonVisible(true);//make that menu button available


            but that menu is just a ContextMenu which is populated with table column headers text so I need to get access to that context menu component
            to add some menu items which will be controlled by me....

            Any ideas???
            • 3. Re: My own MenuItem in table show/hide column menu
              James_D
              You're kind of pushing the limits of the functionality that's provided here...

              I don't see any way to get hold of the menu that's shown when you press that button. Your best bet might be to create your own ContextMenu from scratch. You'll have to implement showing/hiding the table columns, but that's not too hard (simply a case of calling setVisible(...) on the appropriate column). Then add your extra menu item(s). Note this also gives you a mechanism to change the names displayed, as you asked in a previous thread.

              Then you can employ this grotesque hack:
              // Note: this is a horrible hack
              // This code must be executed *after* the table is displayed on the screen (i.e. after it's been added to a scene, which is displayed in a stage, and the stage is shown).
              Node showHideColumnsButton = tableView.lookup(".show-hide-columns-button");
              showHideColumnsButton.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent event) {
                  if (event.getButton() == MouseButton.SECONDARY) {
                    contextMenu.show();
                    event.consume();
                  }
                }
              });
              You still want to have tableView.setTableMenuButtonVisible(true), so that the button appears. The event.consume() will prevent the default menu from appearing.

              You could also, I guess, omit tableView.setTableMenuButtonVisible(true), create your own MenuButton with the corresponding menu items, and add it to the stack pane you get from
              StackPane menuButtonHolder = (StackPane) tableView.lookup(".show-hide-column-image");
              I'm not quite sure how you handle layout in that case.

              Edited by: James_D on Jan 4, 2013 10:58 AM
              • 4. Re: My own MenuItem in table show/hide column menu
                James_D
                It seems not too bad:
                import javafx.application.Application;
                import javafx.beans.property.IntegerProperty;
                import javafx.beans.property.SimpleIntegerProperty;
                import javafx.beans.property.SimpleStringProperty;
                import javafx.beans.property.StringProperty;
                import javafx.collections.FXCollections;
                import javafx.collections.ObservableList;
                import javafx.event.ActionEvent;
                import javafx.event.EventHandler;
                import javafx.geometry.Side;
                import javafx.scene.Node;
                import javafx.scene.Scene;
                import javafx.scene.control.CheckMenuItem;
                import javafx.scene.control.ContextMenu;
                import javafx.scene.control.MenuItem;
                import javafx.scene.control.ScrollPane;
                import javafx.scene.control.TableColumn;
                import javafx.scene.control.TableView;
                import javafx.scene.control.cell.PropertyValueFactory;
                import javafx.scene.input.MouseEvent;
                import javafx.scene.layout.BorderPane;
                import javafx.stage.Stage;
                
                public class TableWithCustomShowHideMenu extends Application {
                
                  @Override
                  public void start(Stage primaryStage) throws Exception {
                    final ObservableList<Person> data = FXCollections.observableArrayList(
                        new Person(1, "Joe", "Pesci"), new Person(2, "Audrey", "Hepburn"),
                        new Person(3, "Gregory", "Peck"), new Person(4, "Cary", "Grant"),
                        new Person(5, "De", "Niro"));
                    TableView<Person> tableView = new TableView<Person>();
                    tableView.setTableMenuButtonVisible(true);
                    TableColumn<Person, Integer> idColumn = new TableColumn<Person, Integer>("id");
                    idColumn.setCellValueFactory(new PropertyValueFactory<Person, Integer>("id"));
                
                    // * Menu item for show/hide id column in custom show/hide menu *
                    CheckMenuItem showHideIdCol = new CheckMenuItem("id");
                    showHideIdCol.selectedProperty().bindBidirectional(idColumn.visibleProperty());
                
                    TableColumn<Person, String> firstNameColumn = new TableColumn<Person, String>("First Name");
                    firstNameColumn.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
                
                    // * Menu item for show/hide firstName column in custom show/hide menu. Note text is different to column header *
                    CheckMenuItem showHideFirstNameCol = new CheckMenuItem("First");
                    showHideFirstNameCol.selectedProperty().bindBidirectional(firstNameColumn.visibleProperty());
                
                    TableColumn<Person, String> lastNameColumn = new TableColumn<Person, String>("Last Name");
                    lastNameColumn.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));
                    // * Menu item for show/hide lastName column in custom show/hide menu. Note text is different to column header *
                    CheckMenuItem showHideLastNameCol = new CheckMenuItem("Last");
                    showHideLastNameCol.selectedProperty().bindBidirectional(lastNameColumn.visibleProperty());
                
                    tableView.getColumns().addAll(idColumn, firstNameColumn, lastNameColumn);
                
                    // *Additional menu item*
                    MenuItem otherMenuItem = new MenuItem("Other option");
                    otherMenuItem.setOnAction(new EventHandler<ActionEvent>() {
                      @Override
                      public void handle(ActionEvent event) {
                        System.out.println("Something else");
                      }
                    });
                
                    // * Custom show/hide context menu *
                    final ContextMenu menu = new ContextMenu();
                    menu.getItems().addAll(showHideIdCol, showHideFirstNameCol, showHideLastNameCol, otherMenuItem);
                
                    tableView.setItems(data);
                    BorderPane root = new BorderPane();
                    ScrollPane scroller = new ScrollPane();
                    scroller.setContent(tableView);
                    root.setCenter(scroller);
                    Scene scene = new Scene(root, 400, 250);
                
                    primaryStage.setScene(scene);
                    primaryStage.show();
                
                    // *Register event filter to show or hide the custom show/hide context menu*
                    final Node showHideColumnsButton = tableView.lookup(".show-hide-columns-button");
                    showHideColumnsButton.addEventFilter(MouseEvent.MOUSE_PRESSED,
                        new EventHandler<MouseEvent>() {
                          @Override
                          public void handle(MouseEvent event) {
                            if (menu.isShowing()) {
                              menu.hide(); 
                            } else {
                              menu.show(showHideColumnsButton, Side.BOTTOM, 0, 0);
                            }
                            event.consume();
                          }
                        });
                  }
                
                  public static void main(String[] args) {
                    launch(args);
                  }
                
                  public static class Person {
                
                    private final SimpleIntegerProperty num;
                    private final SimpleStringProperty firstName;
                    private final SimpleStringProperty lastName;
                
                    private Person(int id, String fName, String lName) {
                      this.firstName = new SimpleStringProperty(fName);
                      this.lastName = new SimpleStringProperty(lName);
                      this.num = new SimpleIntegerProperty(id);
                    }
                
                    public String getFirstName() { return firstName.get(); }
                    public void setFirstName(String fName) { firstName.set(fName); }
                    public StringProperty firstNameProperty() { return firstName ; }
                    public String getLastName() { return lastName.get(); }
                    public void setLastName(String fName) { lastName.set(fName); }
                    public StringProperty lastNameProperty() { return lastName ; }
                    public int getId() { return num.get(); }
                    public void setId(int id) { num.set(id); }
                    public IntegerProperty idProperty() { return num ; }
                  }
                }
                • 5. Re: My own MenuItem in table show/hide column menu
                  qwerty1
                  That's exactly what I wanted. Your code works out of the box ! Thank you so much !

                  On a side note, maybe it is pushing the limits of fx but if I can do it in swing I need to be able to do in fx ! and FX needs to provide a cleaner way to achieve this rather than us using "show-hide-columns-button" but it will do for now.

                  Thanks again for your help, James!
                  • 6. Re: My own MenuItem in table show/hide column menu
                    966041
                    Hi your code works fine.
                    A small question.
                    I observed that you have only 5 data for 5 rows but the code shows around 14 rows with remaining 9 rows being empty. That doesn't look well. If someone wants only these 5 rows in the application and no further increasing the size of table data then how do we restrict the table row size to 5 ?