简体   繁体   English

javafx webview / webengine上的自定义上下文菜单

[英]Customized context menu on javafx webview/webengine

How may I have a customized context menu for whole entry of the document in WebEngine javafx? 如何在WebEngine javafx中为文档的整个条目提供自定义上下文菜单?
Something like this 像这样的东西

+------------+
|Reload      |
|Save page   |
|Hide Images |
+------------+

I like to invoke and show this context popup for whole document entry(same for every node). 我喜欢调用并显示整个文档条目的上下文弹出窗口(每个节点都相同)。 Thanks. 谢谢。

I don't see a way to interact with the default context menu. 我没有看到与默认上下文菜单交互的方法。 However, it's not hard to disable it and implement your own. 但是,禁用它并实现自己的并不困难。

Disable the default context menu with 使用默认上下文菜单禁用

webView.setContextMenuEnabled();

Then create your own context menu, and register a mouse listener with the web view to show it on right click: 然后创建自己的上下文菜单,并使用Web视图注册鼠标侦听器以在右键单击时显示它:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.BorderPane;
import javafx.scene.web.WebView;
import javafx.stage.Stage;


public class WebViewContextMenuTest extends Application {

    private final String START_URL = 
            "http://stackoverflow.com/questions/27047447/customized-context-menu-on-javafx-webview-webengine/27047830#27047830";

    @Override
    public void start(Stage primaryStage) {
        TextField locationField = new TextField(START_URL);
        WebView webView = new WebView();
        webView.getEngine().load(START_URL);

        webView.setContextMenuEnabled(false);
        createContextMenu(webView);

        locationField.setOnAction(e -> {
            webView.getEngine().load(getUrl(locationField.getText()));
        });
        BorderPane root = new BorderPane(webView, locationField, null, null, null);
        primaryStage.setScene(new Scene(root, 800, 600));
        primaryStage.show();

    }

    private void createContextMenu(WebView webView) {
        ContextMenu contextMenu = new ContextMenu();
        MenuItem reload = new MenuItem("Reload");
        reload.setOnAction(e -> webView.getEngine().reload());
        MenuItem savePage = new MenuItem("Save Page");
        savePage.setOnAction(e -> System.out.println("Save page..."));
        MenuItem hideImages = new MenuItem("Hide Images");
        hideImages.setOnAction(e -> System.out.println("Hide Images..."));
        contextMenu.getItems().addAll(reload, savePage, hideImages);

        webView.setOnMousePressed(e -> {
            if (e.getButton() == MouseButton.SECONDARY) {
                contextMenu.show(webView, e.getScreenX(), e.getScreenY());
            } else {
                contextMenu.hide();
            }
        });
    }

    private String getUrl(String text) {
        if (text.indexOf("://")==-1) {
            return "http://" + text ;
        } else {
            return text ;
        }
    }

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

There's no easy solution for this, since there's no public API, and a request is still unresolved. 对此没有简单的解决方案,因为没有公共API,并且请求仍未解决。

The hacky solution uses some private API, so it's not very advisable since it could change without notice. hacky解决方案使用了一些私有API,所以它不太合适,因为它可能会在没有通知的情况下发生变化。

The ContextMenu shown when the user right clicks on the web page is in another window, so using some lookups we'll try to find it, then access to its content and then modify existing or add more MenuItem s. 当用户右键单击网页时显示的ContextMenu在另一个窗口中,因此使用一些查找我们将尝试找到它,然后访问其内容然后修改现有或添加更多MenuItem

These are the private classes required: 这些是所需的私人课程:

import com.sun.javafx.scene.control.skin.ContextMenuContent;
import com.sun.javafx.scene.control.skin.ContextMenuContent.MenuItemContainer;

In our application, we listen for a context menu request: 在我们的应用程序中,我们监听上下文菜单请求:

@Override
public void start(Stage primaryStage) {
    WebView webView = new WebView();
    WebEngine webEngine = webView.getEngine();
    Scene scene = new Scene(webView);

    primaryStage.setScene(scene);
    primaryStage.show();

    webView.setOnContextMenuRequested(new EventHandler<ContextMenuEvent>() {

        @Override
        public void handle(ContextMenuEvent e) {
            getPopupWindow();
        }
    });

}

where getPopupWindow() will: getPopupWindow()将在哪里:

  • Look for the new window being instance of ContextMenu 寻找新窗口作为ContextMenu实例
  • With lookup find the CSS selector context-menu . 使用lookup查找CSS选择器context-menu This is a node having as its only child a ContextMenuContent instance. 这是一个节点,它的唯一子节点是ContextMenuContent实例。
  • This object has an VBox as a container for all the items, which are MenuItem in an special container, MenuItemContainer . 这个对象有一个VBox为所有的项目,这是一个容器MenuItem中的一个特殊的容器, MenuItemContainer
  • We can access to any of the existing items, like reload page, go back, ... and customize them, modifying its text or adding a graphic. 我们可以访问任何现有项目,例如重新加载页面,返回,...并自定义它们,修改其文本或添加图形。
  • We can add our custom items to this box, providing our own actions. 我们可以将自定义项添加到此框中,提供我们自己的操作。

Customize the items as you need to: 根据需要自定义项目:

private PopupWindow getPopupWindow() {
    @SuppressWarnings("deprecation") 
    final Iterator<Window> windows = Window.impl_getWindows();

    while (windows.hasNext()) {
        final Window window = windows.next();

        if (window instanceof ContextMenu) {
            if(window.getScene()!=null && window.getScene().getRoot()!=null){ 
                Parent root = window.getScene().getRoot();

                // access to context menu content
                if(root.getChildrenUnmodifiable().size()>0){
                    Node popup = root.getChildrenUnmodifiable().get(0);
                    if(popup.lookup(".context-menu")!=null){
                        Node bridge = popup.lookup(".context-menu");
                        ContextMenuContent cmc= (ContextMenuContent)((Parent)bridge).getChildrenUnmodifiable().get(0);

                        VBox itemsContainer = cmc.getItemsContainer();
                        for(Node n: itemsContainer.getChildren()){
                            MenuItemContainer item=(MenuItemContainer)n;
                            // customize text:
                            item.getItem().setText("My Custom: "+item.getItem().getText());
                            // customize graphic:
                            item.getItem().setGraphic(new ImageView(new Image(getClass().getResource("unlock24.png").toExternalForm())));
                        }
                        // remove some item:
                        // itemsContainer.getChildren().remove(0);

                        // adding new item:
                        MenuItem menuItem = new MenuItem("Save page");
                        menuItem.setOnAction(new EventHandler<ActionEvent>() {

                            @Override
                            public void handle(ActionEvent e) {
                                System.out.println("Save Page");
                            }
                        });
                        // add new item:
                        cmc.getItemsContainer().getChildren().add(cmc.new MenuItemContainer(menuItem));

                        return (PopupWindow)window;
                    }
                }
            }
            return null;
        }
    }
    return null;
}

This is how it looks like: 这是它的样子:

自定义ContextMenu

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM