我试图捕获在屏幕上显示组件的第一刻,而没有像使用计时器那样使用“肮脏”的解决方案。基本上,我想知道何时可以安全地在组件上使用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);
}
}
提前感谢。
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
我使用AncestorListener并处理了ancestorAdded事件。
奇怪的是,将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);
}
}
使用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
}
});
static ComponentListener cL = new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
super.componentResized(e);
System.out.println("componentShown = "+e.getComponent().isDisplayable());
}
};
大多数情况下,您可以先拨打ComponentListener.componentMoved
(或者如果您也对大小ComponentListener.componentResized
感兴趣)。每当组件的位置/大小改变时,这些函数就会被调用。