【发布时间】:2015-01-18 18:39:48
【问题描述】:
如何为WebEngine javafx 中的整个文档条目提供自定义上下文菜单?
像这样的
+------------+
|Reload |
|Save page |
|Hide Images |
+------------+
我喜欢为整个文档条目调用并显示此上下文弹出窗口(每个节点都相同)。谢谢。
【问题讨论】:
如何为WebEngine javafx 中的整个文档条目提供自定义上下文菜单?
像这样的
+------------+
|Reload |
|Save page |
|Hide Images |
+------------+
我喜欢为整个文档条目调用并显示此上下文弹出窗口(每个节点都相同)。谢谢。
【问题讨论】:
没有简单的解决方案,因为没有公共 API,request 仍未解决。
hacky 解决方案使用了一些私有 API,因此不太可取,因为它可能会在没有通知的情况下更改。
当用户在网页上右击时显示的ContextMenu在另一个窗口中,所以我们会通过一些查找来尝试找到它,然后访问它的内容,然后修改现有的或添加更多MenuItems .
这些是所需的私有类:
import com.sun.javafx.scene.control.skin.ContextMenuContent;
import com.sun.javafx.scene.control.skin.ContextMenuContent.MenuItemContainer;
在我们的应用程序中,我们监听上下文菜单请求:
@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();
}
});
}
getPopupWindow() 将在哪里:
ContextMenu实例的新窗口
context-menu。这是一个以 ContextMenuContent 实例作为其唯一子节点的节点。VBox作为所有项目的容器,这些项目是MenuItem在一个特殊的容器MenuItemContainer中。根据需要自定义项目:
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;
}
看起来是这样的:
【讨论】:
我看不到与默认上下文菜单交互的方法。但是,禁用它并实现自己的并不难。
使用
禁用默认上下文菜单webView.setContextMenuEnabled();
然后创建您自己的上下文菜单,并在 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);
}
}
【讨论】: