2013-06-24 2 views
7

I javafx Tableview mit aktiven Sortier- und Einsetzen einer neuen Reihe bin mit jeder Millisekunde ...JavaFX einer Tabellen- Halten Sie ausgewählte Zeile in der aktuellen Ansicht

ich diese Funktionalität wünschen:

Wenn ich eine Zeile dann ausgewählt Es sollte sichtbar bleiben (das heißt, sollte nicht vom aktuellen sichtbaren Teil meiner Tabelle nach oben oder unten gehen), wenn neue Zeilen eingefügt werden.

+0

Was hast du bisher versucht? –

+0

table.scrollto (selectedindex) aber dann lässt es nicht zu scrollen, wenn etwas ausgewählt ist ... – learner

Antwort

7

Das mag das lange weg sein und es ist irgendwie hackisch, aber es hat für mich funktioniert, als ich etwas ähnliches machen musste.

Der Kern der Antwort ist, dass Sie Zugriff auf die VirtualFlow Mitglied der TableViewSkin erhalten müssen. Das ist nicht so einfach, wie es klingt, weil die Skin erst geladen wird, wenn das CSS analysiert wurde. Ich fügte ein Listener dem skinProperty des TableView hinzu und war in der Lage, das VirtualFlow so zu erhalten.

tableView.skinProperty().addListener(new ChangeListener<Skin>() 
{ 
    @Override 
    public void changed(ObservableValue<? extends Skin> ov, Skin t, Skin t1) 
    { 
     if (t1 == null) { return; } 

     TableViewSkin tvs = (TableViewSkin)t1; 
     ObservableList<Node> kids = tvs.getChildrenUnmodifiable(); 

     if (kids == null || kids.isEmpty()) { return; } 
     flow = (VirtualFlow)kids.get(1); 
    } 
}); 

Nachdem Sie die VirtualFlow haben, können Sie an den Tisch des hören ObservableList für Änderungen und überprüfen, um das ausgewählte Element stellen Sie sicher, nach wie vor in der Ansicht ist.

countries.addListener(new ListChangeListener<Country>() 
{ 
    @Override 
    public void onChanged(ListChangeListener.Change<? extends Country> change) 
    { 
     while (change.next()) 
     { 
      if (change.wasAdded()) 
      { 
      if (flow == null) { return; } 
      int first = flow.getFirstVisibleCell().getIndex(); 
      int last = flow.getLastVisibleCell().getIndex(); 
      int selected = tableView.getSelectionModel().getSelectedIndex(); 

      if (selected < first || selected > last) 
      { 
       flow.show(selected); 
      } 
      } 
     } 
    } 
}); 

Es wird immer noch ein bisschen Buchhaltung zu verwalten sein. Zum Beispiel, wenn Sie den Fokus wieder auf den Tisch legen wollten. Es ist auch erwähnenswert, dass die VirtualFlow nicht streng an das sichtbare Rechteck der Tabelle gebunden ist, sodass ein Objekt auch dann als sichtbar betrachtet werden kann, wenn es sich außerhalb des Ansichtsfensters befindet. Sie können die VirtualFlow für weitere Details studieren.

Hier ist ein SSCCE.

JavaFXApplication21.java:

package javafxapplication21; 

import javafx.application.Application; 
import javafx.fxml.FXMLLoader; 
import javafx.scene.Parent; 
import javafx.scene.Scene; 
import javafx.stage.Stage; 

public class JavaFXApplication21 extends Application 
{ 
    @Override 
    public void start(Stage stage) throws Exception 
    { 
     Parent root = FXMLLoader.load(getClass().getResource("Sample.fxml")); 

     Scene scene = new Scene(root); 

     stage.setScene(scene); 
     stage.show(); 
    } 

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

Sample.fxml:

<?xml version="1.0" encoding="UTF-8"?> 

<?import java.lang.*?> 
<?import java.util.*?> 
<?import javafx.scene.*?> 
<?import javafx.scene.control.*?> 
<?import javafx.scene.layout.*?> 

<AnchorPane id="AnchorPane" prefHeight="200.0" prefWidth="200.0" xmlns:fx="http://javafx.com/fxml" fx:controller="javafxapplication21.SampleController"> 
    <children> 
    <ToolBar AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> 
     <items> 
     <Button fx:id="insertBtn" mnemonicParsing="false" text="Insert" /> 
     </items> 
    </ToolBar> 
    <TableView fx:id="tableView" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="31.0"> 
     <columns> 
     <TableColumn prefWidth="100.0" text="Country" fx:id="countryColumn" /> 
     <TableColumn prefWidth="100.0" text="Capital" fx:id="capitalColumn" /> 
     </columns> 
    </TableView> 
    </children> 
</AnchorPane> 

SampleController.java:

package javafxapplication21; 

import com.sun.javafx.scene.control.skin.TableViewSkin; 
import com.sun.javafx.scene.control.skin.VirtualFlow; 
import java.net.URL; 
import java.util.*; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.value.ChangeListener; 
import javafx.beans.value.ObservableValue; 
import javafx.collections.*; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.fxml.FXML; 
import javafx.fxml.Initializable; 
import javafx.scene.Node; 
import javafx.scene.control.*; 
import javafx.scene.control.cell.PropertyValueFactory; 

public class SampleController implements Initializable 
{ 
    @FXML private Button insertBtn; 
    @FXML private TableView<Country> tableView; 
    @FXML private TableColumn<Country, String> countryColumn; 
    @FXML private TableColumn<Country, String> capitalColumn; 

