Как я могу получить контекстное меню из веб-просмотра в Java FX?

Я хотел бы получить элементы контекстного меню по умолчанию из объекта javafx.scene.web.WebView. Затем я хочу программно запустить пункт меню, например:

table.getContextMenu().getItems().get(0).fire();

Это возможно ?

Ты, наверное, не сможешь. (Кроме того, по крайней мере, когда я создаю WebView, содержимое контекстного меню изменяется в зависимости от того, где в WebView оно вызвано.)

VGR 20.09.2018 17:38

Собственно все, что я хочу, чтобы активировать пункт меню «Открыть фрейм в новом окне». Я знаю, что этот пункт меню появляется при щелчке правой кнопкой мыши по определенному месту в веб-просмотре. Есть ли другой способ сделать это?

Aniki 21.09.2018 08:17
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
2
274
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это XY проблема. На ваш комментарий:

Actually all I want to fire the "Open Frame in New Window" menu item.

Таким образом, вам вообще не нужно получать доступ к контекстному меню WebView, вы просто хотите открыть фрейм из документа в новом окне.

WebEngine WebView всегда хранит документ HTML как объект XML Документ. Когда WebEngine завершит загрузку документа, вы можете:

  • поиск кадров с помощью XPath
  • проверить атрибут src каждого элемента кадра
  • решать значение атрибута src по отношению к URI исходного документа HTML.
  • создать новый WebView и загрузить в него новый разрешенный URI

Во-первых, вы должны дождаться, пока WebEngine закончит загрузку документа. Перед загрузкой страницы необходимо добавить слушателя:

    WebEngine engine = webView.getEngine();
    engine.getLoadWorker().stateProperty().addListener(
        (o, old, state) -> updateFrameList(state));
    engine.load(url);

// ...

private void updateFrameList(Worker.State loadState) {
    if (loadState == Worker.State.SUCCEEDED) {
        Document doc = webView.getEngine().getDocument();

Когда у вас есть полностью загруженный документ, вы можете использовать пакет javax.xml.xpath для поиска фреймов:

NodeList frames;
try {
    XPath xpath = XPathFactory.newInstance().newXPath();
    frames = (NodeList) xpath.evaluate("//*" +
        "[local-name() = 'frame'" +
        " or local-name() = 'FRAME'" + 
        " or local-name() = 'iframe'" + 
        " or local-name() = 'IFRAME']" + 
        "[@src]", doc, XPathConstants.NODESET);
} catch (XPathException e) {
    throw new RuntimeException(e);
}

Поскольку выражение XPath начинается с //*, оно соответствует только элементам, поэтому можно безопасно преобразовать каждый результат в DOM Элемент, чтобы проверить его назначение:

URI docURI = URI.create(webView.getEngine().getLocation());

int count = frames.getLength();
for (int i = 0; i < count; i++) {
    Element frame = (Element) frames.item(i);
    URI frameLocation = docURI.resolve(frame.getAttribute("src"));
    // Show frameLocation in new window...
}

Самая простая часть - показать содержимое фрейма:

WebView frameView = new WebView();
frameView.getEngine().load(frameLocation.toString());

Stage stage = new Stage();
stage.setTitle("Frame content");
stage.setScene(new Scene(new BorderPane(frameView)));
stage.show();

Вот программа, которая объединяет все это:

import java.net.URI;
import java.util.Collection;
import java.util.Objects;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import javax.xml.xpath.XPathException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import javafx.application.Application;
import javafx.concurrent.Worker;
import javafx.geometry.Insets;
import javafx.geometry.Pos;

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;

public class FrameOpener
extends Application {
    private static class FrameInfo {
        final String name;
        final String uri;

        FrameInfo(String name,
                  String uri) {

            this.name = name;
            this.uri = uri;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof FrameInfo) {
                FrameInfo other = (FrameInfo) obj;
                return Objects.equals(this.name, other.name) &&
                       Objects.equals(this.uri, other.uri);
            }
            return false;
        }

        @Override
        public int hashCode() {
            return Objects.hash(name, uri);
        }

        @Override
        public String toString() {
            return name;
        }
    }

    private ComboBox<FrameInfo> frameList;
    private WebView webView;

    @Override
    public void start(Stage stage) {
        String url;
        Collection<String> params = getParameters().getRaw();
        if (params.isEmpty()) {
            url = "https://docs.oracle.com/javase/10/docs/api/index.html" +
                "?overview-summary.html";
        } else {
            url = params.iterator().next();
        }

        frameList = new ComboBox<>();

        Label label = new Label("_Frame:");
        label.setMnemonicParsing(true);
        label.setLabelFor(frameList);

        Button showFrameButton = new Button("_Show frame");
        showFrameButton.setMnemonicParsing(true);
        showFrameButton.setOnAction(e -> showFrame());

        webView = new WebView();

        WebEngine engine = webView.getEngine();
        engine.getLoadWorker().stateProperty().addListener(
            (o, old, state) -> updateFrameList(state));
        engine.load(url);

        HBox framePane = new HBox(6, label, frameList, showFrameButton);
        framePane.setAlignment(Pos.BASELINE_CENTER);
        framePane.setFillHeight(true);
        framePane.setPadding(new Insets(12));

        Scene scene = new Scene(
            new BorderPane(webView, null, null, framePane, null));

        stage.setScene(scene);
        stage.setTitle("Frame Opener");
        stage.show();
    }

    private void updateFrameList(Worker.State loadState) {
        if (loadState == Worker.State.SUCCEEDED) {
            Document doc = webView.getEngine().getDocument();
            NodeList frames;
            try {
                XPath xpath = XPathFactory.newInstance().newXPath();
                frames = (NodeList) xpath.evaluate("//*" +
                    "[local-name() = 'frame'" +
                    " or local-name() = 'FRAME'" + 
                    " or local-name() = 'iframe'" + 
                    " or local-name() = 'IFRAME']" + 
                    "[@src]", doc, XPathConstants.NODESET);
            } catch (XPathException e) {
                throw new RuntimeException(e);
            }

            URI docURI = URI.create(webView.getEngine().getLocation());

            int count = frames.getLength();
            FrameInfo[] newFrameInfo = new FrameInfo[count];
            for (int i = 0; i < count; i++) {
                Element frame = (Element) frames.item(i);
                URI frameLocation = docURI.resolve(frame.getAttribute("src"));
                newFrameInfo[i] = new FrameInfo(
                    frame.getAttribute("name"), frameLocation.toString());
            }

            frameList.getItems().setAll(newFrameInfo);
            if (newFrameInfo.length > 0) {
                frameList.setValue(newFrameInfo[0]);
            }
        }
    }

    private void showFrame() {
        FrameInfo info = frameList.getValue();

        WebView frameView = new WebView();
        frameView.getEngine().load(info.uri);

        Stage stage = new Stage();
        stage.setTitle(info.name);
        stage.setScene(new Scene(new BorderPane(frameView)));
        stage.show();
    }
}

Другие вопросы по теме