4

この投稿の長さについて事前にお詫び申し上げますが、プログラムの設計と実装についてかなり詳細に説明しました。

バックグラウンド

私は現在、大学で3年目のコンピュータサイエンスコースのグループ(2人)プログラミングプロジェクトを行っています。このプログラムの目的は、基本的にスプレッドシートプログラムを使用して、各XMLファイルが履歴レコードであるXMLファイルデータを表すことです。

設計:

スプレッドシートの各レコード(行)は単一のXMLファイルに対応し、レコードの列はXMLファイルの要素に対応します。セルコンポーネントをボタンに設定することで、繰り返される要素(つまり、同じタグを持つ要素)を処理します。ボタンをクリックすると、(対応するファイルの)繰り返される名前を持つすべての要素のリストを含む別のスプレッドシートが開きます。子要素は同様の方法で処理されます。要素に子要素がある場合、XMLファイルの対応するセルにはボタンが含まれ、クリックすると、その要素のすべての子要素を含むスプレッドシートが開きます。

実装:

私たちのシステムの実装はJavaで書かれています。メインクラス(名前SpreadSheetGUI)は、JTableを追加するJFrameを拡張します(デフォルトのテーブルモデルを使用)。3つの異なるセルレンダラーがあります。1つはセルにテキストがある場合、1つはセルにボタンがある場合、もう1つはセルにテキストとボタンがある場合です。ボタンをクリックして新しいスプレッドシート(​​子要素または繰り返し要素名のいずれか)を開くと、スプレッドシートコンストラクターが再帰的に呼び出され、サブスプレッドシートが作成されます。レンダラーは次の順序で追加されます。セルが、ボタンがセルに追加されたときに複数回使用されるタグを持つ要素に対応する場合、それ以外の場合、セルが子ノードを持つ要素に対応する場合、テキストとボタンをセルに追加し、セルにテキストがある場合は、そのセルにテキストを追加します。

GUIのコンストラクターはそれ自体です

        /**
     * Parameterised constructor
     * @param dataVector - Vector of vectors of objects that represent the cell values
     * @param columnNames - The vector of objects that represent the column names
     */
    @SuppressWarnings("unchecked")
    public SpreadSheetGUI(Vector<Vector<LevelElementT>> dataVector, Vector<String> columnNames, boolean hasRepeatedColumns, boolean initialFrame)
    {           
        this.hasRepeatedColumns = hasRepeatedColumns;
        this.initialFrame = initialFrame;

        if (initialFrame)
            populateTable(dataVector, columnNames);

        else if (!hasRepeatedColumns)
            populateTable((Vector<Vector<LevelElementT>>)findRepeatedColumns(dataVector).get(0),
                    (Vector<String>)findRepeatedColumns(dataVector).get(1));

        else
            populateTable(dataVector, columnNames);
        //Get repeated column names and add to repeated column hashmap
        //parseElements(dataVector);
    }

ここで、populateTableメソッドはテーブルモデルを初期化します。先に述べたように、セルには3つの異なるレンダラーとエディターがあり、2つのレンダラーにはボタンがあり、クリックすると新しいスプレッドシートを作成します(つまり、スプレッドシートコンストラクターを呼び出します)。セルエディタには次のコードがあります

             public Object getCellEditorValue() 
          {
              if (isPushed)
              {
                    //will have the child elements of the current cell element
                Vector<Vector<LevelElementT>> children = new Vector<Vector<LevelElementT>>();
                children.add(new Vector<LevelElementT>());

                List<Element> tempChildren = elements.get(row).get(column).getChildren();

                for (Element child : tempChildren)
                    children.get(0).add(new LevelElementT(child));
                //creates our subspreadsheet
                new Thread(new SpreadSheetGUI(children, new Vector<String>(), false, false)).start();
              }

              isPushed = false;
              return new String(bLabel);
          }

LevelElementTは、toStringメソッドをオーバーライドするElement(JDOM2パッケージに含まれる)を拡張するために作成したクラスです。

問題:

