弹出窗口

本页描述了如何处理、显示或抑制弹出窗口。

概述

任何网页都可以使用以下方式之一显示弹出窗口:

  1. 使用 window.open() 函数。 例如:

     window.open("https://www.google.com", "_blank", "resizable=yes,
         top=500, left=500, width=400, height=400");
    
  2. 通过与 target 属性的链接:

     <a href="https://www.google.com" target="_blank">Open Google</a>
    

默认情况下,所有弹出窗口都被抑制。

打开弹出窗口

为了更改默认行为并控制弹出窗口的创建,请使用CreatePopupCallbackOpenPopupCallback 回调。

当引擎想知道是否可以创建弹出窗口时,将调用 CreatePopupCallback 回调。 以下代码显示了如何允许创建弹出窗口:

browser.set(CreatePopupCallback.class, (params) -> Response.create());
browser.set(CreatePopupCallback::class.java, CreatePopupCallback { Response.create() })

如果 CreatePopupCallback 回调允许创建一个弹出窗口, OpenPopupCallback 回调将被调用。 在此回调中,您可以访问创建的弹出窗口并在必要时显示它。 例如:

browser.set(OpenPopupCallback.class, (params) -> {
    // Access the created popup.
    Browser popup = params.popupBrowser();
    return Response.proceed();
});
browser.set(OpenPopupCallback::class.java,  OpenPopupCallback { params -> 
    // Access the created popup.
    val popup = params.popupBrowser()
    Response.proceed()
})

上述示例中的 popup 实例在调用回调时没有加载任何网页。 该网页将在稍后加载。 此时您可以注册所有需要的事件监听器和回调,但是您不能访问 DOM 或 JavaScript,因为 popup 还没有 Frame

抑制弹出窗口

要抑制弹出窗口,请使用以下方法:

browser.set(CreatePopupCallback.class, params -> Response.suppress());
browser.set(CreatePopupCallback::class.java,  CreatePopupCallback { Response.suppress() })

显示弹出窗口

当您创建 Swing 或 JavaFX BrowserView 时,它会使用 CreatePopupCallbackOpenPopupCallback 回调的默认实现自动配置给定的 Browser 实例。

CreatePopupCallback 的默认实现允许创建所有弹出窗口:

browser.set(CreatePopupCallback.class, params -> Response.create());
browser.set(CreatePopupCallback::class.java,  CreatePopupCallback { Response.create() })

Swing 和 JavaFX 的 OpenPopupCallback 回调的默认实现如下所示。

Swing

Swing BrowserView 的默认实现如下:

import static javax.swing.SwingUtilities.invokeLater;

import com.teamdev.jxbrowser.browser.Browser;
import com.teamdev.jxbrowser.browser.callback.OpenPopupCallback;
import com.teamdev.jxbrowser.browser.event.BrowserClosed;
import com.teamdev.jxbrowser.browser.event.TitleChanged;
import com.teamdev.jxbrowser.browser.event.UpdateBoundsRequested;
import com.teamdev.jxbrowser.ui.Rect;
import com.teamdev.jxbrowser.ui.Size;
import com.teamdev.jxbrowser.view.swing.BrowserView;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;

/**
 * The default {@link OpenPopupCallback} implementation for the Swing UI toolkit
 * that creates and shows a new window with the embedded popup browser.
 */
public final class DefaultOpenPopupCallback implements OpenPopupCallback {

    private static final int DEFAULT_POPUP_WIDTH = 800;
    private static final int DEFAULT_POPUP_HEIGHT = 600;

    @Override
    public Response on(Params params) {
        Browser browser = params.popupBrowser();
        invokeLater(() -> {
            BrowserView view = BrowserView.newInstance(browser);
            JFrame frame = new JFrame();
            frame.add(view, BorderLayout.CENTER);
            frame.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    invokeLater(browser::close);
                }
            });

            updateBounds(frame, params.initialBounds());

            browser.on(TitleChanged.class, event -> invokeLater(() ->
                    frame.setTitle(event.title())
            ));
            browser.on(BrowserClosed.class, event -> invokeLater(() -> {
                frame.setVisible(false);
                frame.dispose();
            }));
            browser.on(UpdateBoundsRequested.class, event -> invokeLater(() ->
                    updateBounds(frame, event.bounds())
            ));

            frame.setVisible(true);
        });
        return Response.proceed();
    }

    private static void updateBounds(JFrame frame, Rect bounds) {
        if (bounds.size().isEmpty()) {
            frame.setLocationByPlatform(true);
            frame.setSize(DEFAULT_POPUP_WIDTH, DEFAULT_POPUP_HEIGHT);
        } else {
            frame.setLocation(toPoint(bounds.origin()));
            frame.getContentPane().setPreferredSize(toDimension(bounds.size()));
            frame.pack();
        }
    }

    private static Dimension toDimension(Size size) {
        return new Dimension(size.width(), size.height());
    }

    private static Point toPoint(com.teamdev.jxbrowser.ui.Point point) {
        return new Point(point.x(), point.y());
    }
}
import com.teamdev.jxbrowser.browser.callback.OpenPopupCallback
import com.teamdev.jxbrowser.browser.event.BrowserClosed
import com.teamdev.jxbrowser.browser.event.TitleChanged
import com.teamdev.jxbrowser.browser.event.UpdateBoundsRequested
import com.teamdev.jxbrowser.ui.Point
import com.teamdev.jxbrowser.ui.Rect
import com.teamdev.jxbrowser.ui.Size
import com.teamdev.jxbrowser.view.swing.BrowserView
import java.awt.BorderLayout
import java.awt.Dimension
import java.awt.event.WindowAdapter
import java.awt.event.WindowEvent
import javax.swing.JFrame
import javax.swing.SwingUtilities.invokeLater

/**
 * The default [OpenPopupCallback] implementation for the Swing UI toolkit
 * that creates and shows a new window with the embedded popup browser.
 */
class DefaultOpenPopupCallback : OpenPopupCallback {

    override fun on(params: OpenPopupCallback.Params): OpenPopupCallback.Response? {
        val browser = params.popupBrowser()
        invokeLater {
            val view = BrowserView.newInstance(browser)
            val frame = JFrame()
            frame.add(view, BorderLayout.CENTER)
            frame.addWindowListener(object: WindowAdapter() {
                override fun windowClosing(e: WindowEvent) {
                    invokeLater { browser.close() }
                }
            })
            updateBounds(frame, params.initialBounds())
            browser.on(TitleChanged::class.java) { event ->
                invokeLater { frame.title = event.title() }
            }
            browser.on(BrowserClosed::class.java) {
                invokeLater {
                    frame.isVisible = false
                    frame.dispose()
                }
            }
            browser.on(UpdateBoundsRequested::class.java) { event ->
                invokeLater { updateBounds(frame, event.bounds()) }
            }
            frame.isVisible = true
        }
        return OpenPopupCallback.Response.proceed()
    }

    companion object {
        private const val DEFAULT_POPUP_WIDTH = 800
        private const val DEFAULT_POPUP_HEIGHT = 600
        private fun updateBounds(frame: JFrame, bounds: Rect) {
            if (bounds.size().isEmpty) {
                frame.isLocationByPlatform = true
                frame.setSize(DEFAULT_POPUP_WIDTH, DEFAULT_POPUP_HEIGHT)
            } else {
                frame.location = toPoint(bounds.origin())
                frame.contentPane.preferredSize = toDimension(bounds.size())
                frame.pack()
            }
        }

        private fun toDimension(size: Size): Dimension {
            return Dimension(size.width(), size.height())
        }

        private fun toPoint(point: Point): java.awt.Point {
            return java.awt.Point(point.x(), point.y())
        }
    }
}

JavaFX

JavaFX BrowserView 的默认实现如下:

import static javafx.application.Platform.runLater;

import com.teamdev.jxbrowser.browser.Browser;
import com.teamdev.jxbrowser.browser.callback.OpenPopupCallback;
import com.teamdev.jxbrowser.browser.event.BrowserClosed;
import com.teamdev.jxbrowser.browser.event.TitleChanged;
import com.teamdev.jxbrowser.browser.event.UpdateBoundsRequested;
import com.teamdev.jxbrowser.ui.Rect;
import com.teamdev.jxbrowser.view.javafx.BrowserView;

import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

/**
 * The default {@link OpenPopupCallback} implementation for the JavaFX UI toolkit
 * that creates and shows a new window with the embedded popup browser.
 */
public final class DefaultOpenPopupCallback implements OpenPopupCallback {

    private static final int DEFAULT_POPUP_WIDTH = 800;
    private static final int DEFAULT_POPUP_HEIGHT = 600;

    @Override
    public Response on(Params params) {
        Browser browser = params.popupBrowser();
        runLater(() -> {
            BrowserView view = BrowserView.newInstance(browser);
            Stage stage = new Stage();
            StackPane root = new StackPane();
            Scene scene = new Scene(root);
            root.getChildren().add(view);
            stage.setScene(scene);

            updateBounds(stage, params.initialBounds());

            stage.setOnCloseRequest(event -> browser.close());
            browser.on(TitleChanged.class, event ->
                    runLater(() -> stage.setTitle(event.title()))
            );
            browser.on(BrowserClosed.class, event ->
                    runLater(stage::close)
            );
            browser.on(UpdateBoundsRequested.class, event ->
                    runLater(() -> updateBounds(stage, event.bounds()))
            );
            stage.show();
        });
        return Response.proceed();
    }

