By default, the MoveAction on Widgets in the NetBeans Visual Library lets the user move widgets via the mouse. But what about the keyboard? Using the code below, whenever the user presses Up/Down/Left/Right on a widget, it will move 20 pixels in that direction.
Note: Some little gotchas to be aware of are also solved below, e.g., include a SelectProvider so that when a widget is selected, it receives the focus and, more importantly, so that key event processing is correct.
public AccountBuchWidget(final Scene scene, AccountBuch ab, Point point) {
super(scene);
setNodeName(ab.getDescription());
setPreferredLocation(point);
getActions().addAction(new KeyboardMoveAction());
getActions().addAction(ActionFactory.createSelectAction(new SelectProvider() {
@Override
public boolean isAimingAllowed(Widget widget, Point localLocation, boolean invertSelection) {
return true;
}
@Override
public boolean isSelectionAllowed(Widget widget, Point localLocation, boolean invertSelection) {
return true;
}
@Override
public void select(Widget widget, Point localLocation, boolean invertSelection) {
scene.setFocusedWidget(widget);
}
}));
}
private final class KeyboardMoveAction extends WidgetAction.Adapter {
private MoveProvider provider;
private KeyboardMoveAction() {
this.provider = ActionFactory.createDefaultMoveProvider();
}
@Override
public WidgetAction.State keyPressed(Widget widget, WidgetAction.WidgetKeyEvent event) {
Point originalSceneLocation = provider.getOriginalLocation(widget);
int newY = originalSceneLocation.y;
int newX = originalSceneLocation.x;
if (event.getKeyCode() == KeyEvent.VK_UP) {
newY = newY - 20;
} else if (event.getKeyCode() == KeyEvent.VK_DOWN) {
newY = newY + 20;
} else if (event.getKeyCode() == KeyEvent.VK_RIGHT) {
newX = newX + 20;
} else if (event.getKeyCode() == KeyEvent.VK_LEFT) {
newX = newX - 20;
}
provider.movementStarted(widget);
provider.setNewLocation(widget, new Point(newX, newY));
return State.CONSUMED;
}
@Override
public WidgetAction.State keyReleased(Widget widget, WidgetAction.WidgetKeyEvent event) {
provider.movementFinished(widget);
return State.REJECTED;
}
}
}
Here's the constructor of the related TopComponent, note especially the call to "setKeyEventProcessingType":
public EditorTopComponent() {
initComponents();
setName(Bundle.CTL_EditorTopComponent());
setToolTipText(Bundle.HINT_EditorTopComponent());
setLayout(new BorderLayout());
JScrollPane pane = new JScrollPane();
final LayerWidget layerWidget = new LayerWidget(scene);
scene.getActions().addAction(ActionFactory.createAcceptAction(new AcceptProvider() {
@Override
public ConnectorState isAcceptable(Widget widget, Point point, Transferable t) {
return ConnectorState.ACCEPT;
}
@Override
public void accept(Widget widget, Point point, Transferable t) {
Node node = NodeTransfer.node(t, NodeTransfer.DND_COPY_OR_MOVE);
final AccountBuch ab = node.getLookup().lookup(AccountBuch.class);
layerWidget.addChild(new AccountBuchWidget(scene, ab, point));
}
}));
scene.setKeyEventProcessingType(EventProcessingType.FOCUSED_WIDGET_AND_ITS_CHILDREN);
scene.addChild(layerWidget);
pane.setViewportView(scene.createView());
add(pane, BorderLayout.CENTER);
}
Also, make sure the TopComponent above includes this so that focus is on the Scene when the TopComponent is activated:
@Overridepublic void componentActivated() {
scene.getView().requestFocusInWindow();
}
For extra usability, you could include the above Action together with the default MoveAction:
getActions().addAction(ActionFactory.createMoveAction());getActions().addAction(new KeyboardMoveAction());
Now your user can move widgets via the mouse as well as the keyboard. Maybe the keyboard would be used for finetuning the larger movements made by the mouse.