前に述べたように、セルへのボタンの追加を処理するレンダラーのセットを作成しましたが、「子」スプレッドシートが作成されると、レンダラーは子スプレッドシート番号に従って範囲外のセルをレンダリングしようとしているようです。行と列の数を増やし、配列インデックスを範囲外の例外としてスローします。

より具体的には、エラーは、populateTable()メソッドから取得した次のコードでスローされます。defaultTableModelのインスタンスを使用してJTableを初期化し、各コンポーネントのレンダラーを決定するメソッドを設定します

            table = new JTable(tableModel)
        {
            private static final long serialVersionUID = 1L;

            public TableCellRenderer getCellRenderer(int row, int column)
            {
                //System.out.println(elements.get(row).get(column).getChildren().size());
                if (column == 0)
                {
                    Class<? extends Object> cellClass = getValueAt(row, column).getClass();
                    return getDefaultRenderer(cellClass);
                }
                else if(repeatedColumns.containsKey(table.getColumnModel().getColumn(column).getIdentifier() + " " + elements.get(row).get(0).getText()))
                        return getDefaultRenderer(JButton.class);

                else if(!elements.get(row).get(column).getChildren().isEmpty())
                        return getDefaultRenderer(JPanel.class);

                else 
                        return getDefaultRenderer(JTextArea.class);
            }

            public TableCellEditor getCellEditor(int row, int column)
            {
                if (column == 0)
                {
                    Class<? extends Object> cellClass = getValueAt(row, column).getClass();
                    return getDefaultEditor(cellClass);
                }
                else if(repeatedColumns.containsKey(table.getColumnModel().getColumn(column).getIdentifier() + " " + elements.get(row).get(0).getText()))
                        return getDefaultEditor(JButton.class);

                else if(!elements.get(row).get(column).getChildren().isEmpty())
                        return getDefaultEditor(JPanel.class);

                else 
                        return getDefaultEditor(JTextArea.class);
            }
        };

エラーはifステートメント(クリックしたボタンによって異なります)でスローされますが、要素(levelElementsの2次元ベクトル)またはrepeatedColumns(文字列をキーとして要素のベクトルをキーとするハッシュテーブル)が原因ではありません。値)。


問題は、スプレッドシートコンストラクターを再帰的に呼び出しているという事実にあると思います。友人はまた、この問題はデフォルトのテーブルモデルが原因である可能性があると提案しましたが、カスタムテーブルモデルの作成を検討する必要がありますか?

コードがかなり長いため(合計で約2000行)、コードを含めていませんが、リクエストに応じて提供したいと思います。私はこれで頭を悩ませてきましたが、この問題に関連するスレッドを見つけるのに完全に失敗しました。

4

2 に答える 2

2

コードが提供されていないので、私は推測しています:

  • 再帰呼び出しは、正しく返されない場合にこれを引き起こす可能性があります。私たちはあなたが正確に何をしているのかわかりません...

  • この現象は、子テーブルではなく、親テーブルのセルをレンダラーに誤って渡すことによっても発生する可能性があります。

これらをデバッグします。しかし、繰り返しになりますが、コードスニペットがなければ、答えるのは本当に難しいと思います。

これがお役に立てば幸いです。:)

于 2012-09-19T17:34:37.400 に答える
0

new SpreadSheetGUI(children, new Vector<String>(), false, false)その後、新しいベクターに正常にアクセスできなくなるため、疑わしい(推測のみ)。

.get(row).get(column)インデックスチェックの規定はありません。特に、すべての行に十分な文字列があるかどうか。

DefaultTableModelで十分です。

ベクターはスレッドセーフですが、かなり古いものです。同時実行性のあるList/ArrayListを使用する方が印象的です:CopyOnWriteArrayList

XMLテーブルモデルとツリーテーブルモデルはすでに存在します。プログラミングに関するあなたの要件についてはわかりません。

スタックトレース、ブレークポイント、デバッグ、IDEが役立つはずです。NetBeans IDEは簡単で、EclipseIDEはより広く普及しています。

于 2012-09-24T13:31:41.113 に答える