2

请看下面的代码

package test;


import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.*;
import javax.swing.event.SwingPropertyChangeSupport;

public class MainGui {
   public MainGui() {
      new WizardPanel().setVisible(true);
   }

   public static void main(String[] args) {
      try {
         UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
         new MainGui();
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}

class WizardPanel extends JDialog {
   private JPanel cardPanel, buttonPanel;
   private JButton next;
   private CardLayout c1;
   private SimpleModel simpleModel = new SimpleModel();

   private FileSelector fileSelector;
   private DelemeterSelector delemeterSelector;

   public WizardPanel() {
      fileSelector = FileSelector.getInstance();
      delemeterSelector = DelemeterSelector.getInstance();

      fileSelector.setModel(simpleModel); //!!
      delemeterSelector.setModel(simpleModel); //!!

      cardPanel = new JPanel();
      c1 = new CardLayout();
      cardPanel.setLayout(c1);

      cardPanel.add(fileSelector, "1");
      cardPanel.add(delemeterSelector, "2");

      c1.show(cardPanel, "1");

      buttonPanel = new JPanel();
      buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));

      next = new JButton("Next");
      next.addActionListener(new WizardPanel.NextButtonAction()); 

      buttonPanel.add(next);

      // Creating the GUI
      this.setLayout(new BorderLayout());
      this.add(cardPanel, "Center");
      this.add(buttonPanel, "South");

      this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      this.setResizable(true);
      this.pack();
      this.setVisible(true);

   }

   private class NextButtonAction implements ActionListener {
      public void actionPerformed(ActionEvent ae) {

         // c1.show(cardPanel, "2");
         c1.next(cardPanel); //!!

      }
   }
}

class FileSelector extends JPanel {
   private JLabel fileName, description;
   private JTextField fileTxt;
   private JButton browse;

   private GridBagLayout gbl;
   private GridBagConstraints gbc;
   private SimpleModel simpleModel;

   private static FileSelector instance = null;

   private FileSelector() {
      // Intializing instance variables
      fileName = new JLabel("File Name: ");
      description = new JLabel("Specify the source of the data");

      fileTxt = new JTextField(10);

      browse = new JButton("Browse");
      browse.addActionListener(new ActionListener() {

         @Override
         public void actionPerformed(ActionEvent e) {
            if (simpleModel != null) {
               simpleModel.setFileText(fileTxt.getText());
            }
         }
      });

      gbl = new GridBagLayout();
      gbc = new GridBagConstraints();

      // Creating GUI
      this.setLayout(new GridLayout(2,1));

      this.add(description);
      this.add(locationPanel());


      this.setBorder(BorderFactory.createEmptyBorder());
   }

   public void setModel(SimpleModel simpleModel) {
      this.simpleModel = simpleModel;
   }

   private JPanel locationPanel() {
      JPanel panel = new JPanel();
      panel.setLayout(new FlowLayout());

      panel.add(fileName);
      panel.add(fileTxt);
      panel.add(browse);

      return panel;
   }

   public static FileSelector getInstance() {
      if (instance == null) {
         instance = new FileSelector();
      }

      return instance;
   }
}

class DelemeterSelector extends JPanel {
   private JLabel description;
   private JRadioButton tabBtn, semicolanBtn, commaBtn, spaceBtn;
   private JTextArea txtArea;
   private JScrollPane scroll;
   private ButtonGroup btnGroup;

   private GridBagLayout gbl;
   private GridBagConstraints gbc;
   private SimpleModel simpleModel;

   private String str;

   private static DelemeterSelector instance = null;

   private DelemeterSelector() {
      description = new JLabel(
            "What delemeter separates your fields? Select the appropreiate delemeter");

      tabBtn = new JRadioButton("Tab");
      tabBtn.addItemListener(new RadioAction());
      semicolanBtn = new JRadioButton("Semicolan");
      semicolanBtn.addItemListener(new RadioAction());
      commaBtn = new JRadioButton("Comma");
      commaBtn.addItemListener(new RadioAction());
      spaceBtn = new JRadioButton("Space");
      spaceBtn.addItemListener(new RadioAction());

      btnGroup = new ButtonGroup();
      btnGroup.add(tabBtn);
      btnGroup.add(semicolanBtn);
      btnGroup.add(commaBtn);
      btnGroup.add(spaceBtn);

      txtArea = new JTextArea(20, 70);

      scroll = new JScrollPane(txtArea);

      gbl = new GridBagLayout();
      gbc = new GridBagConstraints();

      this.setLayout(new GridLayout(3,1));

      // Creating the GUI
      this.add(description);
      this.add(radioPanel());
      this.add(scroll);      
   }

