0

クラスClickの配列リストを保存しようとすると、次のエラーが発生します:java.io.NotSerializableException:javax.swing.text.DefaultHighlighter $ LayeredHighlightInfo on this line:os.writeObject(saveList);。Clickクラスの実装をシリアライズ可能にしましたが。誰かがこれの原因を知っていますか?

これが私の保存方法です:

public static void saveArray(ArrayList<Click> saveList) {
        JFileChooser c = new JFileChooser();
        c.showSaveDialog(new JFrame());
        File f = c.getSelectedFile();
        try {
            ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(
                                f.getAbsolutePath()));
            os.writeObject(saveList);
        } catch (IOException e1) {
        e1.printStackTrace();
    }
}

そして、これが私のClickクラスです。

public static class Click implements Serializable {
    JTextField xClickField;
    JTextField yClickField;
    JTextField clickIntervalField;
    JTextField repeatTimesField;
    boolean isLeft;
    Integer clickX;
    Integer clickY;
    Integer clickInterval;
    Integer clickTimes;

    public Click(boolean left){
        xClickField = new JTextField();
        yClickField = new JTextField();
        clickIntervalField = new JTextField();
        repeatTimesField = new JTextField();
        clickX = 0;
        clickY = 0;
        clickInterval = 0;
        clickTimes = 0;
        isLeft = left;
        addToJPanel();
    }

    public void addToJPanel() {
        xClickField.setText(clickX.toString());
        yClickField.setText(clickY.toString());
        clickIntervalField.setText(clickInterval.toString());
        repeatTimesField.setText(clickTimes.toString());
        panel.add(xClickField);
        panel.add(yClickField);
        panel.add(clickIntervalField);
        panel.add(repeatTimesField);

        frame.setVisible(false);
        frame.setVisible(true);
    }

    public void removeFromJPanel() {
        panel.remove(xClickField);
        panel.remove(yClickField);
        panel.remove(clickIntervalField);
        panel.remove(repeatTimesField);

        frame.setVisible(false);
        frame.setVisible(true);
    }
}

ちなみに、Clickクラスからコードのチャンクを取り出しました。したがって、エラーがコードのその部分にある可能性があると思われる場合は、喜んで追加します。

前もって感謝します!

4

4 に答える 4

2

オブジェクトを直列化可能にするには、Serializable を実装するだけでは不十分です。たとえば、Socket はシリアル化できません。ソケットをシリアル化しても意味がありません。したがって、タイプのフィールドを持ち、を実装するFooクラスがある場合、インスタンスをどのようにシリアル化するつもりですか。うまくいきません。シリアライズ可能なオブジェクトのすべてのフィールドも、再帰的にシリアライズ可能でなければなりません。SocketSerializableFoo

また、Hovercraft がコメントで述べているように、Swing コンポーネントではなく、データをシリアル化する必要があります。

于 2012-06-30T17:08:50.383 に答える
2

JTextField やその他の Swing コンポーネントをシリアライズしていますが、これは時間とリソースの無駄であり、まったく不要です。クラスのフィールドが保持するデータである GUI の状態をシリアル化する必要があります。MVC を理解している場合は、ビューではなくモデルをシリアル化する必要があります。MVC を理解していない場合は、Google で検索するか、この記事を読んで主要な概念を学んでください。どの言語でも GUI プログラムを作成するための鍵となります。

また、私のお金のために、JAXB またはその他の XML ベースのツールを使用して、データをテキスト形式で保存し、読み取ったときに理解できるようにシリアル化します。

GUI をモデルから分離し、プロパティ変更リスナーを使用してプロパティの変更をリッスンして応答する例:

import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;

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