    private VirtualFlow flow; 

    private ObservableList<Country> countries = 
      FXCollections.observableArrayList(); 
    private List<Country> insertList = new ArrayList<>(); 

    public SampleController() 
    { 
     countries.addAll(new Country("AG", "Buenos Aires"), 
       new Country("AU", "Vienna"), 
       new Country("BY", "Minsk"), 
       new Country("CO", "Bogota"), 
       new Country("EG", "Cairo")); 

     insertList.add(new Country("ZI", "Harare")); 
     insertList.add(new Country("UK", "London")); 
     insertList.add(new Country("TW", "Taipei")); 
    } 

    @Override 
    public void initialize(URL url, ResourceBundle rb) 
    { 
     countryColumn.setCellValueFactory(
       new PropertyValueFactory<Country, String>("name")); 
     capitalColumn.setCellValueFactory(
       new PropertyValueFactory<Country, String>("capital")); 

     tableView.setItems(countries); 

     tableView.skinProperty().addListener(new ChangeListener<Skin>() 
     { 
      @Override 
      public void changed(ObservableValue<? extends Skin> ov, 
       Skin t, Skin t1) 
      { 
       if (t1 == null) { return; } 

       TableViewSkin tvs = (TableViewSkin)t1; 
       ObservableList<Node> kids = tvs.getChildrenUnmodifiable(); 

       if (kids == null || kids.isEmpty()) { return; } 

       flow = (VirtualFlow)kids.get(1); 
      } 
     }); 

     insertBtn.setOnAction(new EventHandler<ActionEvent>() 
     { 
      @Override 
      public void handle(ActionEvent t) 
      { 
       if (!insertList.isEmpty()) 
       { 
        countries.add(2, insertList.get(0)); 
        insertList.remove(0); 
       } 
      } 
     }); 

     countries.addListener(new ListChangeListener<Country>() 
     { 
      @Override 
      public void onChanged(ListChangeListener.Change<? extends Country> change) 
      { 
       while (change.next()) 
       { 
        if (change.wasAdded()) 
        { 
         if (flow == null) { return; } 
         int first = flow.getFirstVisibleCell().getIndex(); 
         int last = flow.getLastVisibleCell().getIndex(); 
         int selected = tableView.getSelectionModel().getSelectedIndex(); 

         if (selected < first || selected > last) 
         { 
          flow.show(selected); 
         } 
        } 
       } 
      } 
     }); 
    } 

    public class Country 
    { 
     private SimpleStringProperty name; 
     private SimpleStringProperty capital; 

     public Country(String name, String capital) 
     { 
      this.name = new SimpleStringProperty(name); 
      this.capital = new SimpleStringProperty(capital); 
     } 

     public SimpleStringProperty nameProperty() { return name; } 
     public SimpleStringProperty capitalProperty() { return capital; } 
    } 
} 
1

Ich hatte auch das gleiche Problem .Sie cellEventHandler Klasse verwenden können, um Dies bewirkt, dass die EventHandler-Schnittstelle ausgelöst wird, wenn eine Zelle in der Tabelle ausgewählt und der zuletzt ausgewählte Zeilenindex festgelegt wird zu einer Variablen. Die Klasse ist wie folgt.

Dann sollte Ihre Tabelle Klasse Rendern der Tabelle in PanelController-Klasse wie folgt sein.

typeCol.setCellFactory(new Callback<TableColumn<tableModel, String>, TableCell<tableModel, String>>() 
    { 
     @Override 
     public TableCell<tableModel, String> call(TableColumn<tableModel, String> tableColumn) 
     { 
      LableCell lableCell = new LableCell(Pos.CENTER, true); 
      lableCell.addEventFilter(MouseEvent.MOUSE_CLICKED, new CellEventHandler()); 
      return lableCell; 
     } 
    }); 

Das „selectedItem“ Feld sollte in der panelController Klasse als statisches Feld deklariert werden und dann die „selectedItem“ in der Tabelle als ausgewählter Satz soll, wenn Sie die Tabellenzeilendaten aktualisieren.

myTable.getSelectionModel().select(selectedItem);  
Verwandte Themen