Search code examples
javaswingbrowseractivexembed

Problem with JDICplus embedding IE in Java


I am building a Java Swing application that needs to support both an embedded browser and ActiveX. The easy way to do this seemed to be to use JDICplus, which just embeds IE in your application. That would have covered both requirements.

I also need to overlay some buttons on top of this browser view so the user can navigate between views. To do that, I have a JLayeredPane to which I add views, and at a higher layer, buttons. This works in my pure Java views. However, on my Internet view, the Internet draws on top of the buttons. In other words, it doesn't seem to respect the JLayeredPane. I'm guessing this is because it is a native component and not a Java component.

To be sure, I put the Internet pane into a JInternalFrame, and the buttons in the other, and put both of the internal frames into a JDesktopPane. When I drag the button frame on top of the Internet frame, the Internet frame jumps to the foreground and covers the other frame. It's as if the embedded IE steals the focus and puts itself in the forefront of my other windows.

My question is this: is there any way to draw Java components on top of these Windows/IE components reliably? Or, am I not going to get anywhere mixing Java with IE? Are there other options to meeting my requirement of an embedded browser and ActiveX support (which technically, could be a different view--in other words, I could have an Internet view and another view that just supports ActiveX). I'm open to suggestions. I have looked at other free browser components for Java, and as everyone will tell you, it's discouraging.


Solution

  • Check out Sun's article on mixing heavy and light components - since JDICPlus basically embeds IE into your app, it's a heavyweight component.

    You may be able to place buttons over the browser window by using other heavyweight components (i.e. AWT Button), or do something like place the button into a JPopupMenu placed over the browser with setDefaultLightWeightPopupEnabled(false) set on it to make it heavyweight.

    Edited

    I wrote an example using JPopupMenu to display a JButton over a heavyweight component - JPopupMenu works, but it does have built in behavior to close the menu when the popup or components in the popup lose focus. I added a MouseMotionListener to the heavyweight component to show the popups when the mouse entered a bounding box near where the buttons should be. Not sure if this works for you as the buttons aren't always shown.

    Including a code example and screenshot -

    import javax.swing.*;
    import javax.swing.event.MouseInputAdapter;
    import java.awt.*;
    import java.awt.event.MouseEvent;
    import java.awt.geom.Rectangle2D;
    
    public class LightHeavy extends JFrame {
    
        private Component heavyweightComponent;
        private JPopupMenu backButton, forwardButton;
    
        public LightHeavy() {
            super("LightHeavy");
            heavyweightComponent = buildHeavyweightComponent();
            heavyweightComponent.setBackground(Color.ORANGE);
            heavyweightComponent.setSize(640, 480);
            getContentPane().add(heavyweightComponent, BorderLayout.CENTER);
            ImageIcon backArrow = new ImageIcon("left_arrow_128.png");
            backButton = buildPopup(backArrow);
            ImageIcon forwardArrow = new ImageIcon("right_arrow_128.png");
            forwardButton = buildPopup(forwardArrow);
            heavyweightComponent.addMouseMotionListener(new MouseInputAdapter() {
                public void mouseMoved(MouseEvent e) {
                    Rectangle backHotSpot = new Rectangle(0, 0, 200, 200);
                    Rectangle forwardHotSpot = new Rectangle(heavyweightComponent.getWidth() - 200, 0, 200, 200);
                    if (backHotSpot.contains(e.getPoint())) {
                        backButton.show(heavyweightComponent, 0, 0);
                    } else if (forwardHotSpot.contains(e.getPoint())) {
                        forwardButton.show(heavyweightComponent,
                                heavyweightComponent.getWidth() - forwardButton.getWidth(), 0);
                    }
                }
            });
    
        }
    
        private Component buildHeavyweightComponent() {
            return new Canvas() {
                public void paint(Graphics og) {
                    super.paint(og);
                    Graphics2D g = (Graphics2D)og;
    
                    String big = "Heavyweight Component";
                    g.setFont(getFont().deriveFont(20F));
                    Rectangle2D bigBounds = g.getFontMetrics().getStringBounds(big, g);
                    g.drawString(big,
                            (this.getWidth() - (int)bigBounds.getWidth()) / 2,
                            (this.getHeight() - (int)bigBounds.getHeight()) / 2);
    
                    String little = "(assume this is JDICplus)";
                    g.setFont(getFont().deriveFont(10F));
                    Rectangle2D littleBounds = g.getFontMetrics().getStringBounds(little, g);
                    g.drawString(little,
                            (this.getWidth() - (int)littleBounds.getWidth()) / 2,
                            (this.getHeight() + (int)littleBounds.getHeight()) / 2);
                }
            };
        }
    
        private JPopupMenu buildPopup(Icon icon) {
            JButton button = new JButton(icon);
            JPopupMenu popup = new JPopupMenu();
            popup.add(button);
            popup.setBorderPainted(false);
            popup.setLightWeightPopupEnabled(false);
            return popup;
        }
    
        public static void main(String[] args) {
            JFrame f = new LightHeavy();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        }
    }
    

    Here's a screenshot with the JButton on the left showing - note that you also won't be able to do any cool transparency effects, as you're dealing with heavyweight components.

    screenshot of code