简体   繁体   English

使用JComboBox更改/更新JTable内容(类别)

[英]Change/Update JTable content with JComboBox(category)

I have a problem with my JTable. 我的JTable有问题。 My JTable displays content of a database. 我的JTable显示数据库的内容。 One database table has the name category. 一个数据库表具有名称类别。 Every category is displayed in the JComboBox. 每个类别都显示在JComboBox中。 If I click on a category it should update the table content. 如果单击类别,则应该更新表内容。

Here is a short snipped of my code for you, so it is easier to help me. 这是我的代码的简短摘要,因此可以更轻松地为我提供帮助。 The code should be runable: 该代码应可运行:

(TestClass - Main) (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 if required (you need it to execute the code!)) (如果需要,则为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;
    }

}

With this short code the table freeze if you change the category. 使用此短代码,如果更改类别,表格将冻结。 At my whole code,t it freeze too, but I am able to see the updated Table in the background when I resize the window (table resize to the same size as the frame). 在我的整个代码中,它也冻结了,但是当我调整窗口大小时(表调整为与框架相同的大小),我能够在后台看到更新的Table。 I don't know why it isn't at the snipped. 我不知道为什么它不被抢断。

EDIT: The problem to change the content has been solved. 编辑:更改内容的问题已解决。 The source has been updated. 源已更新。 But the problem to get the right table size hasent been solved yet. 但是获得正确表大小的问题已经解决。 In the source first I use a 3 row array and after that a 2 row array. 在源代码中,首先使用3行数组,然后使用2行数组。 I want to delete the old table and create a new one, so the row size is right. 我想删除旧表并创建一个新表,所以行大小正确。

Basically I just want to update the table with new content. 基本上,我只想用新内容更新表。

  • Thank you for Help! 谢谢你的帮助!

The code is buggy because every time actionPerformed() is called, you are creating a new component: 该代码有错误,因为每次调用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();

(Note: There is an additional bug, @mKorbel mentioned it). (注意:还有一个错误,@ mKorbel提到了)。

However you have already added a JScrollPane with a JTable to the frame and those continue to exist. 但是,您已经在框架中添加了带有JTableJScrollPane ,并且它们仍然存在。 (if you try to resize the window you will see the new table beneath the old one). (如果您尝试调整窗口大小,则会在旧表下方看到新表)。

The correct way to update the table data is to get its TableModel make any modifications required in the model and then depending on what you changed you will fire the apporpriate fireXXX() method to notify the table to redraw itself. 更新表数据的正确方法是让其TableModel进行模型中所需的任何修改,然后根据您所做的更改,触发适当的fireXXX()方法来通知表重新绘制自身。

As a crude example your code would be: 作为一个粗略的示例,您的代码将是:

@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
    }
    ...

Update 1: Your problem with your new code has fixed the way that you update the data in the model. 更新1:新代码的问题已修复了更新模型中数据的方式。 However you have a logical flaw when you update the data structure. 但是,更新data结构时存在逻辑缺陷。 This variable starts as an array of 3 rows. 此变量以3行的数组开始。 In the actionPerformed() method you perform a loop for the length of newdata list which only has 2 entries. actionPerformed()方法中,对只有2个条目的newdata列表的长度执行循环。 So you update only the first 2 rows of your model. 因此,您仅更新模型的前2行。

Update 2: It seems that you are missing the point. 更新2:似乎您错过了重点。 How you update your model matters here. 在这里,如何更新模型很重要。 The table will display whatever data your model has. 该表将显示您的模型拥有的所有数据。 If you only update 2 rows but leave the 3rd one unmodified then the table will display 3 rows (2 new ones and an old one). 如果您仅更新2行,但不更改第3行,则该表将显示3行(新2行和旧1行)。 Since you need to change each time all the data then you need to completely replace the data in the model . 由于每次都需要更改所有数据,因此需要完全替换模型中的数据 It is your data that need to be re-created each time not the table. 每次都需要重新创建您的数据,而不是表。 See the update code example. 请参阅更新代码示例。 I have added the actionPerformed() method that re-initializes the data with your current source code. 我添加了actionPerformed()方法,该方法使用您当前的源代码重新初始化数据。 Please read the inline comments. 请阅读内联注释。

Try below code after you change the data in jtable. 更改jtable中的数据后,请尝试以下代码。

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

where model is the tablemodel object and table is JTable object 其中model是tablemodel对象,而table是JTable对象

I hope it helps!!! 希望对您有所帮助!!!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM