Java 按住箭头键时,TableView会失控

Java 按住箭头键时,TableView会失控,java,javafx,Java,Javafx,通过使用此示例,使用箭头键遍历可编辑的表格视图: 按下向下箭头时会出现一个奇怪的问题。它似乎可以正常工作一段时间,但是如果你按下向下箭头键和向上箭头键,桌子开始陷入一个快速上下移动的循环中,你无法摆脱它。只有在表上存在滚动条时才会发生这种情况,因此必须向表中添加一些项目 这是我的密码: Test.java package test; import javafx.application.Application; import javafx.beans.property.SimpleStrin

通过使用此示例,使用箭头键遍历可编辑的
表格视图

按下向下箭头时会出现一个奇怪的问题。它似乎可以正常工作一段时间,但是如果你按下向下箭头键和向上箭头键,桌子开始陷入一个快速上下移动的循环中,你无法摆脱它。只有在表上存在滚动条时才会发生这种情况,因此必须向表中添加一些项目

这是我的密码:

Test.java

package test;

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.stage.Stage;

public class Test extends Application
{

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception
    {
        TableView<Model> table = new TableView();
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());

        table.getSelectionModel().setCellSelectionEnabled(true);
        TableColumn<Model, String> column = new TableColumn<>("Column");
        column.setCellFactory(CustomTableCell.forTableColumn(i -> table.getItems().get(i).getNameProperty()));
        table.getColumns().add(column);

        final Scene scene = new Scene(table);

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public class Model
    {

        private SimpleStringProperty name;

        public Model()
        {
            name = new SimpleStringProperty();
        }

        /**
         * @return the string
         */
        public SimpleStringProperty getNameProperty()
        {
            return name;
        }

    }
}
package test;

import java.util.Objects;
import java.util.function.IntFunction;
import javafx.application.Platform;
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>
{

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

    @Override
    public void updateSelected(boolean selected)
    {
        super.updateSelected(selected);
        if (selected && !isEmpty())
        {
                Platform.runLater(() -> 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())
            {
                Platform.runLater(() -> 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);
                }
            });
        }
    }

}
封装测试;
导入javafx.application.application;
导入javafx.beans.property.SimpleStringProperty;
导入javafx.scene.scene;
导入javafx.scene.control.TableColumn;
导入javafx.scene.control.TableView;
导入javafx.stage.stage;
公共类测试扩展了应用程序
{
/**
*@param指定命令行参数
*/
公共静态void main(字符串[]args)
{
发射(args);
}
@凌驾
public void start(Stage primaryStage)引发异常
{
TableView table=新TableView();
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getItems().add(新模型());
table.getSelectionModel().setCellSelectionEnabled(true);
TableColumn=新的TableColumn(“列”);
setCellFactory(CustomTableCell.forTableColumn(i->table.getItems().get(i).getNameProperty());
table.getColumns().add(列);
最终场景=新场景(表);
初级阶段。场景(场景);
primaryStage.show();
}
公共类模型
{
私有财产名称;
公共模型()
{
名称=新的SimpleStringProperty();
}
/**
*@返回字符串
*/
公共SimpleStringProperty getNameProperty()
{
返回名称;
}
}
}
CustomTableCell.java

package test;

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.stage.Stage;

public class Test extends Application
{

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception
    {
        TableView<Model> table = new TableView();
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());
        table.getItems().add(new Model());

        table.getSelectionModel().setCellSelectionEnabled(true);
        TableColumn<Model, String> column = new TableColumn<>("Column");
        column.setCellFactory(CustomTableCell.forTableColumn(i -> table.getItems().get(i).getNameProperty()));
        table.getColumns().add(column);

        final Scene scene = new Scene(table);

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public class Model
    {

        private SimpleStringProperty name;

        public Model()
        {
            name = new SimpleStringProperty();
        }

        /**
         * @return the string
         */
        public SimpleStringProperty getNameProperty()
        {
            return name;
        }

    }
}
package test;

import java.util.Objects;
import java.util.function.IntFunction;
import javafx.application.Platform;
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>
{

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

    @Override
    public void updateSelected(boolean selected)
    {
        super.updateSelected(selected);
        if (selected && !isEmpty())
        {
                Platform.runLater(() -> 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())
            {
                Platform.runLater(() -> 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);
                }
            });
        }
    }

}
封装测试;
导入java.util.Objects;
导入java.util.function.IntFunction;
导入javafx.application.Platform;
导入javafx.beans.binding.Bindings;
导入javafx.beans.property.ObjectProperty;
导入javafx.beans.property.property;
导入javafx.beans.property.SimpleObject属性;
导入javafx.event.EventDispatcher;
导入javafx.scene.control.TableCell;
导入javafx.scene.control.TableColumn;
导入javafx.scene.control.TextField;
导入javafx.scene.input.KeyEvent;
导入javafx.util.Callback;
导入javafx.util.StringConverter;
导入javafx.util.converter.DefaultStringConverter;
公共类CustomTableCell扩展了TableCell
{
forTableColumn的公共静态回调(
IntFunction(函数提取器)
{
返回forTableColumn(提取器,新的DefaultStringConverter());
}
forTableColumn的公共静态回调(
IntFunction提取器,StringConverter转换器)
{
对象。requirennull(提取器);
对象。requirennull(转换器);
返回列->新建CustomTableCell(提取器、转换器);
}
私有最终ObjectProperty提取器=新的SimpleObjectProperty(此“提取器”);
公共最终无效集合提取器(IntFunction回调)
{
提取器.set(回调);
}
公共函数getExtractor()
{
R