首次显示组件时监听 [英] Listen for when a Component is Shown for the First Time

查看:148
本文介绍了首次显示组件时监听的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图抓住屏幕上显示组件的第一时刻,而不使用脏解决方案,就像使用计时器一样。
基本上,我想知道我可以安全地开始在组件上使用 getLocationOnScreen()方法的那一刻。



我认为组件监听器可以帮助但在这里没有运气。我现在卡住了,不知道哪个听众可以使用。有什么建议吗?



下面是一些示例代码,显示组件侦听器失败。

  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);
}
};

静态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);
}
}

提前致谢。

解决方案

ComponentListener不起作用的原因是它报告了对visible属性的更改 - 默认情况下这是真的,即使不是组件的一部分层次结构。



要可靠地通知,请使用HierarchyListener





编辑(关于我的思考关于这个问题/答案的知识演变,不确定这样做的网络礼仪是什么......如果这是错误的方式,只需指导我: - )



<首先:主题中提出的问题不一定与实际问题有关(如下面Boro评论的那样 - 任何链接到评论的方式?):没有必要保留某种本地标志来决定是否或将getLocationOnScreen发送到组件并不安全,只需询问组件本身即可。我自己学习第1项:-)



第二:问的问题非常有趣。五位专家(包括我自己,自称),五个不同的答案。这引发了我的一些挖掘。



我的假设:ComponentEvents对于(first-)显示的通知没有用。我知道componentShown是无用的,因为它是一种propertyChange通知组件的可见属性(很少改变)。但是,对于移动/调整大小的建议用途感到困惑。



构造一个用例:在示例中完全准备框架并保持准备好以便以后显示,一个典型的提高感知性能的方法。我的预测 - 基于我的假设:在准备时调整大小/移动,在显示时没有任何东西(注意:isShowing是我们所追求的,也就是后者)。在OP的示例中添加的片段:

  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(新JButton(开放));
controller.pack();
controller.setVisible(true);

失望:在准备时没有通知,在展会时间通知,只是需要,我的假设似乎错了;-)最后的机会:交换setSize一包...瞧,准备时通知,在展会时没有通知,再次开心我。玩一点:如果一个组件是可显示的,看起来会触发ComponentEvents,这在某些情况下可能有用,也可能没有用,但如果显示的是我们所处的状态则不会。



新帝国规则(草案):

不要使用ComponentListener通知显示。那是AWT时代的遗留问题。

请使用AncestorListener。这似乎是Swing的替代品,略有误解的添加通知实际上意味着显示

只有在真正对细粒度状态变化感兴趣时才使用HierarchyListener


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:

    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

这篇关于首次显示组件时监听的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