首次显示组件时监听

时间:2011-04-25 11:09:38

标签: java swing listener

我试图抓住屏幕上显示组件的第一时刻,而不使用“脏”解决方案,就像使用计时器一样。 基本上,我想知道我可以安全地开始在组件上使用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");
        }
    };

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

提前致谢。

6 个答案:

答案 0 :(得分:15)

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(new JButton(open));
    controller.pack();
    controller.setVisible(true);

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

新的帝国规则(草案):
不要使用ComponentListener来“显示”通知。这是AWT时代的遗留问题 请使用AncestorListener。这似乎是Swing的替代品,略微误解了“添加”的通知,实际上意味着“显示” 仅在真正对细粒度状态更改感兴趣时才使用HierarchyListener

答案 1 :(得分:6)

我已经使用了AncestorListener并处理了ancestorAdded事件。

答案 2 :(得分:3)

奇怪的是,ComponentListener在应用于JFrame时效果很好。这是我看到它改变的来源。

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

public class CompListenerTest
{
    static ComponentListener cL = new ComponentAdapter()
    {
        @Override
        public void componentShown(ComponentEvent e)
        {
            super.componentShown(e);
            System.out.println("componentShown");
        }
    };

    public static void main(String[] args)
    {
        JPanel p = new JPanel();
        p.setPreferredSize(new Dimension(300, 400));
        p.setBackground(Color.GREEN);

        System.out.println("initial test p="+p.isShowing());
        JPanel contentPane = new JPanel();
        contentPane.setBackground(Color.RED);
        contentPane.add(p);
        JFrame f = new JFrame();
        f.addComponentListener(cL);
        f.setContentPane(contentPane);
        f.setSize(800, 600);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
    }
}

答案 3 :(得分:2)

static ComponentListener cL = new ComponentAdapter() {
        @Override
        public void componentResized(ComponentEvent e) {
            super.componentResized(e);
            System.out.println("componentShown = "+e.getComponent().isDisplayable());
        }
    };

答案 4 :(得分:2)

使用AncestorListener和ancestorAdded为我工作。这是示例代码:

    addAncestorListener(new AncestorListener()
    {
        @Override
        public void ancestorRemoved(AncestorEvent event) {}

        @Override
        public void ancestorMoved(AncestorEvent event) {}

        @Override
        public void ancestorAdded(AncestorEvent event)
        {
            // component is shown here
        }
    });

答案 5 :(得分:1)

在大多数情况下,您可以先拨打ComponentListener.componentMoved(或者如果您对尺寸ComponentListener.componentResized感兴趣)。只要组件的位置/大小发生变化,就会调用它们。