首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >上下文菜单中的第一个选项被高亮显示,而无需将鼠标悬停在javafx 9中。

上下文菜单中的第一个选项被高亮显示,而无需将鼠标悬停在javafx 9中。
EN

Stack Overflow用户
提问于 2019-07-15 05:48:23
回答 1查看 694关注 0票数 8

当我们右键单击上下文菜单时,列表中的第一个选项将被高亮显示,而无需悬停鼠标。这仅在打开应用程序后的第一次右键单击时才发生。这种行为是从javafx-9中观察到的。直到javafx-8还能正常工作。

尝试使用示例代码:

代码语言:javascript
复制
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.TilePane;
import javafx.stage.Stage;

public class SampleContextMenu extends Application {
    // labels
    Label l;

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

    // launch the application
    public void start(Stage stage) {
        // set title for the stage
        stage.setTitle("creating contextMenu ");

        // create a label
        Label label1 = new Label("This is a ContextMenu example ");

        // create a menu
        ContextMenu contextMenu = new ContextMenu();

        // create menuitems
        MenuItem menuItem1 = new MenuItem("menu item 1");
        MenuItem menuItem2 = new MenuItem("menu item 2");
        MenuItem menuItem3 = new MenuItem("menu item 3");

        // add menu items to menu
        contextMenu.getItems().add(menuItem1);
        contextMenu.getItems().add(menuItem2);
        contextMenu.getItems().add(menuItem3);

        // create a tilepane
        TilePane tilePane = new TilePane(label1);

        // setContextMenu to label
        label1.setContextMenu(contextMenu);

        // create a scene
        Scene sc = new Scene(tilePane, 200, 200);

        // set the scene
        stage.setScene(sc);

        stage.show();
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-07-18 14:21:18

经过一番研究,发现罪魁祸首(可以这么说)是最初显示场景的默认焦点遍历--即聚焦第一个可聚焦的节点,在contextMenu的情况下,第一个焦点遍历是第一个项目。

首先尝试黑客的:当项目聚焦时,请求焦点返回到场景的根上。步骤:

  • 在onShown上注册contextMenu处理程序
  • 在处理程序中,获取包含contextMenu的场景:此时,它的focusOwner仍然是空的,因此我们需要在其focusOwner属性上注册一个changeListener。
  • 在侦听器中,在focusOwner的第一次更改(旧值为null)中,请求将焦点放在根上,并清除侦听器

注意:这还不够好,结果只是一次化妆品黑客攻击,如评论中所指出的,有几个小问题。

  • 请求焦点到场景根目录将禁用键盘导航
  • 第一项仍处于活动状态:按enter将激活其操作。

下一步尝试(现在变得非常脏,需要访问非公共类的隐藏实现细节!):将第一次尝试的最后一步替换为

  • 获取包含的ContextMenuContent (com.sun.xx中的内部类),它是焦点项的祖父母
  • 请求关注该内容,以使高亮显示消失。
  • 更新该内容以注意不以项目为重点的内容(对私有字段的反射访问)

代码:

代码语言:javascript
复制
contextMenu.setOnShown(e -> {
    Scene scene = contextMenu.getScene();
    scene.focusOwnerProperty().addListener((src, ov, nv) -> {
        // focusOwner set after first showing
        if (ov == null) {
            // transfer focus to root
            // old hack (see the beware section) on why it doesn't work
            //  scene.getRoot().requestFocus();

            // next try: 
            // grab the containing ContextMenuContainer and force the internal
            // book-keeping into no-item-focused state
            Parent parent = nv.getParent().getParent();
            parent.requestFocus();
            // reflective setting of private field, this is my utility method, use your own ;)
            invokeSetFieldValue(ContextMenuContent.class, parent, "currentFocusedIndex", -1);
            // cleanup
            contextMenu.setOnShown(null);

         }
    });
});

为了方便起见,这里提供了内部字段反射访问的实用方法(没有火箭接线器,只有普通java ;)

代码语言:javascript
复制
public static void invokeSetFieldValue(Class<?> declaringClass, Object target, String name, Object value) {
    try {
        Field field = declaringClass.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target, value);
    } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
        Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e);
    }
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57033827

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档