我试图抓住屏幕上显示组件的第一时刻,而不使用“脏”解决方案,就像使用计时器一样。
基本上,我想知道我可以安全地开始在组件上使用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);
}
}
提前致谢。
答案 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
感兴趣)。只要组件的位置/大小发生变化,就会调用它们。