1

JTable に問題があります。My JTable はデータベースのコンテンツを表示します。1 つのデータベース テーブルには名前カテゴリがあります。すべてのカテゴリが JComboBox に表示されます。カテゴリをクリックすると、テーブルの内容が更新されます。

これが私のコードの短い抜粋ですので、私を助けるのは簡単です. コードは実行可能である必要があります。

(TestClass - メイン)

package test;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;

import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;

public class TestClass implements ActionListener{

    String[] header = {"head", "head", "head"};
    Object[][] data = {{Boolean.FALSE, "text", "text"}, {Boolean.FALSE, "text", "text"}, {Boolean.FALSE, "text", "text"}};

    LinkedList<String> newdata = new LinkedList<String>();

    String[] combolist = {"apple", "banana", "cranberry"};

    JComboBox<String> combobox = new JComboBox<String>(combolist);
    JTable table = new JTable(new TestTableModel(data, header));
    JFrame frame = new JFrame();
    JPanel panel = new JPanel(new GridLayout(1, 0, 1, 0));

    public TestClass() {
        combobox.addActionListener(this);
        panel.add(combobox);

        frame.add(panel, BorderLayout.NORTH);
        frame.add(new JScrollPane(table), BorderLayout.CENTER);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
        frame.pack();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == this.combobox) {
            JComboBox<String> combobox = this.combobox;

            newdata.add("Test1");
            newdata.add("Test2");

            TestTableModel model = (TestTableModel) table.getModel();

            int i = 0;
            for (String text : newdata) {
                data[i][0] = Boolean.TRUE;
                data[i][1] = text;
                data[i][2] = text;
                i++;
            }

            model.setData(data);
        }
    }

    public static void main(String[] args) {
        new TestClass();
    }
}

(TestTableModel - 必要に応じて AbstractTableModel (コードを実行するために必要です!))

package test;

import javax.swing.table.AbstractTableModel;

public class TestTableModel extends AbstractTableModel {
    private static final long serialVersionUID = 5044877015250409328L;

    private String[] header;
    private Object[][] data;

    public TestTableModel(Object[][] data, String[] header) {
        this.header = header;
        this.data = data;
    }

    public void setData(Object[][] data) {
        this.data = data;
        fireTableDataChanged();
    }

    @Override
    public Class<?> getColumnClass(int column) {
        if (column == 0) {
            return Boolean.class;
        }
        return super.getColumnClass(column);
    }

    @Override
    public int getColumnCount() {
        return header.length;
    }

    @Override
    public String getColumnName(int column) {
        return header[column];
    }

    @Override
    public int getRowCount() {
        return data.length;
    }

    @Override
    public Object getValueAt(int row, int column) {
        return data[row][column];
    }

    @Override
    public boolean isCellEditable(int row, int column) {
        return column == 0;
    }

    @Override
    public void setValueAt(Object value, int row, int column) {
        data[row][column] = value;
    }

}

この短いコードを使用すると、カテゴリを変更するとテーブルがフリーズします。コード全体でもフリーズしますが、ウィンドウのサイズを変更すると、更新されたテーブルがバックグラウンドで表示されます (テーブルはフレームと同じサイズにサイズ変更されます)。なぜそれが切り取られていないのかわかりません。

編集: コンテンツを変更する問題は解決されました。ソースが更新されました。しかし、適切なテーブル サイズを取得するという問題はまだ解決されていません。ソースでは、最初に 3 行の配列を使用し、その後 2 行の配列を使用します。古いテーブルを削除して新しいテーブルを作成したいので、行サイズは適切です。

基本的に、テーブルを新しいコンテンツで更新したいだけです。

  • ご協力ありがとう御座います!
4

2 に答える 2

1

が呼び出されるたびactionPerformed()に新しいコンポーネントを作成しているため、コードにバグがあります。

table = new JTable(new TestTableModel(data, header));
frame.add(new JScrollPane( table ));  // <-- BTW: here you need to put the table otherwise you are adding an empty JScrollPane
frame.validate();

(注: 追加のバグがあります。@mKorbel が言及しています)。

ただし、既にフレームに を追加しておりJScrollPaneJTableそれらは引き続き存在します。(ウィンドウのサイズを変更しようとすると、古いテーブルの下に新しいテーブルが表示されます)。

テーブルデータを更新する正しい方法は、モデルTableModelに必要な変更を加えてから、変更内容に応じて適切なメソッドを起動して、テーブル自体を再描画するように通知することです。fireXXX()

大まかな例として、コードは次のようになります。

@Override
public void actionPerformed(ActionEvent e) {
    if (e.getSource() == this.combobox) {
        JComboBox<String> combobox = this.combobox;

        newdata.clear();    // Clear your list or create a new one otherwise data will keep piling up.  
        newdata.add("Test1");
        newdata.add("Test2");

        TestTableModel model = (TestTableModel) table.getModel();

        // Since you need to replace the whole data create a new Object[][] each time
        Object[][] newModelData = new Object[newdata.size()][3];

        // Set whatever data to the new array
        int i = 0;
        for (String text : newdata) {
            newModelData[i][0] = Boolean.TRUE;
            newModelData[i][1] = text;
            newModelData[i][2] = text;
            i++;
        }

        // replace all data of the current model
        model.setData(newModelData);
    }
}
....

// Now inside your table model:
    ...
    @Override
    public Class<?> getColumnClass(int column) {
    // if (column == 0) {   
    //     return Boolean.class;             // <-- this produces a ClassCastException with the data you aretrying to set
    // }
       return super.getColumnClass(column);
    }

    public void setData(Object[][] data) {
        this.data = data;       //  <-- Update the data
        fireTableDataChanged(); //  <-- fire the event so the table is notified. If you change only one cell you need to call the appropriate fire event
    }
    ...

更新 1:新しいコードの問題により、モデル内のデータを更新する方法が修正されました。dataただし、構造を更新するときに論理的な欠陥があります。この変数は、3 行の配列として始まります。メソッドでは、エントリが 2 つしかないリストactionPerformed()の長さのループを実行します。newdataしたがって、モデルの最初の 2 行のみを更新します。

更新 2:ポイントを見逃しているようです。ここでは、モデルをどのように更新するかが重要です。テーブルには、モデルが持つデータがすべて表示されます。2 行だけを更新して 3 行目を変更しない場合、テーブルには 3 行 (新しい 2 行と古い行 1 行) が表示されます。すべてのデータを毎回変更する必要があるため、モデル内のデータを完全に置き換える必要があります。テーブルではなく、毎回再作成する必要があるのはデータです。更新コードの例を参照してください。actionPerformed()現在のソース コードでデータを再初期化するメソッドを追加しました。インラインコメントを読んでください。

于 2013-08-09T12:21:23.667 に答える
-1

jtable のデータを変更した後、以下のコードを試してください。

model.fireTableDataChanged(); table.repaint();

ここで、model は tablemodel オブジェクトで、table は JTable オブジェクトです

役に立てば幸いです!!!

于 2013-08-09T11:56:22.940 に答える