问题描述
当前的默认行为是:
+ ,,,移动焦点
我该如何做到这一点?我应该从哪里开始?
那么,还有另外一个脆弱的方法。
不用乱搞事件,可以用 KeyBinding $ c $ ()新增的ChangeListener< Skin<>>(){$($)
scrollPane.skinProperty b $ b @Override
public void changed(ObservableValue< ;? extends Skin<>> observable,Skin> oldValue,Skin<> newValue){
ScrollPaneSkin scrollPaneSkin =(ScrollPaneSkin )scrollPane.getSkin();
ScrollPaneBehavior scrollPaneBehavior = scrollPaneSkin.getBehavior();
尝试{
字段keyBindingsField = BehaviorBase.class.getDeclaredField(keyBindings);
keyBindingsField。 setAccessible(true);
List< KeyBinding> keyBindings =(List< KeyBinding>)keyBindings Field.get(scrollPaneBehavior);
List< KeyBinding> newKeyBindings = new ArrayList<>(); (KeyBinding keyBinding:keyBindings){
KeyCode code = keyBinding.getCode();
newKeyBindings.add(code == KeyCode.LEFT || code == KeyCode.RIGHT || code == KeyCode.UP || code == KeyCode.DOWN?keyBinding.shift():keyBinding);
}
keyBindingsField.set(scrollPaneBehavior,newKeyBindings);
} catch(NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e){
LOGGER.warn(private api changed。,e);
}
}
});
我认为,如果KeyBindings更加非静态,可修改和公开。
使用来捕获相关的关键事件,并将它们重新映射到不同的关键事件
重映射默认键是个棘手的事情:
- 可能会混淆用户。
- 可能会有意想不到的副作用(例如,TextFields可能无法按预期工作)。 b
$ b请谨慎使用:
import javafx.application。*;
import javafx.event。*;
导入javafx.scene.Scene;
import javafx.scene.control。*;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.TilePane;
import javafx.stage.Stage;
import java.util。*;
public class ScrollInterceptor extends Application {
$ b $ @Override
public void start(Stage stage){
ScrollPane scrollPane = new ScrollPane(
createScrollableContent()
);
场景scene = new Scene(
scrollPane,
300,200
);
remapArrowKeys(scrollPane);
stage.setScene(scene);
stage.show();
hackToScrollToTopLeftCorner(scrollPane);
private void remapArrowKeys(ScrollPane scrollPane){
List< KeyEvent> mappedEvents = new ArrayList<>();
scrollPane.addEventFilter(KeyEvent.ANY,EventHandler< KeyEvent>(){
@Override
public void handle(KeyEvent event){
if(mappedEvents.remove(event) )
return;
switch(event.getCode()){
case UP:
case DOWN:
case LEFT:
case RIGHT:
KeyEvent newEvent = remap(event);
mappedEvents.add(newEvent);
event.consume();
Event.fireEvent(event.getTarget(),newEvent );
}
}
私钥KeyEvent重映射(KeyEvent事件){
KeyEvent newEvent = new KeyEvent(
event.getEventType(),
event.isShiftDown(),$ b $ event.isControlDown(),$ b event.getCharacter(),
event.getText(),
event.getCode(),
! b $ b event.isAltDown(),
event.isMetaDown()
);
return newEvent.copyFor(event.getSource(),event.getTarget());
}
});
$ b $ private TilePane createScrollableContent(){
TilePane tiles = new TilePane();
tiles.setPrefColumns(10);
tiles.setHgap(5);
tiles.setVgap(5);
for(int i = 0; i Button button = new Button(i +);
button.setMaxWidth(Double.MAX_VALUE);
button.setMaxHeight(Double.MAX_VALUE);
tiles.getChildren()。add(button);
}
返回图块;
$ b private void hackToScrollToTopLeftCorner(final ScrollPane scrollPane){
Platform.runLater(new Runnable(){
@Override $ b $ public void run() {
scrollPane.setHvalue(scrollPane.getHmin());
scrollPane.setVvalue(0);
}
});
public static void main(String [] args){
launch(args);
}
}
I got a
ScrollPane
containing focusable Nodes.The current default behaviour is:
+ , , , moves the focus
, , , scrolls the view
I want it the other way around.How can I accomplish this or where should I start?
[EDIT] Well, there is another fragile approach.
Instead of messing around with the events, one could mess around with the
KeyBinding
s.scrollPane.skinProperty().addListener(new ChangeListener<Skin<?>>() { @Override public void changed(ObservableValue<? extends Skin<?>> observable, Skin<?> oldValue, Skin<?> newValue) { ScrollPaneSkin scrollPaneSkin = (ScrollPaneSkin) scrollPane.getSkin(); ScrollPaneBehavior scrollPaneBehavior = scrollPaneSkin.getBehavior(); try { Field keyBindingsField = BehaviorBase.class.getDeclaredField("keyBindings"); keyBindingsField.setAccessible(true); List<KeyBinding> keyBindings = (List<KeyBinding>) keyBindingsField.get(scrollPaneBehavior); List<KeyBinding> newKeyBindings = new ArrayList<>(); for (KeyBinding keyBinding : keyBindings) { KeyCode code = keyBinding.getCode(); newKeyBindings.add(code == KeyCode.LEFT || code == KeyCode.RIGHT || code == KeyCode.UP || code == KeyCode.DOWN ? keyBinding.shift() : keyBinding); } keyBindingsField.set(scrollPaneBehavior, newKeyBindings); } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { LOGGER.warn("private api changed.", e); } } });
I think, that could be the cleaner way, if KeyBindings were more non-static, modifyable and public.
解决方案Use an event filter to capture the relevant key events and remap them to different key events before the events start to bubble.
Re-mapping default keys is a tricky thing which:
- Can confuse the user.
- May have unexpected side effects (e.g. TextFields may no longer work as you expect).
So use with care:
import javafx.application.*; import javafx.event.*; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.input.KeyEvent; import javafx.scene.layout.TilePane; import javafx.stage.Stage; import java.util.*; public class ScrollInterceptor extends Application { @Override public void start(Stage stage) { ScrollPane scrollPane = new ScrollPane( createScrollableContent() ); Scene scene = new Scene( scrollPane, 300, 200 ); remapArrowKeys(scrollPane); stage.setScene(scene); stage.show(); hackToScrollToTopLeftCorner(scrollPane); } private void remapArrowKeys(ScrollPane scrollPane) { List<KeyEvent> mappedEvents = new ArrayList<>(); scrollPane.addEventFilter(KeyEvent.ANY, new EventHandler<KeyEvent>() { @Override public void handle(KeyEvent event) { if (mappedEvents.remove(event)) return; switch (event.getCode()) { case UP: case DOWN: case LEFT: case RIGHT: KeyEvent newEvent = remap(event); mappedEvents.add(newEvent); event.consume(); Event.fireEvent(event.getTarget(), newEvent); } } private KeyEvent remap(KeyEvent event) { KeyEvent newEvent = new KeyEvent( event.getEventType(), event.getCharacter(), event.getText(), event.getCode(), !event.isShiftDown(), event.isControlDown(), event.isAltDown(), event.isMetaDown() ); return newEvent.copyFor(event.getSource(), event.getTarget()); } }); } private TilePane createScrollableContent() { TilePane tiles = new TilePane(); tiles.setPrefColumns(10); tiles.setHgap(5); tiles.setVgap(5); for (int i = 0; i < 100; i++) { Button button = new Button(i + ""); button.setMaxWidth(Double.MAX_VALUE); button.setMaxHeight(Double.MAX_VALUE); tiles.getChildren().add(button); } return tiles; } private void hackToScrollToTopLeftCorner(final ScrollPane scrollPane) { Platform.runLater(new Runnable() { @Override public void run() { scrollPane.setHvalue(scrollPane.getHmin()); scrollPane.setVvalue(0); } }); } public static void main(String[] args) { launch(args); } }
这篇关于JavaFX:使用箭头键滚动与焦点遍历的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!