Listen for when a Component is Shown for the First Time

前端 未结 6 1556
日久生厌
日久生厌 2021-01-07 22:29

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

6条回答
  •  自闭症患者
    2021-01-07 23:00

    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:

        final JFrame f = new JFrame();
        f.setContentPane(contentPane);
        f.setSize(800, 600);
        //        f.pack(); 
    
        JFrame controller = new JFrame("opener");
        controller.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Action open = new AbstractAction("open/hide second") {
    
            @Override
            public void actionPerformed(ActionEvent e) {
                f.setVisible(!f.isVisible());
            }
    
        };
        controller.add(new JButton(open));
        controller.pack();
        controller.setVisible(true);
    

    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

提交回复
热议问题