亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何使用箭頭按鈕在 TableView 的編輯模式下遍歷單元格

如何使用箭頭按鈕在 TableView 的編輯模式下遍歷單元格

喵喵時光機 2022-09-01 17:43:26
我想使用箭頭/enter鍵遍歷 中的單元格,但是,如果我嘗試在我的自定義EditCell類中實現它,它似乎不起作用。有沒有辦法做到這一點?我嘗試過在 上使用偵聽器,但它實際上并沒有在實際單元格中啟動焦點。TableViewTextField這是我的代碼:測試人員.javapackage tester;import javafx.application.Application;import javafx.scene.Scene;import javafx.scene.control.TableCell;import javafx.scene.control.TableColumn;import javafx.scene.control.TableRow;import javafx.scene.control.TableView;import javafx.scene.layout.HBox;import javafx.stage.Stage;import javafx.util.Callback;public class Tester extends Application{    @Override    public void start(Stage primaryStage)    {        TableView<LineItem> table = new TableView<>();        Callback<TableColumn<LineItem, String>, TableCell<LineItem, String>> textFactoryEditable = (TableColumn<LineItem, String> p) -> new EditableTextCell();        TableColumn<LineItem, String> column1 = new TableColumn<>("Test1");        column1.setCellValueFactory(cellData -> cellData.getValue().getString1Property());        column1.setEditable(true);        column1.setCellFactory(textFactoryEditable);        table.getColumns().add(column1);        TableColumn<LineItem, String> column2 = new TableColumn<>("Test2");        column2.setCellValueFactory(cellData -> cellData.getValue().getString2Property());        column2.setEditable(true);        column2.setCellFactory(textFactoryEditable);        table.getColumns().add(column2);        table.getItems().add(new LineItem());        table.getItems().add(new LineItem());        table.getItems().add(new LineItem());        table.setPrefWidth(500);        HBox root = new HBox();        root.getChildren().addAll(table);        Scene scene = new Scene(root, 500, 500);        primaryStage.setTitle("Hello World!");        primaryStage.setScene(scene);        primaryStage.show();    }    /**     * @param args the command line arguments     */    public static void main(String[] args)    {        launch(args);    }}
查看完整描述

2 回答

?
動漫人物

TA貢獻1815條經驗 獲得超10個贊

行選擇模式

盡管我的評論,但看起來您并不需要為此啟用單元格選擇。從CheckBoxTableCell的實現中汲取靈感,您的自定義應該采用某種形式的回調來獲取模型屬性;它還可能需要一個 StringConverter,允許您使用不僅僅包含 s 的 。下面是一個示例:TableCellTableCellString

import java.util.Objects;

import java.util.function.IntFunction;

import javafx.beans.binding.Bindings;

import javafx.beans.property.ObjectProperty;

import javafx.beans.property.Property;

import javafx.beans.property.SimpleObjectProperty;

import javafx.scene.control.TableCell;

import javafx.scene.control.TableColumn;

import javafx.scene.control.TableView.TableViewFocusModel;

import javafx.scene.control.TextField;

import javafx.scene.input.KeyEvent;

import javafx.util.Callback;

import javafx.util.StringConverter;

import javafx.util.converter.DefaultStringConverter;


public class CustomTableCell<S, T> extends TableCell<S, T> {


    public static <S> Callback<TableColumn<S, String>, TableCell<S, String>> forTableColumn(

            IntFunction<Property<String>> extractor) {

        return forTableColumn(extractor, new DefaultStringConverter());

    }


    public static <S, T> Callback<TableColumn<S, T>, TableCell<S, T>> forTableColumn(

            IntFunction<Property<T>> extractor, StringConverter<T> converter) {

        Objects.requireNonNull(extractor);

        Objects.requireNonNull(converter);

        return column -> new CustomTableCell<>(extractor, converter);

    }


    private final ObjectProperty<IntFunction<Property<T>>> extractor = new SimpleObjectProperty<>(this, "extractor");

    public final void setExtractor(IntFunction<Property<T>> callback) { extractor.set(callback); }

    public final IntFunction<Property<T>> getExtractor() { return extractor.get(); }

    public final ObjectProperty<IntFunction<Property<T>>> extractorProperty() { return extractor; }


    private final ObjectProperty<StringConverter<T>> converter = new SimpleObjectProperty<>(this, "converter");

    public final void setConverter(StringConverter<T> converter) { this.converter.set(converter); }

    public final StringConverter<T> getConverter() { return converter.get(); }

