弹出窗口
本页面描述了如何处理、显示或抑制弹出窗口。
概述
任何网页都可以使用以下方式之一显示弹出窗口:
使用
window.open()
JavaScript 函数。例如:window.open("https://www.google.com", "_blank", "resizable=yes, top=500, left=500, width=400, height=400");
通过带有
target
属性的链接:<a href="https://www.google.com" target="_blank">打开 Google</a>
默认情况下,所有弹出窗口都会被抑制。
打开弹出窗口
为了更改默认行为并控制弹出窗口的创建,请使用 CreatePopupCallback
和 OpenPopupCallback
回调。
当 Engine 想知道是否可以创建弹出窗口时,将调用 CreatePopupCallback
回调。以下代码显示了如何允许创建弹出窗口:
browser.set(CreatePopupCallback.class, (params) -> CreatePopupCallback.Response.create());
browser.register(CreatePopupCallback {
CreatePopupCallback.Response.create()
})
如果 CreatePopupCallback
回调允许创建弹出窗口,则会调用 OpenPopupCallback
回调。在此回调中,您可以访问已创建的弹出窗口,并在必要时显示它。例如:
browser.set(OpenPopupCallback.class, (params) -> {
// 访问已创建的弹出窗口。
var popup = params.popupBrowser();
return OpenPopupCallback.Response.proceed();
});
browser.register(OpenPopupCallback { params ->
// 访问已创建的弹出窗口。
val popup = params.popupBrowser()
OpenPopupCallback.Response.proceed()
})
在上述示例中,popup
实例在回调被调用时并没有加载任何网页。网页将在稍后加载。此时,您可以注册所有必需的事件监听器和回调,但不能访问 DOM 或 JavaScript,因为 popup
还没有 Frame
。
抑制弹出窗口
要抑制弹出窗口,请使用以下方法:
browser.set(CreatePopupCallback.class, params -> CreatePopupCallback.Response.suppress());
browser.register(CreatePopupCallback {
CreatePopupCallback.Response.suppress()
})
显示弹出窗口
当您创建一个 Swing 或 JavaFX 的 BrowserView
时,它会自动为给定的 Browser
实例配置 CreatePopupCallback
和 OpenPopupCallback
回调的默认实现。
CreatePopupCallback
的默认实现允许创建所有弹出窗口:
browser.set(CreatePopupCallback.class, params -> CreatePopupCallback.Response.create());
browser.register(CreatePopupCallback {
CreatePopupCallback.Response.create()
})
Swing 和 JavaFX 中 OpenPopupCallback
回调的默认实现如下所示。
Swing
Swing BrowserView
的默认实现如下:
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;
import static javax.swing.SwingUtilities.invokeLater;
/**
* Swing UI 工具包的默认 [OpenPopupCallback] 实现
* 创建并显示带有嵌入式弹出 Browser 的新窗口。
*/
public final class DefaultOpenPopupCallbackSwing implements OpenPopupCallback {
private static final int DEFAULT_POPUP_WIDTH = 800;
private static final int DEFAULT_POPUP_HEIGHT = 600;
@Override
public Response on(Params params) {
var browser = params.popupBrowser();
invokeLater(() -> {
var view = BrowserView.newInstance(browser);
var 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.dsl.subscribe
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
/**
* Swing UI 工具包的默认 {@link OpenPopupCallback} 实现
* 创建并显示带有嵌入式弹出 Browser 的新窗口。
*/
class DefaultOpenPopupCallbackSwing : 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.subscribe<TitleChanged> { event ->
invokeLater { frame.title = event.title() }
}
browser.subscribe<BrowserClosed> {
invokeLater {
frame.isVisible = false
frame.dispose()
}
}
browser.subscribe<UpdateBoundsRequested> { 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 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;
import static javafx.application.Platform.runLater;
/**
* JavaFX UI 工具包的默认 {@link OpenPopupCallback} 实现
* 创建并显示带有嵌入式弹出 Browser 的新窗口。
*/
public final class DefaultOpenPopupCallbackJavaFx implements OpenPopupCallback {
private static final int DEFAULT_POPUP_WIDTH = 800;
private static final int DEFAULT_POPUP_HEIGHT = 600;
@Override
public Response on(Params params) {
var browser = params.popupBrowser();
runLater(() -> {
var view = BrowserView.newInstance(browser);
var stage = new Stage();
var root = new StackPane();
var 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.dsl.subscribe
import com.teamdev.jxbrowser.ui.Rect
import com.teamdev.jxbrowser.view.javafx.BrowserView
import javafx.application.Platform.runLater
import javafx.event.EventHandler
import javafx.scene.Scene
import javafx.scene.layout.StackPane
import javafx.stage.Stage
/**
* JavaFX UI 工具包的默认 [OpenPopupCallback] 实现
* 创建并显示带有嵌入式弹出 Browser 的新窗口。
*/
class DefaultOpenPopupCallbackJavaFx : 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.subscribe<TitleChanged> { event ->
runLater { stage.title = event.title() }
}
browser.subscribe<BrowserClosed> {
runLater { stage.close() }
}
browser.subscribe<UpdateBoundsRequested> { 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.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;
/**
* SWT UI 工具包的默认 {@link OpenPopupCallback} 实现
* 创建并显示带有嵌入式弹出 Browser 的新窗口。
*/
public final class DefaultOpenPopupCallbackSwt implements OpenPopupCallback {
private static final int DEFAULT_POPUP_WIDTH = 800;
private static final int DEFAULT_POPUP_HEIGHT = 600;
@Override
public Response on(Params params) {
var browser = params.popupBrowser();
try {
var display = Display.getDefault();
display.asyncExec(() -> {
var shell = new Shell(display);
shell.setLayout(new FillLayout());
var 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.dsl.subscribe
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
/**
* SWT UI 工具包的默认 [OpenPopupCallback] 实现
* 创建并显示带有嵌入式弹出 Browser 的新窗口。
*/
class DefaultOpenPopupCallbackSwt : 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.layout = FillLayout()
val view = BrowserView.newInstance(shell, browser)
updateBounds(shell, view, params.initialBounds())
shell.addDisposeListener {
if (!browser.isClosed) {
asyncExec(shell) { browser.close() }
}
}
browser.subscribe<TitleChanged> { event ->
asyncExec(shell) { shell.text = event.title() }
}
browser.subscribe<BrowserClosed> {
asyncExec(shell, shell::dispose)
}
browser.subscribe<UpdateBoundsRequested> { event ->
asyncExec(shell) { updateBounds(shell, view, event.bounds()) }
}
view.isVisible = 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.display.asyncExec {
if (!widget.isDisposed) {
doRun.run()
}
}
}
}
}
关闭弹出窗口
已打开的弹出窗口可以通过 Browser.close()
方法关闭,或者通过 JavaScript 中的 window.close()
关闭。在这两种情况下,都会触发 BrowserClosed
事件。
我们建议您始终注册 BrowserClosed
事件监听器,以便在弹出式窗口关闭时获得通知。这将允许您隐藏显示的弹出窗口。
popup.on(BrowserClosed.class, event -> {
// 隐藏弹出窗口。
});
popup.on(BrowserClosed::class.java) { event ->
// 隐藏弹出窗口。
}