    private static void updateBounds(Stage stage, Rect bounds) {
        if (bounds.size().isEmpty()) {
            stage.setWidth(DEFAULT_POPUP_WIDTH);
            stage.setHeight(DEFAULT_POPUP_HEIGHT);
        } else {
            stage.setX(bounds.origin().x());
            stage.setY(bounds.origin().y());
            stage.setWidth(bounds.size().width());
            stage.setHeight(bounds.size().height());
        }
    }
}
import com.teamdev.jxbrowser.browser.callback.OpenPopupCallback
import com.teamdev.jxbrowser.browser.event.BrowserClosed
import com.teamdev.jxbrowser.browser.event.TitleChanged
import com.teamdev.jxbrowser.browser.event.UpdateBoundsRequested
import com.teamdev.jxbrowser.ui.Rect
import com.teamdev.jxbrowser.view.javafx.BrowserView
import javafx.application.Platform
import javafx.application.Platform.runLater
import javafx.event.EventHandler
import javafx.scene.Scene
import javafx.scene.layout.StackPane
import javafx.stage.Stage
import javafx.stage.WindowEvent

/**
 * The default [OpenPopupCallback] implementation for the JavaFX UI toolkit
 * that creates and shows a new window with the embedded popup browser.
 */
class DefaultOpenPopupCallback : OpenPopupCallback {
    
    override fun on(params: OpenPopupCallback.Params): OpenPopupCallback.Response? {
        val browser = params.popupBrowser()
        runLater {
            val view = BrowserView.newInstance(browser)
            val stage = Stage()
            val root = StackPane()
            val scene = Scene(root)
            root.children.add(view)
            stage.scene = scene
            updateBounds(stage, params.initialBounds())
            stage.onCloseRequest = EventHandler { browser.close() }
            browser.on(TitleChanged::class.java) { event -> 
                runLater { stage.title = event.title() } 
            }
            browser.on(BrowserClosed::class.java) {
                runLater { stage.close() }
            }
            browser.on(UpdateBoundsRequested::class.java) { event -> 
                runLater { updateBounds(stage, event.bounds()) } 
            }
            stage.show()
        }
        return OpenPopupCallback.Response.proceed()
    }

    companion object {
        private const val DEFAULT_POPUP_WIDTH = 800
        private const val DEFAULT_POPUP_HEIGHT = 600
        private fun updateBounds(stage: Stage, bounds: Rect) {
            if (bounds.size().isEmpty) {
                stage.width = DEFAULT_POPUP_WIDTH.toDouble()
                stage.height = DEFAULT_POPUP_HEIGHT.toDouble()
            } else {
                stage.x = bounds.origin().x().toDouble()
                stage.y = bounds.origin().y().toDouble()
                stage.width = bounds.size().width().toDouble()
                stage.height = bounds.size().height().toDouble()
            }
        }
    }
}

SWT

SWT BrowserView 的默认实现如下:

import com.teamdev.jxbrowser.browser.Browser;
import com.teamdev.jxbrowser.browser.callback.OpenPopupCallback;
import com.teamdev.jxbrowser.browser.event.BrowserClosed;
import com.teamdev.jxbrowser.browser.event.TitleChanged;
import com.teamdev.jxbrowser.browser.event.UpdateBoundsRequested;
import com.teamdev.jxbrowser.ui.Rect;
import com.teamdev.jxbrowser.view.swt.BrowserView;

import org.eclipse.swt.SWTException;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Widget;

/**
 * The default {@link OpenPopupCallback} implementation for the SWT UI toolkit
 * that creates and shows a new window with the embedded popup browser.
 */
public final class DefaultOpenPopupCallback implements OpenPopupCallback {

    private static final int DEFAULT_POPUP_WIDTH = 800;
    private static final int DEFAULT_POPUP_HEIGHT = 600;

    @Override
    public Response on(Params params) {
        Browser browser = params.popupBrowser();
        try {
            Display display = Display.getDefault();
            display.asyncExec(() -> {
                Shell shell = new Shell(display);
                shell.setLayout(new FillLayout());
                BrowserView view = BrowserView.newInstance(shell, browser);
                updateBounds(shell, view, params.initialBounds());

                shell.addDisposeListener(event -> {
                    if (!browser.isClosed()) {
                        asyncExec(shell, browser::close);
                    }
                });

                browser.on(TitleChanged.class, event ->
                        asyncExec(shell, () -> shell.setText(event.title())));
                browser.on(BrowserClosed.class, event ->
                        asyncExec(shell, shell::dispose));
                browser.on(UpdateBoundsRequested.class, event ->
                        asyncExec(shell, () -> updateBounds(shell, view, event.bounds())));

                view.setVisible(true);
                shell.pack();
                shell.open();

                while (!shell.isDisposed()) {
                    if (!display.readAndDispatch()) {
                        display.sleep();
                    }
                }
            });
        } catch (SWTException ignore) {
            Response.proceed();
        }
        return Response.proceed();
    }

