监听/处理JPanel事件

3

女士们先生们晚上好,

我遇到了一个关于Java Swing的问题,很难解决,希望你能帮助我。以下是问题:

  • 我有一个使用边界布局(BorderLayout)和许多JPanel的JFrame。
  • 每次我需要放置一个新屏幕(即从主菜单,当点击搜索按钮时,转到搜索菜单)时,我只需删除位于中心的组件(JPanel),并将新屏幕(new JPanel)放在中心位置。
  • 这样,我不必每次想要放置新屏幕时都调用所有的标题和页脚对象。

使用这种系统一切正常,除了这个小问题:我想在每次放置一个新的JPanel或切换回现有的JPanel时触发一些方法(通常情况下,每次出现一个JPanel时)。

为了做到这一点,我尝试实现ComponentListener的componentShown(ComponentEvent e)方法,并向我放置在JFrame中心的JPanel添加了一个ComponentListener,但它没有起作用。之后,我进行了一些研究,发现这个componentShown(@ComponentListener)方法仅在JPanel的可见性更改时(从不可见到可见或相反)才起作用。不幸的是,我不是改变JPanel的可见性,只是将其替换为另一个JPanel:删除当前JPanel并添加新的JPanel。下面的代码说明了我如何替换JPanels。

// Get the JPanel located in the center of our JFrame
JPanel currentView = (JPanel) myFrame.getContentPane().getComponent( 2 );

if ( currentView != null )
{
   // Remove it from the JPanel         
   myFrame.getContentPane().remove( currentView );
}

// Add the new JPanel    
myFrame.getContentPane().add( otherView, BorderLayout.CENTER );

// Pack the JFrame and show it
myFrame.pack();

以下是需要翻译的内容:

这是我的问题,如果你能帮忙解决,我会非常感激。


4
你可以使用一个位于contentPaneCENTER位置,且采用CardLayoutJPanel来代替手动添加或移除多个JPanel如何使用 CardLayout - Jeffrey
1
@Jeffrey,感谢你的快速回复。你说的很好也很合理,但我正在处理的是一个团队项目。我们目前正在遵循一种模式,并且在建议改变我们的模式(从BorderLayout到CardLayout)之前,我至少想尝试用当前的模式提出一个解决方案。 - 629
1
仅仅因为你使用了BorderLayout并不意味着你不能同时使用CardLayout,它们并不是互斥的。BorderLayout.CENTER面板可以作为卡片持有者,即使用CardLayout的JPanel。 - Hovercraft Full Of Eels
我不认为我理解你的问题。你有一个可以在面板之间切换的代码,现在你想在切换面板后再做一些额外的事情... 为什么不在调用“add”方法后直接添加代码,而不是尝试使用监听器呢? - Robin
1
直观的“可见性”通知是通过AncestorListener实现的:http://docs.oracle.com/javase/7/docs/api/javax/swing/event/AncestorListener.html - kleopatra
2个回答

2
我认为这个问题与HierarchyListener有关,用于比较。请参考HierarchyListener文档
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ContainerListener extends JFrame {

    private static final long serialVersionUID = 1L;

    public ContainerListener() {
        super("Test");
        setContentPane(new TestPanel());
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    public static void main(String[] parameters) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                ContainerListener containerListener = new ContainerListener();
            }
        });
    }

    private class TestPanel extends JPanel {

        private static final long serialVersionUID = 1L;

        TestPanel() {
            setLayout(new FlowLayout(FlowLayout.LEFT));
            add(new JButton(new AbstractAction("Add label") {

                private static final long serialVersionUID = 1L;
                private int n = 0;

                @Override
                public void actionPerformed(ActionEvent event) {
                    TestPanel.this.add(new JLabel("Label " + ++n));
                    validate();
                }
            }));
            addHierarchyListener(new HierarchyListener() {

                @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: " + e.getChanged());
                        } else {
                            System.out.println("Components: " + e.getChanged());
                        }
                    }
                }
            });
            addContainerListener(new ContainerAdapter() {

                @Override
                public void componentAdded(ContainerEvent event) {
                    System.out.println("componentAdded : " + event.getChild() + "containerName" + " was added");
                }
            });

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }
    }
}

非常感谢您的回答。当我使用HierarchyListener而不是ContainerListener时,它起作用了! - 629

2
我强烈建议听从@Jeffrey的建议,但如果您决定继续这个设计,则实现ContainerListener接口可能会很有用。
当不确定时,请查阅API。

我刚刚尝试了您的解决方案并实现了ContainerListener。它与新创建的JPanels完美地配合使用。不幸的是,当返回到现有的JPanel时,它无法正常工作。无论是返回到现有的JPanel还是创建一个新的,并将其视图放置在上面,我总是使用上述相同的方式来删除和添加视图到我的框架中。我不明白为什么将现有面板放置到框架中时它不能正常工作...:S - 629
3
为此,您需要一个WindowListenerWindowFocusListenerWindowStateListener - trashgod

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接