Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>This may be the long away around it and it's kind of hackish, but it worked for me when I needed to do something similar.</p> <p>The gist of the answer is that you need to get access to the <code>VirtualFlow</code> member of the <code>TableViewSkin</code>. That's not as simple as is sounds because the skin isn't loaded until the CSS is parsed. I added a <code>Listener</code> to the <code>skinProperty</code> of the <code>TableView</code> and was able to get the <code>VirtualFlow</code> that way.</p> <pre><code>tableView.skinProperty().addListener(new ChangeListener&lt;Skin&gt;() { @Override public void changed(ObservableValue&lt;? extends Skin&gt; ov, Skin t, Skin t1) { if (t1 == null) { return; } TableViewSkin tvs = (TableViewSkin)t1; ObservableList&lt;Node&gt; kids = tvs.getChildrenUnmodifiable(); if (kids == null || kids.isEmpty()) { return; } flow = (VirtualFlow)kids.get(1); } }); </code></pre> <p>After you have the <code>VirtualFlow</code>, you can listen to the table's <code>ObservableList</code> for changes and check to make sure the selected item is still in the viewport.</p> <pre><code>countries.addListener(new ListChangeListener&lt;Country&gt;() { @Override public void onChanged(ListChangeListener.Change&lt;? extends Country&gt; 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 &lt; first || selected &gt; last) { flow.show(selected); } } } } }); </code></pre> <p>There will still be a bit of bookkeeping to manage. For instance, if you wanted to place focus back on the table. Also, it's worth noting that the <code>VirtualFlow</code> isn't strictly bound by the visible rectangle of the table, so an item may be considered visible even if it is just outside the viewport. You can study the <a href="https://bitbucket.org/shemnon/openjfx-rt/src/ed94b6913f6676b85cb47267fb3b37985b0ed662/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/VirtualFlow.java">VirtualFlow</a> for more details. </p> <p>Here's a SSCCE.</p> <p>JavaFXApplication21.java:</p> <pre><code>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); } } </code></pre> <p>Sample.fxml:</p> <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;?import java.lang.*?&gt; &lt;?import java.util.*?&gt; &lt;?import javafx.scene.*?&gt; &lt;?import javafx.scene.control.*?&gt; &lt;?import javafx.scene.layout.*?&gt; &lt;AnchorPane id="AnchorPane" prefHeight="200.0" prefWidth="200.0" xmlns:fx="http://javafx.com/fxml" fx:controller="javafxapplication21.SampleController"&gt; &lt;children&gt; &lt;ToolBar AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"&gt; &lt;items&gt; &lt;Button fx:id="insertBtn" mnemonicParsing="false" text="Insert" /&gt; &lt;/items&gt; &lt;/ToolBar&gt; &lt;TableView fx:id="tableView" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="31.0"&gt; &lt;columns&gt; &lt;TableColumn prefWidth="100.0" text="Country" fx:id="countryColumn" /&gt; &lt;TableColumn prefWidth="100.0" text="Capital" fx:id="capitalColumn" /&gt; &lt;/columns&gt; &lt;/TableView&gt; &lt;/children&gt; &lt;/AnchorPane&gt; </code></pre> <p>SampleController.java:</p> <pre><code>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&lt;Country&gt; tableView; @FXML private TableColumn&lt;Country, String&gt; countryColumn; @FXML private TableColumn&lt;Country, String&gt; capitalColumn; private VirtualFlow flow; private ObservableList&lt;Country&gt; countries = FXCollections.observableArrayList(); private List&lt;Country&gt; insertList = new ArrayList&lt;&gt;(); 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&lt;Country, String&gt;("name")); capitalColumn.setCellValueFactory( new PropertyValueFactory&lt;Country, String&gt;("capital")); tableView.setItems(countries); tableView.skinProperty().addListener(new ChangeListener&lt;Skin&gt;() { @Override public void changed(ObservableValue&lt;? extends Skin&gt; ov, Skin t, Skin t1) { if (t1 == null) { return; } TableViewSkin tvs = (TableViewSkin)t1; ObservableList&lt;Node&gt; kids = tvs.getChildrenUnmodifiable(); if (kids == null || kids.isEmpty()) { return; } flow = (VirtualFlow)kids.get(1); } }); insertBtn.setOnAction(new EventHandler&lt;ActionEvent&gt;() { @Override public void handle(ActionEvent t) { if (!insertList.isEmpty()) { countries.add(2, insertList.get(0)); insertList.remove(0); } } }); countries.addListener(new ListChangeListener&lt;Country&gt;() { @Override public void onChanged(ListChangeListener.Change&lt;? extends Country&gt; 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 &lt; first || selected &gt; 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; } } } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload