Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How allow contex menu on html elements in JavaFX

I have an application in JavaFX where I use a WebView to display a particular web page.

I need that the right mouse button on the page doesn't work; but if I use it on HTML elements that have id=eventDiv, it is supposed to work on them. It's JavaFX 17.

I set ContexMenuEnabled false and I don't have context menu and that's OK.

WebView webView = new WebView();
webView.setContextMenuEnabled(false);
webView.getEngine().setJavaScriptEnabled(true);
WebEngine webEngine = webView.getEngine();
webEngine.setUserStyleSheetLocation("data:, body { background-color: #EBEBEB; }");
webEngine.setOnAlert(event -> showAlert(event.getData()));
webEngine.setConfirmHandler(message -> showConfirm(message));
System.out.println(url);
webEngine.load(url);

I did something like this using AI and documentation, but unfortunately it doesn't work. And I would like that when I right-click on a given HTML element, which in this case is a div in a table cell, it opens a custom context menu, which is done in JS. What can I do to make it work?

webView.setOnMousePressed(event -> {
    if (event.isSecondaryButtonDown()) {
        event.consume();
    }
});

webView.getEngine()
       .getLoadWorker()
       .stateProperty()
       .addListener((observable, oldValue, newValue) -> {
                if (newValue == Worker.State.SUCCEEDED) {
                    JSObject window = (JSObject) webView.getEngine().executeScript("window");
                    window.setMember("eventDiv", new EventDivHandler());
                }
            });

public class EventDivHandler {
    public void handleEventDivClick() {
        // Obsłuż PPM na elemencie z id=eventDiv
        System.out.println("Kliknięto na element z id=eventDiv");
    }
}
like image 312
mksiaz Avatar asked Oct 29 '25 10:10

mksiaz


1 Answers

From some testing, calling setContextMenuEnabled(false) appears to disable all context menu handling. Even JavaScript listeners no longer receive contextmenu events. I think the better way to disable the context menu used by WebView is via JavaScript:

window.oncontextmenu = e => e.preventDefault();

You can then add your own contextmenu event listeners to whichever elements you want to handle specially. These listeners would invoke the Java callback object.

For example:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;

public class Main extends Application {

  public static void main(String[] args) {
    launch(Main.class, args);
  }

  // Keep a strong reference to the listener
  private final ContextMenuListener listener = new ContextMenuListener();

  @Override
  public void start(Stage primaryStage) {
    var view = new WebView();
    var engine = view.getEngine();
    var worker = engine.getLoadWorker();

    // Disable context menu when loading page to prevent user from
    // being able to show it before the script is executed.
    view.contextMenuEnabledProperty().bind(worker.runningProperty().not());

    // Run script when page is successfully loaded. There may be a way
    // to do this earlier, not sure.
    worker.stateProperty().addListener((obs, oldState, newState) -> {
      switch (newState) {
        default -> {}
        case FAILED -> worker.getException().printStackTrace();
        case SUCCEEDED -> installContextMenuListener(engine);
      }
    });

    // Load HTML content (insert your own URL)
    engine.load("<SOME URL>");

    primaryStage.setScene(new Scene(view, 500, 300));
    primaryStage.show();
  }

  private void installContextMenuListener(WebEngine engine) {
    var window = (JSObject) engine.executeScript("window");
    window.setMember("ctxMenuListener", listener);
    engine.executeScript(
      """
      window.oncontextmenu = e => e.preventDefault();

      let eventDiv = document.querySelector("#eventDiv");
      eventDiv.oncontextmenu = e => {
        e.preventDefault();
        ctxMenuListener.handle(eventDiv, e.screenX, e.screenY);
      };
      """);
  }

  public static class ContextMenuListener {

    public void handle(JSObject source, double screenX, double screenY) {
      System.out.printf("contextmenu(%s, %.2f, %.2f)%n", source, screenX, screenY);
    }
  }
}
like image 137
Slaw Avatar answered Nov 01 '25 01:11

Slaw



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!