    public final ObjectProperty<StringConverter<T>> converterProperty() { return converter; }


    private Property<T> property;

    private TextField textField;


    public CustomTableCell(IntFunction<Property<T>> extractor, StringConverter<T> converter) {

        setExtractor(extractor);

        setConverter(converter);


        // Assumes this TableCell will never become part of a different TableView

        // after the first one. Also assumes the focus model of the TableView will

        // never change. These are not great assumptions (especially the latter),

        // but this is only an example.

        tableViewProperty().addListener((obs, oldTable, newTable) ->

                newTable.getFocusModel().focusedCellProperty().addListener((obs2, oldPos, newPos) -> {

                    if (getIndex() == newPos.getRow() && getTableColumn() == newPos.getTableColumn()) {

                        textField.requestFocus();

                    }

                })

        );

    }


    @Override

    protected void updateItem(T item, boolean empty) {

        super.updateItem(item, empty);

        if (empty) {

            setText(null);

            setGraphic(null);

            cleanUpProperty();

        } else {

            initializeTextField();

            cleanUpProperty();


            property = getExtractor().apply(getIndex());

            Bindings.bindBidirectional(textField.textProperty(), property, getConverter());


            setGraphic(textField);

            if (getTableView().getFocusModel().isFocused(getIndex(), getTableColumn())) {

                textField.requestFocus();

            }

        }

    }


    private void cleanUpProperty() {

        if (property != null) {

            Bindings.unbindBidirectional(textField.textProperty(), property);

            property = null;

        }

    }


    private void initializeTextField() {

        if (textField == null) {

            textField = new TextField();

            textField.addEventFilter(KeyEvent.KEY_PRESSED, this::processArrowKeys);

            textField.focusedProperty().addListener((observable, wasFocused, isFocused) -> {

                if (isFocused) {

                    getTableView().getFocusModel().focus(getIndex(), getTableColumn());

                }

            });

        }

    }


    private void processArrowKeys(KeyEvent event) {

        if (event.getCode().isArrowKey()) {

            event.consume();


            TableViewFocusModel<S> model = getTableView().getFocusModel();

            switch (event.getCode()) {

                case UP:

                    model.focusAboveCell();

                    break;

                case RIGHT:

                    model.focusRightCell();

                    break;

                case DOWN:

                    model.focusBelowCell();

                    break;

                case LEFT:

                    model.focusLeftCell();

                    break;

                default:

                    throw new AssertionError(event.getCode().name());

            }

            getTableView().scrollTo(model.getFocusedCell().getRow());

            getTableView().scrollToColumnIndex(model.getFocusedCell().getColumn());

        }

    }


}

這個例子并不詳盡,并且做出了不能保證的假設,但它只是一個例子,所以我把任何調整留給你。其中一個改進可能是以某種方式包含文本格式化程序。也就是說,我相信它提供了您正在尋找的基本功能。


要使用此單元格,您只需將 每個 的 設置。沒有必要設置,這樣做實際上可能是有害的,這取決于如何被調用?;旧?,它看起來像這樣:cellFactoryTableColumncellValueFactoryupdateItem


TableView<YourModel> table = ...;


TableColumn<YourModel, String> column = new TableColumn<>("Column");

column.setCellFactory(CustomTableCell.forTableColumn(i -> table.getItems().get(i).someProperty()));

table.getColumns().add(column);

單元格選擇模式

但是,您嘗試實現的此行為本身似乎基于單元格,因此啟用單元格選擇可能更好。這允許自定義人員將其行為基于選擇而不是焦點,并將箭頭鍵處理留給 .下面是上述示例的略微修改版本:TableCellTableView


import java.util.Objects;

import java.util.function.IntFunction;

import javafx.beans.binding.Bindings;

import javafx.beans.property.ObjectProperty;

import javafx.beans.property.Property;

import javafx.beans.property.SimpleObjectProperty;

import javafx.event.EventDispatcher;

import javafx.scene.control.TableCell;

import javafx.scene.control.TableColumn;

import javafx.scene.control.TextField;

import javafx.scene.input.KeyEvent;

import javafx.util.Callback;

import javafx.util.StringConverter;

import javafx.util.converter.DefaultStringConverter;


public class CustomTableCell<S, T> extends TableCell<S, T> {


    /* 

     * -- CODE OMITTED --

     *

     * The factory methods (forTableColumn) and properties (extractor

     * and converter) have been omitted for brevity. They are defined

     * and used exactly the same way as in the previous example.

     */


    private Property<T> property;

    private TextField textField;


    public CustomTableCell(IntFunction<Property<T>> extractor, StringConverter<T> converter) {

        setExtractor(extractor);

        setConverter(converter);

    }


    @Override

    public void updateSelected(boolean selected) {

        super.updateSelected(selected);

        if (selected && !isEmpty()) {

            textField.requestFocus();

        }

    }


    @Override

    protected void updateItem(T item, boolean empty) {

        super.updateItem(item, empty);

        if (empty) {

            setText(null);

            setGraphic(null);

            clearProperty();

        } else {

            initializeTextField();

            clearProperty();


            property = getExtractor().apply(getIndex());

            Bindings.bindBidirectional(textField.textProperty(), property, getConverter());


            setGraphic(textField);

            if (isSelected()) {

                textField.requestFocus();

            }

        }

    }


    private void clearProperty() {

        if (property != null) {

            Bindings.unbindBidirectional(textField.textProperty(), property);

            textField.setText(null);

            property = null;

        }

    }


    private void initializeTextField() {

        if (textField == null) {

            textField = new TextField();

            textField.focusedProperty().addListener((observable, wasFocused, isFocused) -> {

                if (isFocused && !isSelected()) {

                    getTableView().getSelectionModel().clearAndSelect(getIndex(), getTableColumn());

                }

            });


            /*

             * TableView has key handlers that will select cells based on arrow keys being

             * pressed, scrolling to them if necessary. I find this mechanism looks cleaner

             * because, unlike TableView#scrollTo, it doesn't cause the cell to jump to the

             * top of the TableView.

             *

             * The way this works is by bypassing the TextField if, and only if, the event

             * is a KEY_PRESSED event and the pressed key is an arrow key. This lets the

             * event bubble up back to the TableView and let it do what it needs to. All

             * other key events are given to the TextField for normal processing.

             *

             * NOTE: The behavior being relied upon here is added by the default TableViewSkin

             *       and its corresponding TableViewBehavior. This may not work if a custom

             *       TableViewSkin skin is used.

             */

            EventDispatcher oldDispatcher = textField.getEventDispatcher();

            textField.setEventDispatcher((event, tail) -> {

                if (event.getEventType() == KeyEvent.KEY_PRESSED

                        && ((KeyEvent) event).getCode().isArrowKey()) {

                    return event;

                } else {

                    return oldDispatcher.dispatchEvent(event, tail);

                }

            });

        }

    }


}

筆記

  1. 使用(并且實際選擇多個行/單元格)時,這兩種方法都不起作用。SelectionMode.MULTIPLE

  2. 上的集不能定義提取器。由于某種原因,這會導致表在您鍵入 時選擇下一個右側單元格。ObservableListTableViewTextField

  3. 僅使用 JavaFX 12 測試了這兩種方法。


查看完整回答
反對 回復 2022-09-01
?
叮當貓咪

TA貢獻1776條經驗 獲得超12個贊

多虧了Slaw,才想通了。


首先啟用單元格選擇,table.getSelectionModel().setCellSelectionEnabled(true);


然后在 EditableTextCell.java類中:


        this.focusedProperty().addListener((ObservableValue<? extends Boolean> o, Boolean oldValue, Boolean newValue) ->

        {

            if (newValue)

            {

                textField.requestFocus();

            }


        });


        textField.focusedProperty().addListener((ObservableValue<? extends Boolean> o, Boolean oldValue, Boolean newValue) ->

        {

            if (newValue)

            {

                getTableView().getFocusModel().focus(getTableRow().getIndex(), getTableColumn());

            }

        }



        textField.setOnKeyPressed((KeyEvent ke) ->

        {

            switch (ke.getCode())

            {

                case DOWN:

                    getTableView().getFocusModel().focusBelowCell();

                    ke.consume();

                    break;

                case ENTER:

                    getTableView().getFocusModel().focusBelowCell();

                    ke.consume();

                    break;

                case UP:

                    getTableView().getFocusModel().focusAboveCell();

                    ke.consume();

                    break;

                case RIGHT:

                    getTableView().getFocusModel().focusRightCell();

                    ke.consume();

                    break;

                case LEFT:

                    getTableView().getFocusModel().focusLeftCell();

                    ke.consume();

                    break;

                default:

                    break;

            }

        });


查看完整回答
反對 回復 2022-09-01
  • 2 回答
  • 0 關注
  • 95 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號