gocan76
gocan76

Reputation: 39

right click event and double click event on tableview javafx

I am rewriting an application from swing to javafx.

I do not understand how to implement a double click event and a right click event on the same row of a tableview. Separately they work ok.

Thi is my code for right click behaviour.

words_table.setRowFactory(
new Callback<TableView<WordsToFind>, TableRow<WordsToFind>>() {
@Override
public TableRow<WordsToFind> call(TableView<WordsToFind> tableView) {
final TableRow<WordsToFind> row = new TableRow<>();
final ContextMenu rowMenu = new ContextMenu();
MenuItem removeItem = new MenuItem("Delete");
removeItem.setOnAction(e -> {
int wordid = words_table.getSelectionModel().getSelectedItem().getWordToFindId();
deleteWord(wordid);
words_table.getItems().remove(row.getItem());
});
rowMenu.getItems().addAll(removeItem);
row.contextMenuProperty().bind(
  Bindings.when(Bindings.isNotNull(row.itemProperty()))
  .then(rowMenu)
  .otherwise((ContextMenu)null));
return row;
    }    
});

This is my code for double click behaviour

words_table.setRowFactory(  
new Callback<TableView<WordsToFind>, TableRow<WordsToFind>>() {
@Override
public TableRow<WordsToFind> call(TableView<WordsToFind> tableView) {
final TableRow<WordsToFind> row = new TableRow<>();
row.setOnMouseClicked(new EventHandler<MouseEvent>(){
    @Override
        public void handle(MouseEvent event){
            if (event.getClickCount() == 2 && (! row.isEmpty()) ) {
               some code here .....
            }
    }
});
return row;
    }    
});

Thanks Alb

Upvotes: 0

Views: 3182

Answers (2)

James_D
James_D

Reputation: 209235

Just put the row.setOnMouseClicked call in the call() method of the first row factory.

words_table.setRowFactory(tableView -> {
    final TableRow<WordsToFind> row = new TableRow<>();
    final ContextMenu rowMenu = new ContextMenu();
    MenuItem removeItem = new MenuItem("Delete");
    removeItem.setOnAction(e -> {
        int wordid = words_table.getSelectionModel().getSelectedItem().getWordToFindId();
        deleteWord(wordid);
        words_table.getItems().remove(row.getItem());
    });

    rowMenu.getItems().addAll(removeItem);
    row.contextMenuProperty().bind(
        Bindings.when(Bindings.isNotNull(row.itemProperty()))
                .then(rowMenu)
                .otherwise((ContextMenu)null));

    row.setOnMouseClicked(event -> {
        if (event.getClickCount() == 2 && (! row.isEmpty()) ) {
            // some code here .....
        }
    });

    return row;
});

(I converted the anonymous inners classes to lambda expressions for readability.)

Here is a complete example that demonstrates this working:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Function;

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.stage.Stage;

public class RowFactoryExample extends Application {

    @Override
    public void start(Stage primaryStage) {

        TableView<Item> table = new TableView<>();
        table.getColumns().add(column("Item", Item::nameProperty));
        table.getColumns().add(column("Value", Item::valueProperty));
        table.getItems().setAll(createData());

        table.setRowFactory(tableView -> {
            final TableRow<Item> row = new TableRow<>();
            final ContextMenu rowMenu = new ContextMenu();
            MenuItem removeItem = new MenuItem("Delete");
            removeItem.setOnAction(e -> {
                table.getItems().remove(row.getItem());
            });

            rowMenu.getItems().addAll(removeItem);
            row.contextMenuProperty().bind(
                Bindings.when(Bindings.isNotNull(row.itemProperty()))
                        .then(rowMenu)
                        .otherwise((ContextMenu)null));

            row.setOnMouseClicked(event -> {
                if (event.getClickCount() == 2 && (! row.isEmpty()) ) {
                    System.out.println("Double click on "+row.getItem().getName());
                }
            });

            return row;
        });

        Scene scene = new Scene(table, 600, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private <S,T> TableColumn<S,T> column(String text, Function<S, ObservableValue<T>> prop) {
        TableColumn<S,T> col = new TableColumn<>(text);
        col.setCellValueFactory(cellData -> prop.apply(cellData.getValue()));
        return col ;
    }

    private List<Item> createData() {
        Random rng = new Random();
        List<Item> data = new ArrayList<>();
        for (int i = 1 ; i <= 100; i++) {
            data.add(new Item("Item "+i, rng.nextInt(1000))) ;
        }
        return data ;
    }

    public static class Item {

        private final StringProperty name = new SimpleStringProperty();
        private final IntegerProperty value = new SimpleIntegerProperty();

        public Item(String name, int value) {
            setName(name);
            setValue(value);
        }

        public final StringProperty nameProperty() {
            return this.name;
        }


        public final String getName() {
            return this.nameProperty().get();
        }


        public final void setName(final String name) {
            this.nameProperty().set(name);
        }


        public final IntegerProperty valueProperty() {
            return this.value;
        }


        public final int getValue() {
            return this.valueProperty().get();
        }


        public final void setValue(final int value) {
            this.valueProperty().set(value);
        }



    }

    public static void main(String[] args) {
        launch(args);
    }
}

Upvotes: 2

Courage
Courage

Reputation: 792

You can add both events to the row by doing row.setOnMouseClicked(..) itself as shown below

words_table.setRowFactory(  
    new Callback<TableView<WordsToFind>, TableRow<WordsToFind>>() {
    @Override
    public TableRow<WordsToFind> call(TableView<WordsToFind> tableView) {
    final TableRow<WordsToFind> row = new TableRow<>();
    row.setOnMouseClicked(new EventHandler<MouseEvent>(){
        @Override
            public void handle(MouseEvent event){

                if (event.getClickCount() == 2 && (! row.isEmpty()) ) {
                   //double click code here
                }
                else if(event.isSecondaryButtonDown()){
                  //right click code here
                }
        }
    });
    return row;
        }    
    });

Upvotes: 0

Related Questions