2013-08-09 2 views
0

У меня проблема с моей JTable. Мой JTable отображает содержимое базы данных. Одна таблица базы данных имеет категорию имен. Каждая категория отображается в JComboBox. Если я нажму на категорию, она должна обновить содержимое таблицы.Изменение/обновление содержимого JTable с помощью JComboBox (категория)

Вот короткий код моего кода для вас, поэтому мне легче помочь. Код должен быть runable:

(TestClass - Main)

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; 
    } 

} 

С помощью этого короткого кода при изменении категории таблица замерзает. Во всем моем коде он тоже замораживается, но я могу видеть обновленную таблицу в фоновом режиме при изменении размера окна (изменение размера стола до того же размера, что и рамка). Я не знаю, почему это не на отрыве.

EDIT: Проблема с изменением содержимого была решена. Источник обновлен. Но проблема в том, чтобы получить правильный размер таблицы hasent еще не решена. Вначале я использую массив из 3 строк, а затем массив из 2 строк. Я хочу удалить старую таблицу и создать новую, поэтому размер строки правильный.

В принципе, я просто хочу обновить таблицу новым контентом.

  • Благодарим за помощь!
+0

Я не вижу таблицу классов, код не может быть компилируемым table = new JTable (новая таблица (данные, заголовок)); – mKorbel

+0

Woops Мне жаль, что подожди минутку – Gerret

+0

в дополнение к ответу: ваш model.setValueAt неправильно реализован, он _must_ уведомляет своих слушателей об изменении! – kleopatra

ответ

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 упомянул).

Однако вы уже добавили JScrollPane к раме, и они продолжают существовать. (если вы попытаетесь изменить размер окна, вы увидите новую таблицу под старой).

Правильный способ обновить данные таблицы, чтобы получить его TableModel сделать какие-либо изменения требуется в модели, а затем в зависимости от того, что вы изменили вы будете стрелять метод apporpriate 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 
    } 
    ... 

Update 1: Ваша проблема с вашим новым кодом закрепил так, что при обновлении данных в модели.Однако у вас есть логический недостаток при обновлении структуры data. Эта переменная начинается как массив из 3 строк. В методе actionPerformed() вы выполняете цикл для длины списка newdata, который имеет только 2 записи. Таким образом, вы обновляете только первые 2 строки вашей модели.

Обновление 2: Кажется, что вам не хватает точки. Как вы обновляете свою модель. В таблице будут отображаться все данные вашей модели. Если вы обновляете только 2 строки, но оставляете 3-й вариант без изменений, таблица отображает 3 строки (2 новых и одну). Поскольку вам нужно каждый раз менять все данные, то вам нужно будет полностью заменить данные в модели. Это ваши данные, которые нужно воссоздавать каждый раз, а не таблицу. См. Пример кода обновления. Я добавил метод actionPerformed(), который повторно инициализирует данные с помощью вашего текущего исходного кода. Пожалуйста, прочитайте встроенные комментарии.

+0

Мне очень жаль испорченный код, я перепутал что-то новое с моим исходным кодом и получил ошибки. Благодарим вас за помощь, но здесь у меня такая же проблема, как и код mKorbel. Я изменил код сейчас с вашим предложением и один из mKorbel, но, как я сказал, если бы у меня было 4 строки и получить только 2 сейчас из базы данных, он меняет только 2, остальные 2 - старые. Pls попробуйте еще раз запустить код и изменить категорию, чтобы вы поняли, что я имею в виду! – Gerret

+0

Эта логика сама по себе является кодом, но не существует универсальных уведомлений, есть два способа: 1. нотификаторы на стороне БД, которые возвращают только изменения с правильными координатами или 2. создают эти уведомления на стороне Java, зацикливают внутри ResultSet и сопоставление, если оно равно значению, хранящемуся в XxxTableModel – mKorbel

+0

Почему мне нужен уведомитель? Фактически я хочу новую таблицу с моими новыми данными, и мне придется удалить старый. Вы пробовали новый код? Я использовал ваше предложение, оно работает нормально, но проблема только в том, что есть старая строка со старыми данными. В принципе мне нужен новый JTable с правильным количеством строк (col everytime same) – Gerret

-1

Попробуйте ввести код после изменения данных в jtable.

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

где модель является объектом TableModel и таблица JTable объект

Я надеюсь, что это помогает !!!

+0

Надеюсь, это поможет !!! ---> не ................ – mKorbel

+0

хорошо, что я не могу работать, это не отвечает на мой вопрос. Потому что я спросил, как я могу изменить данные. Вы говорите мне, как я уведомляю слушателей и так далее. Но спасибо вам в любом случае. – Gerret

+0

-1: модель с хорошим характером _must_ уведомляет своих слушателей об изменениях. Если ручное уведомление от имени модели или ручной перерисовки представления, похоже, решает проблему, либо модель неправильно или неправильно используется. – kleopatra