I am trying to capture the very first moment when a component is shown on the screen without using ‘dirty’ solutions as with use of a timer.
Basically, I want to know the moment when I can safely start using getLocationOnScreen() method on the component.
I thought that component listener could help but no luck here. I am stuck for now and do not know which listener to use for this. Any suggestions?
Here is some sample code which shows that a component listener fails.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class CompListenerTest
{
static ComponentListener cL = new ComponentAdapter()
{
@Override
public void componentShown(ComponentEvent e)
{
super.componentShown(e);
System.out.println("componentShown");
}
};
static MouseListener mL = new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent e)
{
super.mousePressed(e);
JComponent c = (JComponent) e.getSource();
System.out.println("mousePressed c="+c.isShowing());
}
};
public static void main(String[] args)
{
JPanel p = new JPanel();
p.setPreferredSize(new Dimension(300, 400));
p.setBackground(Color.GREEN);
p.addComponentListener(cL);
p.addMouseListener(mL);
System.out.println("initial test p="+p.isShowing());
JPanel contentPane = new JPanel();
contentPane.setBackground(Color.RED);
contentPane.add(p);
JFrame f = new JFrame();
f.setContentPane(contentPane);
f.setSize(800, 600);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
Thanks in advance.
The reason a ComponentListener doesn’t work is that it reports changes to the visible property – and that is true by default, even without being part of the component hierarchy.
To be reliably notified, use a HierarchyListener
Edit (musings about my knowledge evolution in regard to this question/answers, not sure what the netiquette has to say about doing it … simply guide me if that’s the wrong way to go 🙂
First: the question as asked in the subject is not necessarily related to the actual problem (as commented by Boro below – any way to link to a comment?): there’s no need to keep some kind of local flag to decide whether or not it is safe to send a getLocationOnScreen to a component, simply ask the component itself. Learn-item 1 for myself 🙂
Second: The question as asked is quite interesting. Five experts (including myself, self-proclaimed), five different answers. Which triggered a bit of digging on my part.
My hypothesis: ComponentEvents are not useful for notification of (first-)showing. I knew that componentShown is useless because it’s a kind-of propertyChange notification of the visible property of a component (which rarely changes). Puzzled about the suggested usefulness of moved/resized, though.
Constructing a use-case: fully prepare the frame in the example and keep it ready for later showing, a typical approach to improve perceived performance. My prediction – based on my hypothesis: resized/moved fired at prepare-time, nothing at show-time (note: the isShowing is what we are after, that is the latter). A snippet to add in the OP’s example:
Disappointment: no notification at prepare-time, notification at show-time, just as needed, my hypothesis seemed wrong 😉 Last chance: swap the setSize for a pack … and voila, notification at prepare-time, no notification at show-time, happy me again. Playing a bit more: looks like ComponentEvents are fired if the a component is displayable, which may or may not be useful in some contexts but not if showing is the state we are after. The
New imperial rules (draft):
Do not use ComponentListener for notification of “showing”. That’s left-over from AWT-age.
Do use AncestorListener. That seems to be the Swing replacement, slightly misnomed notification of “added” which actually means “showing”
Do use HierarchyListener only if really interested in fine-grained state changes