This discussion is archived
6 Replies Latest reply: Jan 5, 2013 4:05 PM by 966041 RSS

My own MenuItem in table show/hide column menu

976575 Newbie
Currently Being Moderated
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 Newbie
    Currently Being Moderated
    How you built your menu?

    with Java code?
    FXML coded?
  • 2. Re: My own MenuItem in table show/hide column menu
    976575 Newbie
    Currently Being Moderated
    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 Guru
    Currently Being Moderated
    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 Guru
    Currently Being Moderated
    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
    976575 Newbie
    Currently Being Moderated
    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 Newbie
    Currently Being Moderated
    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 ?

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points