2014-10-25 28 views
42

Potrzebuję wykryć podwójne kliknięcia w wierszu TableView.Wykrywanie podwójnego kliknięcia w wierszu tabeli Widok JavaFX

Jak mogę odsłuchać podwójne kliknięcia dowolnej części wiersza i uzyskać wszystkie dane z tego wiersza, aby wydrukować ją na konsoli?

+0

Rozwiązania z użyciem podwójnie kliknąć na komórki będzie działać, bo zawsze można zadzwonić 'getTableRow() GetItem()' na komórce, aby uzyskać pozycję w rzędzie. . Lepiej jest tylko zarejestrować słuchacza w wierszu tabeli bezpośrednio (patrz odpowiedź). –

Odpowiedz

84
TableView<MyType> table = new TableView<>(); 

//... 

table.setRowFactory(tv -> { 
    TableRow<MyType> row = new TableRow<>(); 
    row.setOnMouseClicked(event -> { 
     if (event.getClickCount() == 2 && (! row.isEmpty())) { 
      MyType rowData = row.getItem(); 
      System.out.println(rowData); 
     } 
    }); 
    return row ; 
}); 

Powyżej znajduje się pełna przykład praca:

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

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.beans.value.ObservableValue; 
import javafx.scene.Scene; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableRow; 
import javafx.scene.control.TableView; 
import javafx.stage.Stage; 

public class TableViewDoubleClickOnRow extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     TableView<Item> table = new TableView<>(); 
     table.setRowFactory(tv -> { 
      TableRow<Item> row = new TableRow<>(); 
      row.setOnMouseClicked(event -> { 
       if (event.getClickCount() == 2 && (! row.isEmpty())) { 
        Item rowData = row.getItem(); 
        System.out.println("Double click on: "+rowData.getName()); 
       } 
      }); 
      return row ; 
     }); 
     table.getColumns().add(column("Item", Item::nameProperty)); 
     table.getColumns().add(column("Value", Item::valueProperty)); 

     Random rng = new Random(); 
     for (int i = 1 ; i <= 50 ; i++) { 
      table.getItems().add(new Item("Item "+i, rng.nextInt(1000))); 
     } 

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

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

    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 StringProperty nameProperty() { 
      return name ; 
     } 

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

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

     public IntegerProperty valueProperty() { 
      return value ; 
     } 

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

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

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

Nie działa w ogóle. – Aubin

+0

@Aubin Myślę, że od kiedy ta odpowiedź została przyjęta i ma ponad 80 głosów w górę, to rozsądnie jest założyć, że jeśli to nie działa dla ciebie, to jest coś nie tak z tym, w jaki sposób to robisz. Opublikuj własne pytanie za pomocą [MCVE]. –

+0

Co, jeśli chcę zamiast tego użyć fabryki komórek?Mam już kod, który używa 'PropertyValueFactory' dla każdego pola, jak mogę rozszerzyć twoją metodę, aby nasłuchiwać podwójnych kliknięć? Ponadto, nie rozumiem tej części fabryki twoich wierszy: tworzysz nowy 'TableRow', wywołujesz' getItem' na nim, a następnie drukujesz nazwę tego elementu? Kiedy w grę wchodzą rzeczywiste dane? – Arno

15

Przykład:

table.setOnMousePressed(new EventHandler<MouseEvent>() { 
    @Override 
    public void handle(MouseEvent event) { 
     if (event.isPrimaryButtonDown() && event.getClickCount() == 2) { 
      System.out.println(table.getSelectionModel().getSelectedItem());     
     } 
    } 
});

Jeśli używasz modelu wyboru niestandardowy, a następnie można uzyskać wiersz od zdarzenia, przykład:

table.setOnMousePressed(new EventHandler<MouseEvent>() { 
    @Override 
    public void handle(MouseEvent event) { 
     if (event.isPrimaryButtonDown() && event.getClickCount() == 2) { 
      Node node = ((Node) event.getTarget()).getParent(); 
      TableRow row; 
      if (node instanceof TableRow) { 
       row = (TableRow) node; 
      } else { 
       // clicking on text part 
       row = (TableRow) node.getParent(); 
      } 
      System.out.println(row.getItem()); 
     } 
    } 
});
+3

Podczas gdy to działa (ponieważ pierwsze kliknięcie dwukrotnego kliknięcia wybiera wiersz), selekcja różni się semantycznie dołączając obsługę myszy do wiersza. Jeśli z jakiegoś powodu musisz użyć niestandardowego modelu wyboru, może on złamać ten kod. –

+0

@James_D w pytaniu, w którym nie został zapisany niestandardowy przypadek modelu selekcji, ale odpowiedź dostosowana również dla tego przypadku. –

+0

Który polega zamiast tego na określonej hierarchii węzłów (która jest nieudokumentowana i celowo). Co się stanie, jeśli implementacja mechanizmu układu widoku tabeli zmieni się w przyszłej wersji JavaFX? Po prostu dołącz słuchacza bezpośrednio do wiersza tabeli, kiedy zostanie utworzony. –

0

Jeśli jesteś śpiewać SceneBuilder można ustawić OnMouseClicked do handleRowSelect() metody tabeli w sposób przedstawiony poniżej:

MyType temp; 
Date lastClickTime; 
@FXML 
private void handleRowSelect() { 
    MyType row = myTableView.getSelectionModel().getSelectedItem(); 
    if (row == null) return; 
    if(row != temp){ 
     temp = row; 
     lastClickTime = new Date(); 
    } else if(row == temp) { 
     Date now = new Date(); 
     long diff = now.getTime() - lastClickTime.getTime(); 
     if (diff < 300){ //another click registered in 300 millis 
      System.out.println("Edit dialog"); 
     } else { 
      lastClickTime = new Date(); 
     } 
    } 
} 
0

Ta odpowiedź została przetestowana:

table.setOnMouseClicked(event -> { 
    if(event.getClickCount() == 2) { 
     System.out.println(table.getSelectionModel().getSelectedItem()); 
    }}); 

table.getSelectionModel().getSelectedItem() może być użyty ponieważ złapać podwójne kliknięcie. Jedno pierwsze kliknięcie powoduje przesunięcie zaznaczenia, na sekundę jest wykonywany ten przewodnik.

0

Działa to dla mnie:

table.setOnMouseClicked((MouseEvent event) -> { 
      if (event.getButton().equals(MouseButton.PRIMARY) && event.getClickCount() == 2){ 
       System.out.println(table.getSelectionModel().getSelectedItem()); 
      } 
     }); 
    }