更改了其中一个侦听器适合可见性的 JPanel

Posted

技术标签:

【中文标题】更改了其中一个侦听器适合可见性的 JPanel【英文标题】:JPanel which one of Listeners is proper for visibility is changed 【发布时间】:2012-06-08 11:14:30 【问题描述】:

AncestorListenerComponentListenerHierarchyListener 是否有一些规则或好/坏体验?

其中一个比其他的更好或更安全吗?我特别想知道JPanel / JComponent 何时以及如何隐藏。

注意以下代码包含不正确的 Swing 规则,例如在这种情况下使用 Thread.sleep(int),以允许我在 Swing GUI 中打印出正确的 Listeners 顺序

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;

public class CardlayoutTest extends JFrame 

    private static final long serialVersionUID = 1L;
    public CardLayout card = new CardLayout();

    public CardlayoutTest() 
        JPanel pnlA = new JPanel(new BorderLayout());
        pnlA.add(new JButton("A"), BorderLayout.CENTER);
        JPanel pnlB = new JPanel(new BorderLayout());
        pnlB.add(new JButton("B"), BorderLayout.CENTER);
        JPanel pnlC = new JPanel(new BorderLayout());
        pnlC.add(new JButton("C"), BorderLayout.CENTER);

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(card);
        add(pnlA, "A");
        add(pnlB, "B");
        add(pnlC, "C");

        pnlA.addAncestorListener(new EventHandler());
        pnlB.addAncestorListener(new EventHandler());
        pnlC.addAncestorListener(new EventHandler());

        pnlA.addHierarchyListener(new EventHandler());
        pnlB.addHierarchyListener(new EventHandler());
        pnlB.addHierarchyListener(new EventHandler());

        pnlA.addComponentListener(new EventHandler());
        pnlB.addComponentListener(new EventHandler());
        pnlB.addComponentListener(new EventHandler());
    

    class EventHandler implements AncestorListener, ComponentListener, HierarchyListener 

        @Override
        public void ancestorAdded(AncestorEvent event) 
            System.out.println("CardlayoutTest.EventHandler.ancestorAdded()");
        

        @Override
        public void ancestorMoved(AncestorEvent event) 
            System.out.println("CardlayoutTest.EventHandler.ancestorMoved()");
        

        @Override
        public void ancestorRemoved(AncestorEvent event) 
            System.out.println("CardlayoutTest.EventHandler.ancestorRemoved()");
        

        @Override
        public void hierarchyChanged(HierarchyEvent e) 
            System.out.println("Components Change: " + e.getChanged());
            if ((e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0) 
                if (e.getComponent().isDisplayable()) 
                    System.out.println("Components DISPLAYABILITY_CHANGED : " + e.getChanged());
                 else 
                    System.out.println("Components DISPLAYABILITY_CHANGED : " + e.getChanged());
                
            
            if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) 
                if (e.getComponent().isDisplayable()) 
                    System.out.println("Components SHOWING_CHANGED : " + e.getChanged());
                 else 
                    System.out.println("Components SHOWING_CHANGED : " + e.getChanged());
                
            
        

        public void componentHidden(ComponentEvent e) 
            System.out.println(e.getComponent().getClass().getName() + " --- Hidden");
        

        public void componentMoved(ComponentEvent e) 
            System.out.println(e.getComponent().getClass().getName() + " --- Moved");
        

        public void componentResized(ComponentEvent e) 
            System.out.println(e.getComponent().getClass().getName() + " --- Resized ");
        

        public void componentShown(ComponentEvent e) 
            System.out.println(e.getComponent().getClass().getName() + " --- Shown");
        
    

    public static void main(String[] args) 
        CardlayoutTest t = new CardlayoutTest();
        t.setSize(500, 500);
        System.out.println("CardlayoutTest.main()------------------------ FIRST");
        t.card.show(t.getContentPane(), "A");
        t.setVisible(true);
        System.out.print("\n");
        try 
            Thread.sleep(2000);
         catch (InterruptedException e) 
        
        System.out.println("CardlayoutTest.main()------------------------ SECOND");
        t.card.show(t.getContentPane(), "B");
        System.out.print("\n");
        try 
            Thread.sleep(2000);
         catch (InterruptedException e) 
        
        System.out.println("CardlayoutTest.main()------------------------ THIRD");
        t.card.show(t.getContentPane(), "C");
        System.out.print("\n");
    

【问题讨论】:

【参考方案1】:

如果您想准确了解可见性变化 - 使用 ComponentListenerComponentAdapter

    JPanel panel = new JPanel ();
    panel.addComponentListener ( new ComponentAdapter ()
    
        public void componentShown ( ComponentEvent e )
        
            System.out.println ( "Component shown" );
        

        public void componentHidden ( ComponentEvent e )
        
            System.out.println ( "Component hidden" );
        
     );

但这种可见性可能不是您所想的。 isVisible() 标志将是 true,即使 Component 未添加到任何 Container 并且因此根本不显示!

可见性 a 的目的略有不同。您可以使用它手动隐藏已添加并显示在应用程序某处的Component。在这种情况下,(如果您使用setVisible(false))它将被隐藏,并且该Component 中的每个ComponentListener 都会被告知该更改。

所以,谈论实际可见性...

这是您应该用来聆听实际组件出现/消失的内容:

    JPanel panel = new JPanel ();
    panel.addAncestorListener ( new AncestorListener ()
    
        public void ancestorAdded ( AncestorEvent event )
        
            // Component added somewhere
        

        public void ancestorRemoved ( AncestorEvent event )
        
            // Component removed from container
        

        public void ancestorMoved ( AncestorEvent event )
        
            // Component container moved
        
     );

我总是使用该侦听器来确定何时将Component 添加到某处,并在移动/移除它时进行侦听。

此外,您可以随时通过调用isShowing() 方法检查Component 是否对应用程序用户真正可见:

boolean userCanSeeThePanel = panel.isShowing();

仅当该面板添加到对用户框架的可见性并且isVisible() 标志也为真时,这将返回true(通常为true,除非您将其设置为false)。

关于可见性,我想这就是我能告诉你的全部内容了。我可能误解了你的问题。如果我在这种情况下错了,请纠正我。

【讨论】:

@mKorbel 如果您仍然不了解可见性的某些部分,请随时询问更多信息。这实际上是 Swing 的一个非常棘手的部分 当已经可见的 JComponent 被(更改为)隐藏时,我很感兴趣地捕捉适当的事件 如果更改是通过“setVisible(false)”方法进行的 - 使用 ComponentListener 或 ComponentAdapter。在“componentHidden”中,当组件隐藏时(调用“setVisible(false)”)和在“componentShown”中显示(调用“setVisible(true)”)时,您将收到通知 直到这一刻一切都清楚了,正如我的 SSCCE 所展示的那样,所有三个 Listener 都触发了预期的事件, 那么,有什么问题呢?您正在为适当的事件使用适当的侦听器......我想在这种情况下没有什么可说的了。还是您发现了其他问题?

以上是关于更改了其中一个侦听器适合可见性的 JPanel的主要内容,如果未能解决你的问题,请参考以下文章

OnItemClick 侦听器和单击的 View 项的可见性

如何将文档侦听器添加到面板内的 JTextFields?

在 JPanel 上的任何位置检测鼠标进入/退出事件

来自另一个类的 JButton 动作侦听器

数据更改 SwiftUI 时多次调用 Firebase 侦听器

在我的自定义列表项中单击书签图像的侦听器,多次更改另一个 row_item 图像