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