WebView何时准备好快照()?

问题描述 投票:3回答:2

JavaFX docs指出WebView is ready when Worker.State.SUCCEEDED is reached,除非您稍等片刻(即WebViewWorker.State.SUCCEEDEDAnimation等),否则将呈现空白页。

这表明在WebView内部发生了一个事件,准备将其捕获,但这是什么?

Transition,但其中大多数似乎与PauseTransition无关,是交互式的(人类遮住了种族条件)或使用了任意的Transitions(从100ms到2,000ms的任何位置。)>

我尝试过:

  • over 7,000 code snippets on GitHub which use SwingFXUtils.fromFXImage的尺寸内监听SwingFXUtils.fromFXImage(高度和宽度属性WebView实现了changed(...),可以监视这些东西)]

    • 🚫不可行。有时,该值似乎与绘制例程分开更改,从而导致部分内容。
  • 盲目告诉FX应用程序线程上的changed(...)所有信息。

    • 🚫许多技术都使用此功能,但是我自己的单元测试(以及其他开发人员的一些宝贵反馈)解释说,事件通常已经在正确的线程上,并且此调用是多余的。我能想到的最好的办法就是通过排队,对某些人起作用而增加了足够的延迟。
  • 将DOM侦听器/触发器或JavaScript侦听器/触发器添加到WebView

    • 🚫尽管捕获为空白,但在调用DoubleProperty时,JavaScript和DOM似乎都已正确加载。 DOM / JavaScript侦听器似乎无济于事。
  • 使用ObservableValuerunLater(...)有效地“休眠”而不阻塞主FX线程。

    • ⚠️这种方法有效,如果延迟足够长,则可以产生高达100%的单元测试,但是过渡时间似乎是runLater(...),而且设计不好。对于高性能或关键任务应用程序,这迫使程序员在速度或可靠性之间做出权衡,这两者对于用户而言都是潜在的不良体验。

    什么时候打电话给WebView

用法:

SUCCEEDED

代码段:

Animation

相关:

  • Transition
  • some future moment that we're just guessing
  • WebView.snapshot(...)
  • SnapshotRaceCondition.initialize(); BufferedImage bufferedImage = SnapshotRaceCondition.capture("<html style='background-color: red;'><h1>TEST</h1></html>"); /** * Notes: * - The color is to observe the otherwise non-obvious cropping that occurs * with some techniques, such as `setPrefWidth`, `autosize`, etc. * - Call this function in a loop and then display/write `BufferedImage` to * to see strange behavior on subsequent calls. * - Recommended, modify `<h1>TEST</h1` with a counter to see content from * previous captures render much later. */
  • import javafx.application.Application; import javafx.application.Platform; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.concurrent.Worker; import javafx.embed.swing.SwingFXUtils; import javafx.scene.Scene; import javafx.scene.SnapshotParameters; import javafx.scene.image.WritableImage; import javafx.scene.web.WebView; import javafx.stage.Stage; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Logger; public class SnapshotRaceCondition extends Application { private static final Logger log = Logger.getLogger(SnapshotRaceCondition.class.getName()); // self reference private static SnapshotRaceCondition instance = null; // concurrent-safe containers for flags/exceptions/image data private static AtomicBoolean started = new AtomicBoolean(false); private static AtomicBoolean finished = new AtomicBoolean(true); private static AtomicReference<Throwable> thrown = new AtomicReference<>(null); private static AtomicReference<BufferedImage> capture = new AtomicReference<>(null); // main javafx objects private static WebView webView = null; private static Stage stage = null; // frequency for checking fx is started private static final int STARTUP_TIMEOUT= 10; // seconds private static final int STARTUP_SLEEP_INTERVAL = 250; // millis // frequency for checking capture has occured private static final int CAPTURE_SLEEP_INTERVAL = 10; // millis /** Called by JavaFX thread */ public SnapshotRaceCondition() { instance = this; } /** Starts JavaFX thread if not already running */ public static synchronized void initialize() throws IOException { if (instance == null) { new Thread(() -> Application.launch(SnapshotRaceCondition.class)).start(); } for(int i = 0; i < (STARTUP_TIMEOUT * 1000); i += STARTUP_SLEEP_INTERVAL) { if (started.get()) { break; } log.fine("Waiting for JavaFX..."); try { Thread.sleep(STARTUP_SLEEP_INTERVAL); } catch(Exception ignore) {} } if (!started.get()) { throw new IOException("JavaFX did not start"); } } @Override public void start(Stage primaryStage) { started.set(true); log.fine("Started JavaFX, creating WebView..."); stage = primaryStage; primaryStage.setScene(new Scene(webView = new WebView())); // Add listener for SUCCEEDED Worker<Void> worker = webView.getEngine().getLoadWorker(); worker.stateProperty().addListener(stateListener); // Prevents JavaFX from shutting down when hiding window, useful for calling capture(...) in succession Platform.setImplicitExit(false); } /** Listens for a SUCCEEDED state to activate image capture **/ private static ChangeListener<Worker.State> stateListener = (ov, oldState, newState) -> { if (newState == Worker.State.SUCCEEDED) { WritableImage snapshot = webView.snapshot(new SnapshotParameters(), null); capture.set(SwingFXUtils.fromFXImage(snapshot, null)); finished.set(true); stage.hide(); } }; /** Listen for failures **/ private static ChangeListener<Throwable> exceptListener = new ChangeListener<Throwable>() { @Override public void changed(ObservableValue<? extends Throwable> obs, Throwable oldExc, Throwable newExc) { if (newExc != null) { thrown.set(newExc); } } }; /** Loads the specified HTML, triggering stateListener above **/ public static synchronized BufferedImage capture(final String html) throws Throwable { capture.set(null); thrown.set(null); finished.set(false); // run these actions on the JavaFX thread Platform.runLater(new Thread(() -> { try { webView.getEngine().loadContent(html, "text/html"); stage.show(); // JDK-8087569: will not capture without showing stage stage.toBack(); } catch(Throwable t) { thrown.set(t); } })); // wait for capture to complete by monitoring our own finished flag while(!finished.get() && thrown.get() == null) { log.fine("Waiting on capture..."); try { Thread.sleep(CAPTURE_SLEEP_INTERVAL); } catch(InterruptedException e) { log.warning(e.getLocalizedMessage()); } } if (thrown.get() != null) { throw thrown.get(); } return capture.get(); } }
  • Screenshot of the full web page loaded into JavaFX WebView component, not only visible part
  • Can I capture snapshot of scene programmatically?
  • Whole page screenshot, Java
  • JavaFX 2.0+ WebView /WebEngine render web page to an image
  • Set Height and Width of Stage and Scene in javafx

JavaFX文档指出,当到达Worker.State.SUCCEEDED时,WebView就绪,除非您等待一会儿(即,Animation,Transition,PauseTransition等),否则将呈现空白页面。 ...

java multithreading javafx race-condition p
2个回答
0
投票

我之前没有见过的建议是监听JavaFX脉冲以确定是否绘制了JavaFX:how to resize the stage when using webview


0
投票

似乎是使用WebEngine的WebView方法时发生的错误。使用com.sun加载本地文件时也会发生这种情况,但是在这种情况下,调用PauseTransition将对此进行补偿。

© www.soinside.com 2019 - 2024. All rights reserved.