首次显示组件时监听 [英] Listen for when a Component is Shown for the First Time
问题描述
我试图抓住屏幕上显示组件的第一时刻,而不使用脏解决方案,就像使用计时器一样。
基本上,我想知道我可以安全地开始在组件上使用 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屋!