oz1cz
oz1cz

Reputation: 5844

Detect removal of component

I create a Popup using the PopupFactory.getPopup method. According to the documentation, I am required to call the hide() method on the popup when it is no longer needed.

In my application, the popup is the child of a JLabel which may be removed from the current frame in a number of different situations. (Either the JLabel itself or one of its parent containers is removed.) Rather that calling hide() in every single place (and making the Popup object available in all these places) I would prefer to be able to detect the removal of the JLabel or one of its parent containers.

How can I detect the removal? I naively assumed that the removal of a component meant the removal/hiding of its children, but as the code below shows, the popup survives the removal of the JLabel.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Xyzzy extends JFrame {
    static Xyzzy frame;
    static JPanel panel;
    static JLabel text1;
    static JLabel text2;

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    frame = new Xyzzy();
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.PAGE_AXIS));

                    panel = new JPanel();
                    panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
                    frame.add(panel);


                    text1 = new JLabel("text1");
                    text2 = new JLabel("text2");

                    panel.add(text1);

                    frame.add(new JButton(new AbstractAction("Add popup") {
                            public void actionPerformed(ActionEvent e) {
                                PopupFactory factory = PopupFactory.getSharedInstance();
                                Popup popup = factory.getPopup(text1, new JLabel("POPUP"),frame.getX()+300,frame.getY()+300);
                                popup.show();
                            }
                        }));

                    frame.add(new JButton(new AbstractAction("New label") {
                            public void actionPerformed(ActionEvent e) {
                                panel.remove(text1);
                                panel.add(text2);
                                panel.revalidate();
                            }
                        }));

                    frame.setSize(600, 600);
                    frame.setVisible(true);
                }
            });
    }
}

This code creates a JFrame displaying the text "text1" and two buttons. If you press the button labeled "Add popup", a Popup with the text "POPUP" appears in the window. This Popup is a child of text1. Press the "New label" button and "text1" is removed from the display, but the Popup survives.

I need to be able to detect when text1 or the containing panel is removed so that I can hide the popup. I want to avoid adding code where the actual remove() method is called.

Upvotes: 3

Views: 840

Answers (1)

Peter Bagyinszki
Peter Bagyinszki

Reputation: 1080

You can use HierarchyListener:

public void actionPerformed(ActionEvent e) {
  PopupFactory factory = PopupFactory.getSharedInstance();
  final Popup popup = factory.getPopup(text1, new JLabel("POPUP"),frame.getX()+300,frame.getY()+300);
  text1.addHierarchyListener(new HierarchyListener() {

    public void hierarchyChanged(HierarchyEvent e) {
      if (e.getID() == HierarchyEvent.HIERARCHY_CHANGED
          && (e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) {
        popup.hide();
      }
    }
  });
  popup.show();
}

Upvotes: 4

Related Questions