Javafx Tableview将选定的行保留在当前视图中 [英] Javafx Tableview Keep selected row in current view

查看:66
本文介绍了Javafx Tableview将选定的行保留在当前视图中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用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.

答案的要点是,您需要访问TableViewSkinVirtualFlow成员.这并不像听起来那么简单,因为在解析CSS之前不会加载外观.我在TableViewskinProperty中添加了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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