java Javafx Tableview 在当前视图中保留所选行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17268529/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 01:31:52  来源:igfitidea点击:

Javafx Tableview Keep selected row in current view

javajavafx-2tableview

提问by learner

I am using javafx tableview with active sorting and insertion of a new row every millisecond...

我正在使用 javafx tableview,每毫秒主动排序和插入一个新行...

I want this functionality:

我想要这个功能:

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.

如果我选择了一行,那么在插入新行时它应该保持可见(即不应该从我的表的当前可见部分向上或向下)。

采纳答案by OttPrime

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.

这可能离它很远而且有点hackish,但是当我需要做类似的事情时它对我有用。

The gist of the answer is that you need to get access to the VirtualFlowmember 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 Listenerto the skinPropertyof the TableViewand was able to get the VirtualFlowthat way.

答案的要点是,你需要获得访问VirtualFlow的成员TableViewSkin。这并不像听起来那么简单,因为在解析 CSS 之前不会加载皮肤。我添加了一个ListenerskinPropertyTableView,并能得到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);
   }
});

After you have the VirtualFlow, you can listen to the table's ObservableListfor changes and check to make sure the selected item is still in the viewport.

获得 后VirtualFlow,您可以听取表格的ObservableList更改并检查以确保所选项目仍在视口中。

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

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 VirtualFlowisn'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 VirtualFlowfor more details.

仍然会有一些簿记需要管理。例如,如果您想将焦点放回到桌子上。此外,值得注意的VirtualFlow是, 不受表格的可见矩形严格约束,因此即使项目位于视口之外,也可能被视为可见。您可以研究VirtualFlow以获取更多详细信息。

Here's a SSCCE.

这是一个 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:

示例.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:

示例控制器.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; }
    }
}

回答by mawas

I also had the same problem .You can use cellEventHandler class to which implemets EventHandler interface to fired when a cell is selcted in table and set last selected row index to a variable. The class is as followed.

我也有同样的问题。您可以使用 cellEventHandler 类,当在表格中选择单元格并将最后选择的行索引设置为变量时,该类实现了 EventHandler 接口。课程如下。

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

Then your table class render of the table in PanelController Class should be as followed.

然后您的 PanelController Class 中表格的表格类渲染应如下所示。

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

The "selectedItem" field should be declared in the panelController class as static field and then that "selectedItem " should set as selected in the table when you refresh the table row data.

“selectedItem”字段应在 panelController 类中声明为静态字段,然后当您刷新表行数据时,“selectedItem”应在表中设置为选中。

 myTable.getSelectionModel().select(selectedItem);