public class SimpleClickEg {
   private static void createAndShowGui() {
      SimpleClickPanel clickPanel = new SimpleClickPanel();

      JFrame frame = new JFrame("SimpleClickEg");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(clickPanel);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

class SimpleClickPanel extends JPanel {
   private static final int PREF_WIDTH = 800;
   private static final int PREF_HIEGHT = 600;
   private JTextField clickCountField = new JTextField(5);
   private JTextField clickXField = new JTextField(5);
   private JTextField clickYField = new JTextField(5);
   private SimpleClick click = new SimpleClick();

   public SimpleClickPanel() {
      add(new JLabel("Click X:"));
      add(clickXField);
      add(new JLabel("Click Y:"));
      add(clickYField);
      add(new JLabel("Click Count:"));
      add(clickCountField);

      addMouseListener(new MouseAdapter() {
         @Override
         public void mousePressed(MouseEvent e) {
            click.setClickPoint(e.getPoint());
         }
      });

      click.addPropertyChangeListener(new PropertyChangeListener() {

         @Override
         public void propertyChange(PropertyChangeEvent evt) {
            if (SimpleClick.CLICK_COUNT.equals(evt.getPropertyName())) {
               clickCountField.setText(String.valueOf(click.getClickCount()));
            } else if (SimpleClick.CLICK_X.equals(evt.getPropertyName())) {
               clickXField.setText(String.valueOf(click.getClickX()));
            } else if (SimpleClick.CLICK_Y.equals(evt.getPropertyName())) {
               clickYField.setText(String.valueOf(click.getClickY()));
            }
         }
      });
   }

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

   public SimpleClick getClick() {
      return click;
   }
}

class SimpleClick implements Serializable {
   private static final long serialVersionUID = 1L;
   public static final String CLICK_COUNT = "click count";
   public static final String CLICK_X = "click x";
   public static final String CLICK_Y = "click y";

   private int clickCount;
   private int clickX;
   private int clickY;
   private transient SwingPropertyChangeSupport spcSupport = new SwingPropertyChangeSupport(
         this);

   public int getClickCount() {
      return clickCount;
   }

   public void setClickCount(int clickCount) {
      Integer oldValue = this.clickCount;
      Integer newValue = clickCount;
      this.clickCount = newValue;
      spcSupport.firePropertyChange(CLICK_COUNT, oldValue, newValue);
   }

   public void incrementClickCount() {
      setClickCount(getClickCount() + 1);
   }

   public void setClickPoint(Point p) {
      setClickX(p.x);
      setClickY(p.y);
      incrementClickCount();
   }

   public int getClickX() {
      return clickX;
   }

   public void setClickX(int clickX) {
      Integer oldValue = this.clickX;
      Integer newValue = clickX;
      this.clickX = newValue;
      spcSupport.firePropertyChange(CLICK_X, oldValue, newValue);
   }

   public int getClickY() {
      return clickY;
   }

   public void setClickY(int clickY) {
      Integer oldValue = this.clickY;
      Integer newValue = clickY;
      this.clickY = newValue;
      spcSupport.firePropertyChange(CLICK_Y, oldValue, newValue);
   }

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

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

}
于 2012-06-30T17:13:22.457 に答える
1

ご覧のとおり、エラーjavax.swing.text.DefaultHighlighterはシリアル化できないことを明確に示しています。

JTextField現在、このクラスは、GUI コンポーネントである内のコンポジションによって使用されており、シリアル化することを意図していません。コードから、フィールド自体をシリアル化する必要はないように思われるので、フィールドをマークするだけtransientで完了です。

補足として、データだけを簡単にシリアル化し、GUI に関することはすべて忘れられるように、データと GUI を分割することは常に良いことです。これは、シリアライゼーションだけでなく、一般的に、カプセル化を維持し、OOP を意図したとおりに使用するのに役立ちます。

于 2012-06-30T17:08:21.217 に答える
1

問題は、Clickクラスに JTextField インスタンスへの参照があり、これらに (おそらく) DefaultHighlighter.LayeredHighlightInfo... という名前の Swing クラスへの参照があり、それがシリアル化できないことです。

おそらく、4 つのJTextField変数を として宣言する必要がありますtransient。原則として、Swing コンポーネントなどの Java GUI クラスは効果的に直列化できません。

于 2012-06-30T17:08:52.090 に答える