   private JPanel radioPanel() {
      JPanel panel = new JPanel();
      panel.setLayout(new FlowLayout());

      panel.add(tabBtn);
      panel.add(semicolanBtn);
      panel.add(commaBtn);
      panel.add(spaceBtn);

      panel.setBorder(BorderFactory
            .createTitledBorder("Choose the Delimeter that seperates your fields"));

      return panel;
   }

   //!!
   public void setModel(final SimpleModel simpleModel) {
      this.simpleModel = simpleModel;
      simpleModel.addPropertyChangeListener(new PropertyChangeListener() {

         @Override
         public void propertyChange(PropertyChangeEvent evt) {
            txtArea.append("File Text: " + simpleModel.getFileText() + "\n");            
         }
      });
   }

   public static DelemeterSelector getInstance() {
      if (instance == null) {
         instance = new DelemeterSelector();
      }

      return instance;
   }

   private class RadioAction implements ItemListener
   {
       public void itemStateChanged(ItemEvent ae)
       {
           if(ae.getStateChange()==ItemEvent.SELECTED){
           if(ae.getSource().equals(commaBtn))
           {
               str = ".";
           }
           else if(ae.getSource().equals(spaceBtn))
           {
               str = " ";
           }
           else if(ae.getSource().equals(semicolanBtn))
           {
               str = ";";
           }

           simpleModel.setDelemeter(str);}
       }
   }
}

class SimpleModel {
   public static final String FILE_TEXT = "file text";
   public static final String FILE_DELEMETER = "dELEMETERtext";
   private SwingPropertyChangeSupport pcSupport = 
      new SwingPropertyChangeSupport(this);
   private String fileText;
   private String str;

   public void addPropertyChangeListener(PropertyChangeListener listener) {
      pcSupport.addPropertyChangeListener(listener);
   }

   public void removePropertyChangeListener(PropertyChangeListener listener) {
      pcSupport.removePropertyChangeListener(listener);
   }

   public void setFileText(String fileText) {
      String oldValue = this.fileText;
      String newValue = fileText;
      this.fileText = fileText;
      pcSupport.firePropertyChange(FILE_TEXT, oldValue , newValue);

   }

   public String getFileText() {
      return fileText;
   }

   public void setDelemeter(String str)
   {
       String oldValue = this.str;
      String newValue = str;
      this.str = str;
      pcSupport.firePropertyChange(FILE_DELEMETER, oldValue , newValue);

      System.out.println(str);
   }

}

此代码使用 MVC 设计模式。它从第一个滑动窗口记录 JTextField 的文本。当用户移动到第二个窗口时,它会在 JTextArea 中显示您在第一个窗口中键入的文本。

现在,单击那里分配的任何单选按钮。您将看到 JTextArea 正在显示在第一个窗口中输入的数据,即使我没有在getFileText()那里调用该方法。getFileText()每当我单击 JRadioButton 时,它似乎一直在调用方法并继续更新 JTextArea。但是在 JRadioButton 的动作类中,我从来没有调用过这样的动作,我只是设置了 delemeter !!

为什么会发生这个错误?请帮忙!

4

2 回答 2

3

你的问题是这一行:

  simpleModel.addPropertyChangeListener(new PropertyChangeListener() {

     @Override
     public void propertyChange(PropertyChangeEvent evt) {
        txtArea.append("File Text: " + simpleModel.getFileText() + "\n");            
     }
  });

结合这些:

 public void setFileText(String fileText) {
      String oldValue = this.fileText;
      String newValue = fileText;
      this.fileText = fileText;
      pcSupport.firePropertyChange(FILE_TEXT, oldValue , newValue);

   }

   public void setDelemeter(String str)
   {
       String oldValue = this.str;
      String newValue = str;
      this.str = str;
      pcSupport.firePropertyChange(FILE_DELEMETER, oldValue , newValue);

      System.out.println(str);
   }

您没有检查被触发的属性的名称(在第一组代码中),所以当setFileTextorsetDelemeter被调用时,firePropertyChange将执行并显示文件名。

最简单的解决方案是检查属性的名称,如下所示:

  simpleModel.addPropertyChangeListener(new PropertyChangeListener() {

     @Override
     public void propertyChange(PropertyChangeEvent evt) {
        if(evt.getPropertyName().equale(SimpleModel.FILE_TEXT)
            txtArea.append("File Text: " + simpleModel.getFileText() + "\n");            
     }
  });
于 2012-11-26T15:06:21.883 回答
2

我没有仔细阅读所有代码,但请注意,更改单选按钮时会收到两个事件。我用于取消选择第一个按钮,并用于选择新按钮。

您可以在 中检查状态ItemEvent。参见ItemEvent#getStateChangeandItemEvent.SELECTEDItemEvent.DESELECTED常量。

请注意,如果您只想在选择按钮时触发操作,则将 an 附加ActionListener到单选按钮会更容易。这在单选按钮教程中进行了说明。

于 2012-11-26T14:27:23.233 回答