Javafx Tableview将选定的行保留在当前视图中 [英] Javafx Tableview Keep selected row in current view
问题描述
我使用javafx tableview进行主动排序并每毫秒插入新行...
I am using javafx tableview with active sorting and insertion of a new row every millisecond...
我想要此功能:
如果我选择了一行,那么在插入新行时,该行应保持可见(即不应从表的当前可见部分向上或向下).
If I have selected a row then it should remain visible (that is should not go up or down from current visible portion of my table) when new rows are inserted.
推荐答案
这可能与它相距甚远,有点破旧,但是当我需要做类似的事情时,它对我有用.
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.
答案的要点是,您需要访问TableViewSkin
的VirtualFlow
成员.这并不像听起来那么简单,因为在解析CSS之前不会加载外观.我在TableView
的skinProperty
中添加了Listener
,并能够以这种方式获取VirtualFlow
.
The gist of the answer is that you need to get access to the VirtualFlow
member of the TableViewSkin
. That's not as simple as is sounds because the skin isn't loaded until the CSS is parsed. I added a Listener
to the skinProperty
of the TableView
and was able to get the VirtualFlow
that way.
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);
}
});
在拥有VirtualFlow
之后,您可以收听表的ObservableList
进行更改,并检查以确保所选项目仍在视口中.
After you have the VirtualFlow
, you can listen to the table's ObservableList
for changes and check to make sure the selected item is still in the viewport.
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);
}
}
}
}
});
仍然需要管理一些簿记.例如,如果您想将焦点重新放在桌子上.另外,值得注意的是VirtualFlow
并不受表的可见矩形的严格限制,因此即使项仅位于视口之外,也可以将其视为可见.您可以研究
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 VirtualFlow
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 VirtualFlow for more details.
这是SSCCE.
JavaFXApplication21.java:
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:
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:
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; }
}
}
这篇关于Javafx Tableview将选定的行保留在当前视图中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!