2013-06-24 9 views
7

Używam JavaFX tableview z aktywnym sortowaniu i wstawienie nowego wiersza każdy milisekundy ...JavaFX Tableview zachować wybrany wiersz w bieżącym widoku

chcę tę funkcjonalność:

Jeśli wybrałem wiersz następnie powinna pozostać widoczna (to znaczy nie powinna podnosić się ani opuszczać z obecnej widocznej części mojego stołu) po wstawieniu nowych wierszy.

+0

Jak dotąd próbowałeś? –

+0

table.scrollto (selectedindex) ale wtedy nie pozwoli na przewinięcie, jeśli coś jest zaznaczone ... – learner

Odpowiedz

7

To może być dość daleko i jest to trochę hackish, ale pracował dla mnie, gdy potrzebowałem zrobić coś podobnego.

Istotą odpowiedzi jest to, że musisz uzyskać dostęp do VirtualFlow członka z TableViewSkin. To nie jest tak proste, jak brzmi, ponieważ skóra nie jest ładowana, dopóki nie zostanie przeanalizowany CSS. Dodałem Listener do skinProperty z TableView i udało mi się uzyskać w ten sposób VirtualFlow.

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); 
    } 
}); 

Po masz VirtualFlow można słuchać do stołu ObservableList zmiany i sprawdzić, czy wybrana pozycja jest nadal w rzutni.

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); 
      } 
      } 
     } 
    } 
}); 

Nadal będzie trochę księgowości do zarządzania. Na przykład, jeśli chcesz umieścić skupienie z powrotem na stole. Warto również zauważyć, że VirtualFlow nie jest ściśle związany z widocznym prostokątem stołu, więc element może być uznany za widoczny, nawet jeśli znajduje się tuż poza rzutnią. Aby dowiedzieć się więcej, możesz zapoznać się z VirtualFlow.

Oto 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

miałem również ten sam problem .Umożliwia klasę cellEventHandler do która implikuje interfejs EventHandler do uruchomienia, gdy komórka jest ustawiona w tabeli i ustawia ostatnio wybrany indeks wiersza do zmiennej. Klasa jest następująca.

public class CellEventHandler implements EventHandler<MouseEvent> 

{ 
    CellEventHandler() 
    { 
    } 

    @Override 
    public void handle(MouseEvent t) 
    { 
     TableCell c; 
     c = (TableCell) t.getSource(); 
     c.getIndex(); 
     PanelController.selectedItem = c.getIndex(); 
    } 
}` 

Następnie należy renderować tabelę tabeli w klasie PanelController zgodnie z poniższą instrukcją.

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; 
     } 
    }); 

W „selectedItem” pole powinno być zadeklarowane w klasie panelController jako pola statycznego, a następnie, że „selectedItem” należy ustawić jako wybrany w tabeli po odświeżeniu danych wiersz tabeli.

myTable.getSelectionModel().select(selectedItem);  
Powiązane problemy