如何从另一个面板更改卡片布局面板?

11

我在谷歌上搜了很多,但没有找到解决方案。我认为一定有Java大师能帮助我……

这是我的初始化方法:


private void initialize() {
    this.setSize(750, 480);
    this.setContentPane(getJContentPane());
    this.setTitle("Registration");
    JPanel topPane = new TopPane();
    this.getContentPane().add(topPane,BorderLayout.PAGE_START);
    cards=new JPanel(new CardLayout());
    cards.add(step0(),"step0");
    cards.add(step1(),"step1");
    cards.add(step2(),"step2");
    this.getContentPane().add(cards,BorderLayout.CENTER);
}

public JPanel step2(){
    EnumMap<DPFPFingerIndex,DPFPTemplate> template = new EnumMap<DPFPFingerIndex, DPFPTemplate>(DPFPFingerIndex.class); 
    JPanel enrol = new Enrollment(template,2);
    return enrol;
}

public JPanel step0(){
    JPanel userAgree = new UserAgreement();
    return userAgree;
}

public JPanel step1(){
    JPanel userInfo = new UserInformation();
    return userInfo;
}

public JPanel getCards(){
    return cards;
}
这是在另一个步骤的JPanel中的方法:
jButtonAgree.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent e) {
                Registration reg = new Registration();
                LayoutManager cards = reg.getCards().getLayout();
                ((CardLayout) cards).show(reg.getCards(),"step1");
            }
        });

完全没有反应,我尝试重新验证(revalidate)、重绘(repaint)和其他操作...都不起作用...有人能在这里提供任何解决方案吗!


1
问题在于没有在正确的Registration实例上调用方法。在上面的代码中,您正在创建一个与GUI中显示的Registration实例完全无关的新Registration实例。相反,您需要获取对可见Registration对象的引用。请参见下面的答案... - Hovercraft Full Of Eels
1个回答

20

重点在于向外界公开正确的方法和常量字符串,使得该类可以自行切换视图。例如,给你的第一个类一个称为cardlayout的私有CardLayout字段和一个称为cards(卡片持有者JPanel)的私有JPanel字段,并提供一些公共的字符串常量,用于将您的卡片JPanel添加到cards容器中。还要给它一个名为public void swapView(String key)的公共方法,允许外部类交换卡片...就像这样:

// code corrected
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Registration extends JPanel {
   // use these same constants as button texts later
   private static final Dimension PREF_SIZE = new Dimension(450, 300);
   public static final String USER_AGREEMENT = "User Agreement";
   public static final String USER_INFO = "User Information";
   public static final String ENROLLMENT = "Enrollment";
   // we'll extract them from this array
   public static final String[] KEY_TEXTS = {USER_AGREEMENT, USER_INFO, ENROLLMENT};
   private CardLayout cardlayout = new CardLayout();
   private JPanel cards = new JPanel(cardlayout);

   public Registration() {
      cards.add(createUserAgreePanel(), USER_AGREEMENT);
      cards.add(createUserInfoPanel(), USER_INFO);
      cards.add(createEnrollmentPanel(), ENROLLMENT);
      setLayout(new BorderLayout());
      add(cards, BorderLayout.CENTER);
   }

   @Override
   public Dimension getPreferredSize() {
      return PREF_SIZE;
   }

   private JPanel createEnrollmentPanel() {
      JPanel enrol = new JPanel();
      enrol.add(new JLabel("Enrollment"));
      return enrol;
   }

   private JPanel createUserAgreePanel() {
      JPanel userAgree = new JPanel();
      userAgree.add(new JLabel("User Agreement"));
      return userAgree;
   }

   private JPanel createUserInfoPanel() {
      JPanel userInfo = new JPanel();
      userInfo.add(new JLabel("User Information"));
      return userInfo;
   }

   public void swapView(String key) {
      cardlayout.show(cards, key);
   }

}

通过在这个类的可视化实例上调用swapView,传递适当的键字符串(例如在这种情况下是CardTest.USER_INFO),外部类可以简单地交换视图以显示用户信息JPanel。

现在您遇到了这段代码的问题,我在注释中指出:

    jButtonAgree.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent e) {
            Registration reg = new Registration(); // **** HERE *****
            LayoutManager cards = reg.getCards().getLayout();
            ((CardLayout) cards).show(reg.getCards(),"step1");
        }
    });
在那一行代码中,你正在创建一个新的Registration对象,很可能与在GUI上可视化的对象完全不相关,因此在这个新对象上调用方法对当前查看的GUI没有任何影响。相反,你需要获取对可视化的Registration对象的引用,可能通过为这个类提供一个getRegistration方法,然后调用它的方法,如下所示:
class OutsideClass {
   private Registration registration;
   private JButton jButtonAgree = new JButton("Agree");

   public OutsideClass() {
      jButtonAgree.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            // make sure registration reference has been obtained first!
            if (registration != null) { 
               registration.swapView(Registration.USER_AGREEMENT);
            }
         }
      });
   }

   // here I allow the calling class to pass a reference to the visualized
   // Registration instance.
   public void setRegistration(Registration registration) {
      this.registration = registration;
   }
}
例如:
@SuppressWarnings("serial")
class ButtonPanel extends JPanel {
   private Registration registration;

   public ButtonPanel() {
      setLayout(new GridLayout(1, 0, 10, 0));
      // go through String array making buttons
      for (final String keyText : Registration.KEY_TEXTS) {
         JButton btn = new JButton(keyText);
         btn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
               if (registration != null) {
                  registration.swapView(keyText);
               }
            }
         });
         add(btn);
      }
   }

   public void setRegistration(Registration registration) {
      this.registration = registration;
   }
}

还有驱动所有这些的 MainClass

class MainClass extends JPanel {
   public MainClass() {
      Registration registration = new Registration();
      ButtonPanel buttonPanel = new ButtonPanel();
      buttonPanel.setRegistration(registration);

      buttonPanel.setBorder(BorderFactory.createTitledBorder("Button Panel"));
      registration.setBorder(BorderFactory.createTitledBorder("Registration Panel"));

      setLayout(new BorderLayout());
      add(registration, BorderLayout.CENTER);
      add(buttonPanel, BorderLayout.SOUTH);
   }

   private static void createAndShowUI() {
      JFrame frame = new JFrame("Registration");
      frame.getContentPane().add(new MainClass());
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      java.awt.EventQueue.invokeLater(new Runnable() {
         public void run() {
            createAndShowUI();
         }
      });
   }
}

非常有帮助!非常感谢!这个问题已经困扰我很多天了...哈哈... - Shuyi
我希望这篇文章能够得到更高的评分。 - Zavior
1
但是如果我的JPanel是一个单独的文件呢?这意味着我每次创建JPanel对象时都必须传递cardsLayout或cards JPanel吗? - zygimantus

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