    private static void updateBounds(Shell shell, BrowserView view, Rect bounds) {
        shell.setLocation(bounds.x(), bounds.y());
        if (bounds.size().isEmpty()) {
            view.setSize(DEFAULT_POPUP_WIDTH, DEFAULT_POPUP_HEIGHT);
        } else {
            view.setSize(bounds.width(), bounds.height());
        }
    }

    private static void asyncExec(Widget widget, Runnable doRun) {
        widget.getDisplay().asyncExec(() -> {
            if (!widget.isDisposed()) {
                doRun.run();
            }
        });
    }
}
import com.teamdev.jxbrowser.browser.Browser
import com.teamdev.jxbrowser.browser.callback.OpenPopupCallback
import com.teamdev.jxbrowser.browser.event.BrowserClosed
import com.teamdev.jxbrowser.browser.event.TitleChanged
import com.teamdev.jxbrowser.browser.event.UpdateBoundsRequested
import com.teamdev.jxbrowser.event.Observer
import com.teamdev.jxbrowser.ui.Rect
import com.teamdev.jxbrowser.view.swt.BrowserView
import org.eclipse.swt.SWTException
import org.eclipse.swt.layout.FillLayout
import org.eclipse.swt.widgets.Display
import org.eclipse.swt.widgets.Shell
import org.eclipse.swt.widgets.Widget

/**
 * The default [OpenPopupCallback] implementation for the SWT UI toolkit
 * that creates and shows a new window with the embedded popup browser.
 */
class DefaultOpenPopupCallback : OpenPopupCallback {
    override fun on(params: OpenPopupCallback.Params): OpenPopupCallback.Response? {
        val browser: Browser = params.popupBrowser()
        try {
            val display: Display = Display.getDefault()
            display.asyncExec {
                val shell = Shell(display)
                shell.setLayout(FillLayout())
                val view = BrowserView.newInstance(shell, browser)
                updateBounds(shell, view, params.initialBounds())
                shell.addDisposeListener { event ->
                    if (!browser.isClosed) {
                        asyncExec(shell) { browser.close() }
                    }
                }
                browser.on(TitleChanged::class.java) { event -> 
                    asyncExec(shell) { shell.setText(event.title()) } 
                }
                browser.on(BrowserClosed::class.java) { 
                    asyncExec(shell, shell::dispose)
                }
                browser.on(UpdateBoundsRequested::class.java) { event ->
                    asyncExec(shell) { updateBounds(shell, view, event.bounds()) }
                }
                view.setVisible(true)
                shell.pack()
                shell.open()
                while (!shell.isDisposed()) {
                    if (!display.readAndDispatch()) {
                        display.sleep()
                    }
                }
            }
        } catch (ignore: SWTException) {
            OpenPopupCallback.Response.proceed()
        }
        return OpenPopupCallback.Response.proceed()
    }

    companion object {
        private const val DEFAULT_POPUP_WIDTH = 800
        private const val DEFAULT_POPUP_HEIGHT = 600
        private fun updateBounds(shell: Shell, view: BrowserView, bounds: Rect) {
            shell.setLocation(bounds.x(), bounds.y())
            if (bounds.size().isEmpty) {
                view.setSize(DEFAULT_POPUP_WIDTH, DEFAULT_POPUP_HEIGHT)
            } else {
                view.setSize(bounds.width(), bounds.height())
            }
        }

        private fun asyncExec(widget: Widget, doRun: Runnable) {
            widget.getDisplay().asyncExec {
                if (!widget.isDisposed()) {
                    doRun.run()
                }
            }
        }
    }
}

关闭弹出窗口

可以通过 Browser.close() 方法或通过 JavaScript 的 window.close() 关闭打开的弹出窗口。 在这两种情况下,都会触发 BrowserClosed 事件。

我们建议您始终注册 BrowserClosed 事件监听器,以便在弹出式窗口关闭时获得通知。这将允许您隐藏弹出窗口(如果已显示)。

popup.on(BrowserClosed.class, event -> {
    // Hide the pop-up window.
});
popup.on(BrowserClosed::class.java) { event ->
    // Hide the pop-up window.
}
Go Top