【问题标题】:Row edit in TableViewTableView 中的行编辑
【发布时间】:2014-05-27 08:09:33
【问题描述】:

我在 JavaFX(具体来说是 2.2/Java 7)中有一个 TableView,其中每一列都是可排序的(实时排序)并且所有行/列都是可编辑的。例如,假设整个表格代表一个“订单”。表格中的每一行代表“订单行”,列代表“订单行”的属性,如“产品”、“数量”、“价格”等。用户可以添加、删除和编辑行(“订单”行”)如他所愿。

为了让用户界面不那么混乱,我想使用行选择,并确保一次只能编辑一行(因为排序会使当前编辑的值“跳跃”桌子)。我也有每个“订单行”的验证,这更容易对一行进行可视化,而不是单个列(例如,假设组合或产品 X 和数量 7 是非法的,因为产品 X 只能以单位订购5,我想突出显示 X 和值 7)。

可以轻松启用行选择。但是有没有实现行编辑的好方法TableView 中的默认/内置编辑模式更像是 Excel,其中每一列都可以单独编辑、提交和验证,这不是我想要的。我想要文件资源管理器中的文件列表之类的东西。由于排序和验证,对已编辑行的所有编辑都必须立即提交给支持模型(TableViewitems 属性)(即,对于单个列没有 onEditCommit),这一点很重要。

我之前在 Swing 中实现了类似的东西,然后最终使用了我命名的 ColumnList,它实际上是 List,但带有列标题和列,使它看起来像一个表格。在 JavaFX 中这也是一个可行的选择吗? TableColum 类似乎与 TableView 非常绑定,但我可能遗漏了一些东西。

我还知道 JavaFX 教程中的“地址簿”示例,该示例在表格下方具有行选择和编辑器字段。这是我目前在我的应用程序中实现的,但我希望编辑显示在当前选定的行中。因此,让编辑器出现在当前选定行的“顶部”或“内部”也是一种选择,如果有人能想出一种方法来实现这一点。

【问题讨论】:

  • 是的,有一个好方法。是的,TableColumnTableView 非常有界。看看这个Oracles tutorial 我想它解释了你需要的一切。
  • 谢谢@brano!不过,我知道那个例子,但这并不是我真正想要的。我想要“内联”行编辑。但是,如果我可以使编辑文本字段出现在选定行内的表格“顶部”,它就可以工作。但我还没有找到一种方法来做到这一点......我会更新这个问题。
  • 您希望表格行的所有文本字段同时可编辑吗?
  • @ItachiUchiha:是的,视觉上该行中的所有字段都应该是可编辑的(尽管从技术上讲,只有焦点编辑器必须是可编辑的)。然而,最重要的部分是由于排序/验证,所有编辑都必须立即提交给支持模型(即,单个列没有onEditCommit)。我会再次更新。谢谢!

标签: java javafx javafx-2


【解决方案1】:

您可以随时制作自己的编辑框并根据需要将其弹出到表格上方。这不是一个很好的解决方案,但通过一些调整可能会很好。 Dbl 点击编辑一行。

import javafx.application.Application;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class TableEdit extends Application {

    @Override
    public void start(Stage primaryStage) {
        TableView<Order> tv = new TableView<>();
        ObservableList<Order> items = FXCollections.observableArrayList(
                new Order("a-12", 100), new Order("b-23", 200), new Order("c-34", 300));
        tv.setItems(items);

        TableColumn<Order, String> tcNum = new TableColumn("Order#");
        tcNum.setPrefWidth(100);
        TableColumn<Order, Number> tcQty = new TableColumn("Qty");
        tcQty.setPrefWidth(100);
        tcNum.setCellValueFactory(new PropertyValueFactory<>("orderNum"));
        tcQty.setCellValueFactory(new PropertyValueFactory<>("qty"));
        tv.getColumns().addAll(tcNum, tcQty);

        HBox hbox = new HBox();
        TextField orderNum = new TextField();
        orderNum.setPrefWidth(100);
        TextField qty = new TextField();
        qty.setPrefWidth(100);

        tv.getSelectionModel().selectedItemProperty().addListener((obs, ov, nv) -> {
            if (nv != null) {
                orderNum.setText(nv.orderNum.get());
                qty.setText(String.valueOf(nv.qty.get()));
            }
        });

        Button commit = new Button("Commit");
        commit.setOnAction(new EventHandler<ActionEvent>() {
            public void handle(ActionEvent evt) {
                Order item = tv.getSelectionModel().getSelectedItem();
                item.orderNum.set(orderNum.getText());
                item.qty.set(Integer.valueOf(qty.getText()));
                tv.toFront();
            }
        });

        hbox.getChildren().addAll(orderNum, qty, commit);
        StackPane root = new StackPane(hbox, tv);

        tv.setOnMouseClicked(new EventHandler<MouseEvent>() {
            public void handle(MouseEvent evt) {
                if (evt.getClickCount()==2){
                    StackPane.setMargin(hbox, new Insets(evt.getSceneY(), 0, 0, 0));
                    hbox.toFront();
                }
            }
        });

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

    }

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

    public class Order {

        private final SimpleStringProperty orderNum = new SimpleStringProperty();
        private final SimpleIntegerProperty qty = new SimpleIntegerProperty();

        public SimpleStringProperty orderNumProperty() {return orderNum;}
        public SimpleIntegerProperty qtyProperty() {return qty;}

        public Order(String orderNum, int qty) {
            this.orderNum.set(orderNum);
            this.qty.set(qty);
        }
    }
}

【讨论】:

  • 有趣... :-) 谢谢!明天我将不得不调查这个问题,因为我现在的项目中没有我的工作笔记本电脑。据我了解,这看起来很有希望。我不确定hbox 是否完全适合此代码的当前选择,或者文本字段是否与表中的列对齐。但这似乎是一个可能的开始。 :-)
  • 我添加了一张照片。问题是找到 TableCell 的顶部。所有其他对齐工作正常。我刚刚使用了 prefWidth。
  • 我刚刚意识到,如果您将鼠标单击侦听器放在每个单元格中,您可以从((Cell)event.getSource()).getLocalToSceneTransform().getTy()获取单元格顶部 Y 值
  • 我有机会尝试,是的,这是一个好的开始!我会看看我能不能把它变成我可以使用的东西。正如预期的那样,列/编辑器只是意外对齐(相同的 prefWidth),如果您调整(或重新排列)列标题,您会看到。我使用tv.setRowFactory 和自定义TableRow 来完美对齐hbox 顶部。
  • 通过将文本字段的 prefWidth 属性绑定到相应列标题的 width 属性来修复对齐问题 + 每当列顺序更改时重新排列布局。发现一个新问题:如果在编辑模式下点击列标题(排序),稍后提交时会得到 NPE...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-10-14
  • 2016-12-17
  • 1970-01-01
  • 2012-12-24
  • 1970-01-01
  • 2017-10-21
  • 1970-01-01
相关资源
最近更新 更多