import java.awt.BorderLayout; import javafx.application.Application; import javafx.application.Platform; import javafx.beans.value.InvalidationListener; import javafx.beans.value.ObservableValue; import javafx.embed.swing.JFXPanel; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.web.PopupFeatures; import javafx.scene.web.WebEngine; import javafx.scene.web.WebView; import javafx.stage.Stage; import javafx.util.Callback; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.plaf.basic.*; import javax.swing.JFrame; import javax.swing.JTabbedPane; import javax.swing.SwingUtilities; public class Test extends Application { private JClosableTabbedPane tabPane; private WebEngine webEngine; public Test() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JFrame frame = new JFrame(); frame.getContentPane().setLayout(new BorderLayout()); frame.getContentPane().add(tabPane = new JClosableTabbedPane()); frame.setSize(600, 600); frame.setLocationRelativeTo(null); frame.setVisible(true); Platform.runLater(new Runnable() { @Override public void run() { final JFXPanel panel = createBrowserPanel("http://www.wenxuecity.com", null); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { tabPane.addTab("", panel); } }); } }); } }); } @SuppressWarnings("unchecked") protected JFXPanel createBrowserPanel(String url, WebEngine engine) { JFXPanel panel = new JFXPanel(); Group root = new Group(); final Scene scene; panel.setScene(scene = new Scene(root)); final WebView browser; root.getChildren().add(browser = new WebView()); webEngine = engine == null ? new WebEngine(url) : engine; browser.setEngine(webEngine); webEngine.setCreatePopupHandler(new Callback() { @Override public WebEngine call(PopupFeatures arg0) { WebEngine newEngine = new WebEngine(); final JFXPanel popupPanel = createBrowserPanel(null, newEngine); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { tabPane.addTab(tabPane.getTabCount() + "", new CloseIcon(null), popupPanel); tabPane.setSelectedComponent(popupPanel); } }); return newEngine; } }); scene.widthProperty().addListener(new InvalidationListener() { @Override public void invalidated(ObservableValue ov) { browser.resize(scene.getWidth(), scene.getHeight()); } }); scene.heightProperty().addListener(new InvalidationListener() { @Override public void invalidated(ObservableValue ov) { browser.resize(scene.getWidth(), scene.getHeight()); } }); browser.widthProperty().addListener(new InvalidationListener() { @Override public void invalidated(ObservableValue ov) { browser.resize(scene.getWidth(), scene.getHeight()); } }); browser.heightProperty().addListener(new InvalidationListener() { @Override public void invalidated(ObservableValue ov) { browser.resize(scene.getWidth(), scene.getHeight()); } }); return panel; } public static void main(String[] args) { Application.launch(Test.class, null); } @Override public void start(Stage arg0) throws Exception { // TODO Auto-generated method stub } /** * Class JCloseableTabbedPane */ static class JClosableTabbedPane extends JTabbedPane { /** */ private static final long serialVersionUID = -1906059835458246754L; /** The popup menu that shows the menu items for the tab */ private JPopupMenu tabPopupMenu = new JPopupMenu(); /** Item that closes the current tab */ private CloseTabMenuItem closeMenuItem; /** Item that closes all other tabs */ private CloseOtherTabsMenuItem closeOthersMenuItem; /** Item that closes all tabs */ private JMenuItem closeAllMenuItem; public JClosableTabbedPane() { this(TOP, true); } public JClosableTabbedPane(boolean equalWidthTab) { this(TOP, equalWidthTab); } /** * Default constructor. */ public JClosableTabbedPane(int tabPosition, boolean equalWidthTab) { super(tabPosition); // setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); if (equalWidthTab) { setUI(new MyBasicTabbedPaneUI()); } closeMenuItem = new CloseTabMenuItem(); closeMenuItem.setText("Close Tab"); closeMenuItem.addActionListener(closeMenuItem); closeOthersMenuItem = new CloseOtherTabsMenuItem(); closeOthersMenuItem.setText("Close Other Tabs"); closeOthersMenuItem.addActionListener(closeOthersMenuItem); closeAllMenuItem = new JMenuItem("Close All Tabs"); closeAllMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { removeAll(); } }); tabPopupMenu.add(closeMenuItem); tabPopupMenu.add(closeOthersMenuItem); tabPopupMenu.add(closeAllMenuItem); addMouseListener(new PopupMenuMouseListener()); } /** * The mouse listener responsible for showing the popup menu when a user * right-clicks on a tab. */ private class PopupMenuMouseListener extends MouseAdapter { @Override public void mousePressed(MouseEvent e) { int tabNumber = getUI().tabForCoordinate(JClosableTabbedPane.this, e.getX(), e.getY()); if (tabNumber >= 1 && (e.isPopupTrigger() || e.getModifiers() == InputEvent.BUTTON3_MASK)) { closeMenuItem.setTabNumber(tabNumber); closeOthersMenuItem.setTabNumber(tabNumber); tabPopupMenu.show(JClosableTabbedPane.this, e.getX(), e.getY()); } else if (tabNumber >= 1) { CloseIcon icon = (CloseIcon) getIconAt(tabNumber); if (icon == null) { return; } Rectangle rect = icon.getBounds(); if (rect.contains(e.getX(), e.getY())) { remove(tabNumber); } } } } /** * The menu item that closes a single tab. */ private class CloseTabMenuItem extends JMenuItem implements ActionListener { /** The tab number of the tab to close. */ private int tabNumber = -1; /** * @param number the number of the tab to close */ public void setTabNumber(int number) { tabNumber = number; } public void actionPerformed(ActionEvent e) { closeTab(tabNumber); } } /** * The menu item that closes other tabs. */ private class CloseOtherTabsMenuItem extends JMenuItem implements ActionListener { /** The tab number of the tab to close. */ private int tabNumber = -1; /** * @param number the number of the tab to close */ public void setTabNumber(int number) { tabNumber = number; } public void actionPerformed(ActionEvent e) { int tabCount = getTabCount(); if (tabCount > 1) { for (int i = tabCount - 1; i > 0; i--) { if (i != tabNumber) { closeTab(i); } } } } } /** * Overrides remove all to unsubscribe tabs as they are removed. */ @Override public void removeAll() { int tabCount = getTabCount(); if (tabCount > 1) { for (int i = tabCount - 1; i > 0; i--) { closeTab(i); } } } /** * @param i the tab index to close */ private void closeTab(int i) { remove(i); } /** * * @author rdong */ public static class MyBasicTabbedPaneUI extends BasicTabbedPaneUI { private Rectangle selIconRect; private int horizontalTextPosition = SwingUtilities.LEFT; public MyBasicTabbedPaneUI() { // do nothing } public MyBasicTabbedPaneUI(int horTextPosition) { horizontalTextPosition = horTextPosition; } protected int calculateTabWidth(int tabPlacement, int tabIndex, FontMetrics metrics) { Icon icon = tabPane.getIconAt(tabIndex); int iconWidth = icon == null ? 0 : icon.getIconWidth(); Insets margin = tabPane.getInsets(); return ( (tabPane.getWidth() - margin.left - margin.right) / tabPane.getTabCount()) - iconWidth; } public Rectangle getSelectedIconRect() { return selIconRect; } protected void layoutLabel(int tabPlacement, FontMetrics metrics, int tabIndex, String title, Icon icon, Rectangle tabRect, Rectangle iconRect, Rectangle textRect, boolean isSelected) { textRect.x = 0; textRect.y = 0; iconRect.x = 0; iconRect.y = 0; SwingUtilities.layoutCompoundLabel(tabPane, metrics, title, icon, SwingUtilities.CENTER, SwingUtilities.CENTER, SwingUtilities.CENTER, horizontalTextPosition, tabRect, iconRect, textRect, textIconGap + 2); selIconRect = iconRect; } @Override protected void paintText(Graphics g, int tabPlacement, Font font, FontMetrics metrics, int tabIndex, String title, Rectangle textRect, boolean isSelected) { Rectangle tabRect = rects[tabIndex]; Icon icon = tabPane.getIconAt(tabIndex); int iconWidth = icon == null ? 0 : icon.getIconWidth(); Rectangle rect = new Rectangle(textRect.x + tabInsets.left, textRect.y, tabRect.width - tabInsets.left - tabInsets.right - iconWidth, textRect.height); String clippedText = SwingUtilities.layoutCompoundLabel(metrics, title, null, SwingUtilities.CENTER, SwingUtilities.CENTER, SwingUtilities.CENTER, SwingUtilities.TRAILING, rect, new Rectangle(), rect, 0); if (title.equals(clippedText)) { super.paintText(g, tabPlacement, font, metrics, tabIndex, title, textRect, isSelected); } else { rect = new Rectangle(textRect.x + tabInsets.left, textRect.y, tabRect.width - tabInsets.left - tabInsets.right, textRect.height); super.paintText(g, tabPlacement, font, metrics, tabIndex, clippedText, rect, isSelected); } } } } /* * * The class which generates the 'X' icon for the tabs. The constructor * accepts an icon which is extra to the 'X' icon, so you can have tabs like * in JBuilder. This value is null if no extra icon is required. */ public static class CloseIcon implements Icon { private int x_pos; private int y_pos; private int width; private int height; private Icon fileIcon; public CloseIcon(Icon fileIcon) { this.fileIcon = fileIcon; width = 16; height = 16; } public void paintIcon(Component c, Graphics g, int x, int y) { this.x_pos = x; this.y_pos = y; int verticalPad = 2; drawEX(g, x, y, verticalPad); if (fileIcon != null) { fileIcon.paintIcon(c, g, x + width, y + verticalPad); } } /** * @param g graphics to draw with * @param x - x position to start drawing from * @param y - y position to start drawing from * @param verticalPad to bump the y coord up by */ public void drawEX(Graphics g, int x, int y, int verticalPad) { Color col = g.getColor(); g.setColor(Color.LIGHT_GRAY.darker()); int y_p = y + verticalPad; g.drawLine(x + 3, y_p + 3, x + 10, y_p + 10); g.drawLine(x + 3, y_p + 4, x + 9, y_p + 10); g.drawLine(x + 4, y_p + 3, x + 10, y_p + 9); g.drawLine(x + 10, y_p + 3, x + 3, y_p + 10); g.drawLine(x + 10, y_p + 4, x + 4, y_p + 10); g.drawLine(x + 9, y_p + 3, x + 3, y_p + 9); g.setColor(col); } public int getIconWidth() { return width + (fileIcon != null ? fileIcon.getIconWidth() : 0); } public int getIconHeight() { return height; } public Rectangle getBounds() { return new Rectangle(x_pos, y_pos, width, height); } } }