Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
231 views
in Technique[技术] by (71.8m points)

java - Pass Context menu shortcuts up from editing control

I have a JavaFX pane (TabPane, if it matters) with a context menu associated with it. The context menu has a few shortcut keys (F2, F3) defined in it, and indeed when they are pressed the correct action is performed. However, when inside a TextField or ComboBox the shortcut keys are completely ignored.

Why is this happening, and how can I overcome this? If possible, I would like to avoid setting "onKeyPressed" for every single control.

(Edit: Apparently it is the TabPane that has the ContextMenu. For some reason which I can't fathom normal Panes can't have context menus, but TabPane is a Control. Don't know if it changes anything)

Edit: Provided is a minimal example:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Example extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {

        VBox vbox = new VBox();
        vbox.getChildren().add(new TextField());

        TabPane tp = new TabPane();
        Tab t = new Tab("foo");
        t.setContent(vbox);

        tp.getTabs().add(t);

        ContextMenu cm = new ContextMenu();
        MenuItem mi = new MenuItem("Action");
        mi.setAccelerator(KeyCombination.keyCombination("F2"));
        mi.setOnAction(ev->{ System.out.println("Action!"); });
        cm.getItems().add(mi);

        tp.setContextMenu(cm);
        Scene sc = new Scene(tp);

        stage.setScene(sc);

        stage.show();
    }
}

Note that pressing F2 while inside the TextField does nothing, while pressing it while not inside it prints out "Action!"

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I have found this roundabout solution to the problem: Add an EventFilter on the TabPane - this fires even when an editing control has focus:

tabPane.addEventFilter(KeyEvent.KEY_PRESSED, this::keyPressed);

Use this as your keyPressed function:

private void keyPressed(KeyEvent event) {
  for (MenuItem mi : tabPane.getContextMenu().getItems())
     {
        if (mi.getAccelerator()!=null && mi.getAccelerator().match(event))
        {
            mi.getOnAction().handle(null);
            event.consume();
            return;
        }
    }
}

It is important to consume the event, so in case no editing control is selected it won't get fired twice. This obviously won't work if you have nested menus, but in my case it is a flat context menu.

If there is anything horribly wrong with this solution, or a more straightforward way to solve this problem - please let me know!

Edit: It may be desirable to add !mi.isDisable() to the firing condition, to avoid firing events for disabled menu items.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...