【问题标题】:How to get position of an item in ListView in JavaFX?如何在 JavaFX 的 ListView 中获取项目的位置?
【发布时间】:2013-09-28 17:45:50
【问题描述】:

如果我像这样在 JavaFX 中创建 ListView:

ObservableList<String> elements = FXCollections.observableArrayList("John", "Doe");
ListView<String> lView = new ListView<String>(elements);

我想要做的是从 ListView 中一行的末尾开始画一条线,比如从“John”开始

为此,我需要“John”行的位置(x,y)。是否可以获取位置?

更新

这是我使用 Swing 和 Piccolo2D 获得的示例界面。然而,使用那个库是很痛苦的。我想知道我是否可以在 JavaFX 中做同样的事情

【问题讨论】:

  • 您可能需要扩展 ListView 并对其进行自定义,以便某个位置在该 GUI 上有一条线。如果不使用与鼠标相关的事件,我看不到任何简单的方法来获得位置......
  • 嗨 Ankit。您想在什么时候执行此操作?当用户点击列表项时?
  • 你想为每一行画一条线吗?图片说明会很有帮助。

标签: user-interface javafx-2 javafx


【解决方案1】:

这是可能的,但它可能不像您希望的那样简单。为了确定ListView(或TableView/TreeView)中特定Cell 的布局坐标,您需要有权访问该特定Cell 对象。最好的方法(也许是 JavaFX 2.2 中唯一的方法)是为容器提供自定义的 CellCellFactory,它们会公开每个 Cell。你如何暴露Cell 取决于你的触发器是什么来画线的。

根据您的插图,一旦填充了ListViews,您将需要访问每个单元格。您可以使用CellFactory 中的List&lt;ListCell&lt;String&gt;&gt; 字段来执行此操作。我将在这里提到一个关于ListCells 的警告。 ListViewSkin 将尽可能重用Cells。这意味着如果您要尝试填充和连接一个最终滚动的列表,那么将您的行保持在正确的位置将更加困难。我建议您尝试确保您的所有列表项都适合屏幕。

下面是一个示例,其中包含 cmets 中的一些注释。请注意,获取正确的坐标以绘制 Line 可能需要计算 SceneGraph 的偏移量,我在本示例中没有这样做。

package listviewcellposition;

import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
import javafx.util.Callback;

public class ListViewCellPosition extends Application {

    // CustomCellFactory for creating CustomCells
    public class CustomCellFactory implements
            Callback<ListView<String>, ListCell<String>> {

        List<ListCell<String>> allCells = new ArrayList<>();

        @Override
        public ListCell<String> call(final ListView<String> p) {
            final CustomCell cell = new CustomCell();
            allCells.add(cell);
            return cell;
        }

        public List<ListCell<String>> getAllCells() {
            return allCells;
        }
    }

    // CustomCell is where the exposure occurs. Here, it's based on the
    // Cell being selected in the ListView. You could choose a different
    // trigger here but you'll need to explore.
    public class CustomCell extends ListCell<String> {
        // General display stuff
        @Override
        protected void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);
            if (empty) {
                setText(null);
                setGraphic(null);
            } else {
                setText(item == null ? "" : item);
                setGraphic(null);
            }
        }
    }

    @Override
    public void start(Stage primaryStage) {
        // This pane will contain the lines after they are created.
        // I set it into an AnchorPane to avoid having to deal with 
        // resizing.
        Pane linePane = new Pane();
        AnchorPane pane = new AnchorPane();
        pane.setPrefSize(100, 250);
        AnchorPane.setBottomAnchor(linePane, 0.0);
        AnchorPane.setLeftAnchor(linePane, 0.0);
        AnchorPane.setRightAnchor(linePane, 0.0);
        AnchorPane.setTopAnchor(linePane, 0.0);
        pane.getChildren().add(linePane);

        ListView<String> lView = new ListView<>();
        lView.setPrefSize(100, 250);
        CustomCellFactory lCellFactory = new CustomCellFactory();
        lView.setCellFactory(lCellFactory);

        ListView<String> rView = new ListView<>();
        rView.setPrefSize(100, 250);
        CustomCellFactory rCellFactory = new CustomCellFactory();
        rView.setCellFactory(rCellFactory);

        lView.getItems().addAll("Bill", "Doctor", "Steve", "Joanne");
        rView.getItems().addAll("Seuss", "Rowling", "King", "Shakespeare");

        HBox root = new HBox();
        root.getChildren().addAll(lView, pane, rView);

        Scene scene = new Scene(root, 300, 250);
        primaryStage.setScene(scene);
        primaryStage.show();

        connectCells(lCellFactory, "Bill", rCellFactory, "Shakespeare", linePane);
        connectCells(lCellFactory, "Doctor", rCellFactory, "Seuss", linePane);
        connectCells(lCellFactory, "Steve", rCellFactory, "King", linePane);
        connectCells(lCellFactory, "Joanne", rCellFactory, "Rowling", linePane);
    }

    // Looks up the ListCell<> for each String and creates a Line
    // with the coordinates from each Cell. The calculation is very 
    // contrived because I know that all the components have the same 
    // x-coordinate. You'll need more complicated calculations if your
    // containers are not aligned this way.
    private void connectCells(CustomCellFactory lCellFactory, String lVal,
            CustomCellFactory rCellFactory, String rVal, Pane linePane) {

        List<ListCell<String>> lList = lCellFactory.getAllCells();
        ListCell<String> lCell = null;

        for (ListCell<String> lc : lList) {
            if (lc.getItem() != null && lc.getItem().equals(lVal)) {
                lCell = lc;
                break;
            }
        }

        List<ListCell<String>> rList = rCellFactory.getAllCells();
        ListCell<String> rCell = null;

        for (ListCell<String> rc : rList) {
            if (rc.getItem() != null && rc.getItem().equals(rVal)) {
                rCell = rc;
                break;
            }
        }

        if (lCell != null && rCell != null) {
            double startY = lCell.getLayoutY() +
                    (lCell.getBoundsInLocal().getHeight() / 2);
            double endY = rCell.getLayoutY() +
                    (rCell.getBoundsInLocal().getHeight() / 2);

            Line line = new Line(0, startY, 
                    linePane.getBoundsInParent().getWidth(), endY);
            line.setStrokeWidth(2);
            line.setStroke(Color.BLACK);

            linePane.getChildren().add(line);
        }
    }   

    public static void main(String[] args) {
        launch(args);
    }
}

【讨论】:

  • 我认为 op 想要确定一个单元格的位置而不必选择它...
  • 是的,这是一个棘手的布局。我相应地更新了我的示例。我对 Piccolo2D 不熟悉,所以我不知道 JavaFX 会让它变得多么容易(如果有的话)。
猜你喜欢
  • 2021-03-10
  • 1970-01-01
  • 1970-01-01
  • 2015-05-18
  • 2018-03-14
  • 2013-04-11
  • 1970-01-01
  • 2016-08-04
  • 1970-01-01
相关资源
最近更新 更多