首次显示组件时的聆听

问题描述 投票:14回答:6

我试图捕获在屏幕上显示组件的第一刻,而没有像使用计时器那样使用“肮脏”的解决方案。基本上,我想知道何时可以安全地在组件上使用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);
    }
}

提前感谢。

java swing listener
6个回答
17
投票

ComponentListener不起作用的原因是它报告了对visible属性的更改-默认情况下为true,即使它不属于组件层次结构也是如此。

要得到可靠的通知,请使用HierarchyListener


编辑(关于我对这个问题/答案的知识发展的困惑,不确定网络礼仪对此有何看法……如果这是错误的方法,请直接指导我:)

[第一:本主题中提出的问题不一定与实际问题相关(如下文Boro所评论-可以通过任何方式链接到评论吗?):无需保留某种本地标志来决定是否或将getLocationOnScreen发送到组件不是安全的,只需询问组件本身即可。我自己的学习项目1 :-)

第二:所提出的问题很有趣。五位专家(包括我自己,自称),五个不同的答案。这触发了我的部分兴趣。

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

构建用例:为示例充分准备框架,并为以后的展示作好准备,这是提高perceived性能的典型方法。我的预测-基于我的假设:在准备时调整大小/移动,在放映时不放任何东西(请注意: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


6
投票

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


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

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

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

1
投票

大多数情况下,您可以先拨打ComponentListener.componentMoved(或者如果您也对大小ComponentListener.componentResized感兴趣)。每当组件的位置/大小改变时,这些函数就会被调用。

© www.soinside.com 2019 - 2024. All rights reserved.