JPanel which one of Listeners is proper for visibility is changed
Asked Answered
H

1

24

Are there some rules, or good/bad experiences with AncestorListener, ComponentListener or HierarchyListener listening for visibility of changes with JPanel and JComponents?

Is one of them better or safer than the others? I would especially like to know about when and how JPanel / JComponent is hidden.

Notice the following code contains incorrect Swing rules, like using Thread.sleep(int), in this case, to allow me to print-out correct order of Listeners in Swing GUI

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;

public class CardlayoutTest extends JFrame {

    private static final long serialVersionUID = 1L;
    public CardLayout card = new CardLayout();

    public CardlayoutTest() {
        JPanel pnlA = new JPanel(new BorderLayout());
        pnlA.add(new JButton("A"), BorderLayout.CENTER);
        JPanel pnlB = new JPanel(new BorderLayout());
        pnlB.add(new JButton("B"), BorderLayout.CENTER);
        JPanel pnlC = new JPanel(new BorderLayout());
        pnlC.add(new JButton("C"), BorderLayout.CENTER);

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(card);
        add(pnlA, "A");
        add(pnlB, "B");
        add(pnlC, "C");

        pnlA.addAncestorListener(new EventHandler());
        pnlB.addAncestorListener(new EventHandler());
        pnlC.addAncestorListener(new EventHandler());

        pnlA.addHierarchyListener(new EventHandler());
        pnlB.addHierarchyListener(new EventHandler());
        pnlB.addHierarchyListener(new EventHandler());

        pnlA.addComponentListener(new EventHandler());
        pnlB.addComponentListener(new EventHandler());
        pnlB.addComponentListener(new EventHandler());
    }

    class EventHandler implements AncestorListener, ComponentListener, HierarchyListener {

        @Override
        public void ancestorAdded(AncestorEvent event) {
            System.out.println("CardlayoutTest.EventHandler.ancestorAdded()");
        }

        @Override
        public void ancestorMoved(AncestorEvent event) {
            System.out.println("CardlayoutTest.EventHandler.ancestorMoved()");
        }

        @Override
        public void ancestorRemoved(AncestorEvent event) {
            System.out.println("CardlayoutTest.EventHandler.ancestorRemoved()");
        }

        @Override
        public void hierarchyChanged(HierarchyEvent e) {
            System.out.println("Components Change: " + e.getChanged());
            if ((e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0) {
                if (e.getComponent().isDisplayable()) {
                    System.out.println("Components DISPLAYABILITY_CHANGED : " + e.getChanged());
                } else {
                    System.out.println("Components DISPLAYABILITY_CHANGED : " + e.getChanged());
                }
            }
            if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) {
                if (e.getComponent().isDisplayable()) {
                    System.out.println("Components SHOWING_CHANGED : " + e.getChanged());
                } else {
                    System.out.println("Components SHOWING_CHANGED : " + e.getChanged());
                }
            }
        }

        public void componentHidden(ComponentEvent e) {
            System.out.println(e.getComponent().getClass().getName() + " --- Hidden");
        }

        public void componentMoved(ComponentEvent e) {
            System.out.println(e.getComponent().getClass().getName() + " --- Moved");
        }

        public void componentResized(ComponentEvent e) {
            System.out.println(e.getComponent().getClass().getName() + " --- Resized ");
        }

        public void componentShown(ComponentEvent e) {
            System.out.println(e.getComponent().getClass().getName() + " --- Shown");
        }
    }

    public static void main(String[] args) {
        CardlayoutTest t = new CardlayoutTest();
        t.setSize(500, 500);
        System.out.println("CardlayoutTest.main()------------------------ FIRST");
        t.card.show(t.getContentPane(), "A");
        t.setVisible(true);
        System.out.print("\n");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
        }
        System.out.println("CardlayoutTest.main()------------------------ SECOND");
        t.card.show(t.getContentPane(), "B");
        System.out.print("\n");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
        }
        System.out.println("CardlayoutTest.main()------------------------ THIRD");
        t.card.show(t.getContentPane(), "C");
        System.out.print("\n");
    }
}
Hornbill answered 4/6, 2012 at 11:14 Comment(0)
F
41

If you want to listen EXACTLY the visibility changes - use ComponentListener or ComponentAdapter:

    JPanel panel = new JPanel ();
    panel.addComponentListener ( new ComponentAdapter ()
    {
        public void componentShown ( ComponentEvent e )
        {
            System.out.println ( "Component shown" );
        }

        public void componentHidden ( ComponentEvent e )
        {
            System.out.println ( "Component hidden" );
        }
    } );

But that visibility might not be the one you think about. isVisible() flag will be true even if the Component is not added to any Container and hence not showing at all!

That visibility a has a slightly different purpose. You can use it to manually hide the Component that is already added and shown somewhere in your application. In that case, (if you use setVisible(false)) it will become hidden and every ComponentListener of that Component will be informed about that change.

So, talking about actual visibility...

This is what you should use to listen to actual component appearance/disappearance:

    JPanel panel = new JPanel ();
    panel.addAncestorListener ( new AncestorListener ()
    {
        public void ancestorAdded ( AncestorEvent event )
        {
            // Component added somewhere
        }

        public void ancestorRemoved ( AncestorEvent event )
        {
            // Component removed from container
        }

        public void ancestorMoved ( AncestorEvent event )
        {
            // Component container moved
        }
    } );

I always use that listener to determine when the Component is added somewhere and also to listen when it is moved/removed.

Also, you can always check if the Component is actually visible to application user by calling isShowing() method:

boolean userCanSeeThePanel = panel.isShowing();

This will return true ONLY if that panel is added to VISIBLE to user frame and isVisible() flag is also true (it is usually true, unless you set it to false).

I guess that's all I can tell you about visibility. I might have misunderstood your question. Correct me if I am wrong in that case.

Fulvous answered 4/6, 2012 at 12:54 Comment(7)
@Hornbill Feel free to ask more if you still don't understand some part of the visiblity. It is a pretty tricky part of Swing actuallyFulvous
basically interesting me to catch proper events when already visible JComponent is (change to) hiddenHornbill
If the change is made by "setVisible(false)" method - use ComponentListener or ComponentAdapter. In "componentHidden" you will recieve notification when component is hidden ("setVisible(false)" called) and in "componentShown" when it is shown ("setVisible(true)" called)Fulvous
till this moment is everything clear as demonstrated my SSCCE, all three Listener fired expected events,Hornbill
So, whats the question then? You are using proper listeners for proper events... i guess there is nothing more to say in such case. Or you have found some other problem?Fulvous
So, whats the question then? :) hehehe your answer is most complex with clear description, we need to be patient, maybe someone will kill my and your posts here, with wrong experiences, maybe yes, maybe not :-)Hornbill
accepting your very good for AncesorListener, works together with RepaintManager exception (my simple and reduced test)Hornbill

© 2022 - 2024 — McMap. All rights reserved.