代码之家  ›  专栏  ›  技术社区  ›  user3810626

标签窗格快捷方式

  •  0
  • user3810626  · 技术社区  · 3 年前

    我试图创建一个笔记本(在JavaFX中),其中的标签页有快捷键,就像按钮一样。所以,在下面的例子中,有一个带有“人工”、“零件”和“税务”的笔记本。

    enter image description here

    当然,用户可以单击选项卡,但他们也可以单击Alt+L、Alt+P、Alt+T分别选择人工、零件和税务窗格。

    查看文档,标准快捷方式行为似乎来自 Labeled 类,Tab不会从中派生。如何将此行为添加到选项卡式窗格选项卡中?

    编辑:更具体地说,我正在寻找与现有行为和控制代码相匹配的视觉效果,而不需要控制代码知道热键是什么。

    因此,与按钮一样,用户按下元键(CTRL、ALT、OPT等),相应的字符会加下划线,当他们按下该键时,家长可能必须搜索选项卡的文本才能知道要选择哪个。

    0 回复  |  直到 3 年前
        1
  •  4
  •   Zephyr    3 年前

    你只需要注册自己的 EventFilter Scene 。这将允许您收听所需的键盘组合并做出相应反应。

    在下面的示例应用程序中,您将传递所需的 Tab KeyCombination 涉及一种处理注册的方法 事件筛选器 .

    在这个例子中,我配置了以下快捷方式 CTRL+1 , CTRL+2 ,以及 CTRL+3 选择 选项卡 分别为1、2或3。

    请注意,您也可以使用 KeyCombination.CONTROL_DOWN 而不是 KeyCombination.SHORTCUT_DOWN ,但使用 SHORTCUT_DOWN 因为它是独立于平台的。

    import javafx.application.Application;
    import javafx.geometry.Insets;
    import javafx.geometry.Pos;
    import javafx.scene.Scene;
    import javafx.scene.control.Tab;
    import javafx.scene.control.TabPane;
    import javafx.scene.input.KeyCode;
    import javafx.scene.input.KeyCodeCombination;
    import javafx.scene.input.KeyCombination;
    import javafx.scene.input.KeyEvent;
    import javafx.scene.layout.VBox;
    import javafx.stage.Stage;
    
    public class TabPaneShortcuts extends Application {
    
        public static void main(String[] args) {
    
            launch(args);
        }
    
        @Override
        public void start(Stage primaryStage) {
    
            // **********************************************************************************************
            // Create a basic layout
            // **********************************************************************************************
            VBox root = new VBox(5);
            root.setAlignment(Pos.TOP_CENTER);
            root.setPadding(new Insets(10));
    
            // **********************************************************************************************
            // Create a TabPane
            // **********************************************************************************************
            TabPane tabPane = new TabPane();
    
            // **********************************************************************************************
            // Create the Tabs
            // **********************************************************************************************
            Tab tab1 = new Tab("Labor");
            Tab tab2 = new Tab("Parts");
            Tab tab3 = new Tab("Tax");
            tabPane.getTabs().addAll(tab1, tab2, tab3);
    
            // **********************************************************************************************
            // Add the TabPane to our root layout
            // **********************************************************************************************
            root.getChildren().add(tabPane);
    
            // **********************************************************************************************
            // Set the Scene for the stage
            // **********************************************************************************************
            Scene scene = new Scene(root);
            primaryStage.setScene(scene);
    
            // **********************************************************************************************
            // Register keyboard shortcuts to select Tabs with the keyboard. Here, we create the KeyCodeCombination
            // to listen for CTRL + 1,2, or 3.
            // **********************************************************************************************
            registerShortcut(tabPane, tab1, scene,
                             new KeyCodeCombination(KeyCode.DIGIT1,
                                                    KeyCombination.SHORTCUT_DOWN));
            registerShortcut(tabPane, tab2, scene,
                             new KeyCodeCombination(KeyCode.DIGIT2,
                                                    KeyCombination.SHORTCUT_DOWN));
            registerShortcut(tabPane, tab3, scene,
                             new KeyCodeCombination(KeyCode.DIGIT3,
                                                    KeyCombination.SHORTCUT_DOWN));
    
            // **********************************************************************************************
            // Configure the Stage
            // **********************************************************************************************
            primaryStage.setWidth(300);
            primaryStage.setHeight(200);
            primaryStage.setTitle("Test Application");
            primaryStage.show();
        }
    
        /**
         * Registers the given KeyCombination to automatically select the given Tab of the TabPane
         *
         * @param tabPane     The TabPane whose selection model we need to manipulate
         * @param tab         The Tab to be selected when the given KeyCombination is detected
         * @param scene       The main Scene on which to register this EventFilter
         * @param combination The KeyCombination to listen for
         */
        private void registerShortcut(TabPane tabPane, Tab tab, Scene scene, KeyCombination combination) {
    
            // **********************************************************************************************
            // Add an EventFilter to the Scene to listen for the given KeyCombination
            // **********************************************************************************************
            scene.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
                // **********************************************************************************************
                // If the event matches the KeyCombination passed to this method, select the desired Tab
                // **********************************************************************************************
                if (combination.match(event)) {
                    tabPane.getSelectionModel().select(tab);
                }
            });
    
        }
    }
    

    您的问题特别提到使用 ALT+[letter] 对于组合,这也可以很容易地完成:

    registerShortcut(tabPane, tab1, scene,
                     new KeyCodeCombination(KeyCode.L,
                                            KeyCombination.ALT_DOWN));
    

    我选择了一起去 CTRL 仅仅因为使用 ALT 导致我的Windows 10系统每次都“叮”,我懒得弄清楚原因。:)

        2
  •  3
  •   kleopatra Aji kattacherry    3 年前

    不幸的是(让我有点惊讶的是),Tabs上的助记符没有得到直接支持。按照建议注册事件过滤器 in another answer 这是一条出路。另一种方法是使用现有的助记符支持。

    做类似的事情:

    Label label = new Label("_MyLabel");
    label.setMnemonicParsing(true);
    label.setLabelFor(otherControl);
    

    当系统检测到组合键作为助记符时(这基本上取决于操作系统),将聚焦otherControl。

    试图将其应用于Tabs会立即遇到问题:

    • 无法直接访问显示选项卡标题的标签
    • 隐藏节点(如未选中选项卡的内容)将不会获得焦点

    深入探究内部,发现了一些有趣的合作者:

    • 有一个类Mnemonic,它使用一个方法处理一对组合键和节点 fire(ActionEvent)
    • 场景有方法 addMnemonic(Mnemonic) :在检测到给定助记符的组合键时,它会在其节点上触发一个动作事件
    • LabeledSkinBase通过在其场景中注册助记符来管理其标签的助记符解析:通常,它是labelFor/keyCombination对,但有趣的是,回退(即labelFor为空时)对是label/keyCombination

    结合所有这些,我们可以使用该机制通过助记符触发任意操作:

    Label label = new Label("_MyLabel");
    label.setMnemonicParsing(true);
    label.addEventHandler(ActionEvent.ACTION, ac -> {
        // do stuff
    });
    

    当将这种方法应用于TabPane时,标签将位于Tab的标题中,doStuff将选择它所在的Tab。由于我们仍然无法直接访问由皮肤创建的标签,我们可以配置一个仅包含图形的Tab,图形是如上所述的标签:

    Tab tab = new Tab();
    tab.setGraphic(label);
    // do stuff: tab.getTabPane().getSelectionModel().select(tab);
    

    另一种选择是查找皮肤创建的标签,并以相同的方式配置这些标签,例如:

    // building the tabs/tabPane as usual
    Tab tab = new Tab("_MyTabText");
    
    // .. after skin has been created
    Set<Node> labels = tabPane.lookupAll(".tab-label");    
    labels.forEach(e -> {
        if (e instanceof Label) {
            Label label = (Label) e;
            // beware: internal hierarchy!
            Parent innerContainer = label.getParent();
            Parent tabHeaderSkin = innerContainer.getParent();
            // beware: implementation detail
            Tab tab = (Tab) tabHeaderSkin.getProperties().get(Tab.class);
            
            label.setMnemonicParsing(true);
            label.addEventHandler(ActionEvent.ACTION, c -> {
                tabPane.getSelectionModel().select(tab);
            });
    
        }
    });
    

    两者都有用,但都有缺点

    • 第一个旁路选项卡的文本属性,如果需要文本和图形,则需要额外的努力
    • 第二个依赖于皮肤的实现细节,在不显示记忆下划线方面存在视觉问题(不知道为什么不显示)

    两者都有好的一面:客户端代码中没有操作系统的具体细节。