2

I am struggling to avoid data duplication with multiple JTable. Basically I have a TableModel which has an arraylist of data and a string[] header.

So far nothing new. Now I have another TableModel which has the same arraylist of data BUT a different string[] header.

I can't make my code to work. I would appreciate some idea on how to share the arrayList of data across multiple table model.

So when I change the data all models are updated and there isn't data duplication. I would like to avoid copy of arraylist any idea or am I wrong with this setup? I did try listener but I think going that way we still have data duplication across table model.

public class GymTableModel extends AbstractTableModel {
    private final ResourceBundle name = ResourceBundle.getBundle("labels/TableLabel", Locale.getDefault());
    private final String[] entete = {
        name.getString("LNAME"),
        name.getString("FNAME"),
        name.getString("CONTACT"),
        name.getString("TELFIX"),
        name.getString("TELGSM"),
        name.getString("EMAIL"),
        name.getString("BDATE"),
        name.getString("EDATE"),
        name.getString("LICENSE"),
        name.getString("AGE"),
        name.getString("ANCIEN")
    };

    @Override
    public Class<?> getColumnClass(int columnIndex){
        switch(columnIndex){
            case 6:
                return Date.class;
            case 7:
                return Date.class;
            case 9:
                return Integer.class;
            default:
                return Object.class;
        }
    }

    @Override
    public int getRowCount() {
        return gymList.size();
    }

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

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        switch(columnIndex){
            case 0:
                return gymList.get(rowIndex).getLastName();
            case 1:
                return gymList.get(rowIndex).getFirstName();
            case 2:
                return gymList.get(rowIndex).getContact();
            case 3:
                return gymList.get(rowIndex).getTelFix();
            case 4:
                return gymList.get(rowIndex).getTelGsm();
            case 5:
                return gymList.get(rowIndex).getEmail();
            case 6:
                return gymList.get(rowIndex).getDateBirth();
            case 7:
                return gymList.get(rowIndex).getDateClub();
            case 8:
                return gymList.get(rowIndex).getLicence();
            case 9:
                return gymList.get(rowIndex).getAge();
            case 10:
                return gymList.get(rowIndex).getAnciennete();
            default:
                return null; // should never happen;
        }
    }

    public String getColumnName(int columnIndex){
        return entete[columnIndex];
    }

}

Now I have another table which has same data but only 3 columns (LNAME, FNAME and AGE) so getColumnClass isn't same. Question is, can I share my gymList data (which is an arrayList) with another table model? Thankyou

  • 2
    Some code would be nice :) – christopher Mar 09 '13 at 16:45
  • 1
    Please post your code. – Boris the Spider Mar 09 '13 at 16:46
  • How can we tell without seeing your code? You should be able to use the same list with many references to it. – jlordo Mar 09 '13 at 17:05
  • Normally when you create a TableModel you have two pieces of data, the column names and the data. So if your model is implemented correctly you should not have a problem. Look at the DefaultTableModel as an example. You pass it a Vector of column names and a Vector of data. – camickr Mar 09 '13 at 17:45
  • Camickr, so when passing vector or arraylist of data does java copy this arraylist or is it just a reference? if I have two table model with same data and different columns, would Java make a copy of the data or just create a reference to the same list? – Fabrice Khedadi Mar 09 '13 at 17:57
  • @FabriceKhedadi, it depends on your model. You can either just use the reference to the Vector/ArrayList (which is what the DefaultTableModel does), or you can' create a new Vector/ArrayList and copy the data. – camickr Mar 09 '13 at 20:19

4 Answers4

3

Using Che's answer as a basis for a main table containing four columns then your code should be something like:

AllTableModel model = new AllTableModel();
JTable mainTable = new JTable( model );

If you want another View of the model then you create a new view not a new model. So the code would be:

JTable studentTable = new JTable( model );
studentTable.removeColumn( studentTable.getColumn("Subject") );
studentTable.removeColumn( studentTable.getColumn("Staff") );

Now the Student table will only contain the "Name" and "Grade" columns.

This is the basis behind MVC programming. That is you can easily change the View of the Model. So you are sharing 1 model not sharing the data of 3 separate models.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • Thank you Camickr, not sure if removeColumn doesn't affect my getColumnClass method of the model. If it only affect the table view then I believe you are absolutely correct with MVC pattern. Thank you for helping me all. – Fabrice Khedadi Mar 10 '13 at 12:05
  • Please look at the updated answer. You are absolutely right NO need to use separate models are all. +1 for the suggestion. – Amarnath Mar 10 '13 at 15:55
  • Thank you both Che and Camickr, I tried it and it all work ... removeColumn only remove the column from the table not from the model ... – Fabrice Khedadi Mar 10 '13 at 22:52
2

I have used a table model which stores all the rows, another table model which store only student details and the third table model which stores staff details. All of them get the data from the same source but showing of columns is different foe each table.

All Table Model

import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;


public class AllTableExample {

    private JTabbedPane tabbedPane;
    private JTable allTable;
    private JTable studentTable;
    private JTable staffTable;

    public AllTableExample() {
        setData();

        allTable = new JTable();
        studentTable = new JTable();
        staffTable = new JTable();
    }

    public void createUI() {
        JFrame frame = new JFrame();

        tabbedPane = new JTabbedPane();

        tabbedPane.add("All", getAllTablePanel());
        tabbedPane.add("Student", getStudentTablePanel());
        tabbedPane.add("Staff", getStaffTablePanel());

        frame.add(tabbedPane);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setTitle("Table Model Example.");
        frame.pack();
        frame.setVisible(true);
    }

    private void setData() {
        List<TableData> data = new ArrayList<TableData>();
        data.add(new TableData("John1", "A", "Maths", "Hellen1"));
        data.add(new TableData("John2", "A", "Maths", "Hellen2"));
        data.add(new TableData("John3", "A", "Maths", "Hellen3"));
        data.add(new TableData("John4", "A", "Maths", "Hellen4"));
        data.add(new TableData("John5", "A", "Maths", "Hellen5"));

        MainDataClass.getInstance().setData(data);
    }

    private JPanel getAllTablePanel() {
        JPanel panel = new JPanel();
        JTable table = new JTable(new AllTableModel());
        JScrollPane scroll = new JScrollPane(table);
        panel.add(scroll);

        return panel;
    }

    private JPanel getStudentTablePanel() {
        JPanel panel = new JPanel();
        JTable table = new JTable(new StudentTableModel());
        JScrollPane scroll = new JScrollPane(table);
        panel.add(scroll);

        return panel;
    }

    private JPanel getStaffTablePanel() {
        JPanel panel = new JPanel();
        JTable table = new JTable(new StaffTableModel());
        JScrollPane scroll = new JScrollPane(table);
        panel.add(scroll);

        return panel;
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
                new AllTableExample().createUI();
            }
        };

        EventQueue.invokeLater(r);
    }

}


class AllTableModel extends AbstractTableModel {

    List<TableData> tableData = new ArrayList<TableData>();

    Object[] columnNames = {"Name", "Grade", "Subject", "Staff"};

    public AllTableModel() {
        tableData = MainDataClass.getInstance().getData();
    }

    @Override
    public String getColumnName(int column) {
        return columnNames[column].toString();
    }

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

    @Override
    public int getRowCount() {
        return tableData.size();
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        TableData data = tableData.get(rowIndex);
        switch (columnIndex) {
        case 0:
            return data.getName();
        case 1:
            return data.getGrade();
        case 2:
            return data.getSubject();
        case 3:
            return data.getStaff();
        default:
            return null;
        }
    }

}

class StudentTableModel extends AbstractTableModel {

    List<TableData> tableData = new ArrayList<TableData>();

    Object[] columnNames = {"Name", "Grade"};

    public StudentTableModel() {
        tableData = MainDataClass.getInstance().getData();
    }

    @Override
    public String getColumnName(int column) {
        return columnNames[column].toString();
    }

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

    @Override
    public int getRowCount() {
        return tableData.size();
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        TableData data = tableData.get(rowIndex);
        switch (columnIndex) {
        case 0:
            return data.getName();
        case 1:
            return data.getGrade();
        default:
            return null;
        }
    }
}

class StaffTableModel extends AbstractTableModel {

    List<TableData> tableData = new ArrayList<TableData>();

    Object[] columnNames = {"Subject", "Staff"};

    public StaffTableModel() {
        tableData = MainDataClass.getInstance().getData();
    }

    @Override
    public String getColumnName(int column) {
        return columnNames[column].toString();
    }

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

    @Override
    public int getRowCount() {
        return tableData.size();
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        TableData data = tableData.get(rowIndex);
        switch (columnIndex) {
        case 0:
            return data.getSubject();
        case 1:
            return data.getStaff();
        default:
            return null;
        }
    }
}

class TableData {

    private String name;
    private String grade;
    private String subject;
    private String staff;

    public TableData(String name, String grade, String subject, String staff) {
        super();
        this.name = name;
        this.grade = grade;
        this.subject = subject;
        this.staff = staff;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getGrade() {
        return grade;
    }
    public void setGrade(String grade) {
        this.grade = grade;
    }
    public String getSubject() {
        return subject;
    }
    public void setSubject(String subject) {
        this.subject = subject;
    }
    public String getStaff() {
        return staff;
    }
    public void setStaff(String staff) {
        this.staff = staff;
    }
}

class MainDataClass {

    private static MainDataClass mainDataClass;
    private List<TableData> data;

    private MainDataClass() {

    }

    public static MainDataClass getInstance() {
        if(null == mainDataClass) {
            mainDataClass = new MainDataClass();
        }
        return mainDataClass;
    }

    public List<TableData> getData() {
        return data;
    }

    public void setData(List<TableData> data) {
        this.data = data;
    }
}

EDIT-2:

Referring @camickr explanation of using only one model I tried this one and it worked. Use removeColumn method it worked like a charm.

import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;


public class AllTableExample {


    private JTabbedPane tabbedPane;
    private JTable allTable;
    private JTable studentTable;
    private JTable staffTable;
    private AllTableModel allTableModel;

    public AllTableExample() {
        allTable = new JTable();
        studentTable = new JTable();
        staffTable = new JTable();

        allTableModel = new AllTableModel();
    }

    public void createUI() {
        JFrame frame = new JFrame();

        tabbedPane = new JTabbedPane();

        tabbedPane.add("All", getAllTablePanel());
        tabbedPane.add("Student", getStudentTablePanel());
        tabbedPane.add("Staff", getStaffTablePanel());

        frame.add(tabbedPane);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setTitle("Table Model Example.");
        frame.pack();
        frame.setVisible(true);
    }

    private JPanel getAllTablePanel() {
        JPanel panel = new JPanel();
        JTable table = new JTable(allTableModel);
        JScrollPane scroll = new JScrollPane(table);
        panel.add(scroll);

        return panel;
    }

    private JPanel getStudentTablePanel() {
        JPanel panel = new JPanel();
        JTable table = new JTable(allTableModel);
        table.removeColumn(table.getColumn("Subject"));
        table.removeColumn(table.getColumn("Staff"));
        JScrollPane scroll = new JScrollPane(table);
        panel.add(scroll);

        return panel;
    }

    private JPanel getStaffTablePanel() {
        JPanel panel = new JPanel();
        JTable table = new JTable(allTableModel);
        table.removeColumn(table.getColumn("Name"));
        table.removeColumn(table.getColumn("Grade"));
        JScrollPane scroll = new JScrollPane(table);
        panel.add(scroll);

        return panel;
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
                new AllTableExample().createUI();
            }
        };

        EventQueue.invokeLater(r);
    }

}


class AllTableModel extends AbstractTableModel {

    List<TableData> tableData = new ArrayList<TableData>();

    Object[] columnNames = {"Name", "Grade", "Subject", "Staff"};

    public AllTableModel() {
        List<TableData> data = new ArrayList<TableData>();
        data.add(new TableData("John1", "A", "Maths", "Hellen1"));
        data.add(new TableData("John2", "A", "Maths", "Hellen2"));
        data.add(new TableData("John3", "A", "Maths", "Hellen3"));
        data.add(new TableData("John4", "A", "Maths", "Hellen4"));
        data.add(new TableData("John5", "A", "Maths", "Hellen5"));
        tableData = data;
    }

    @Override
    public String getColumnName(int column) {
        return columnNames[column].toString();
    }

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

    @Override
    public int getRowCount() {
        return tableData.size();
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        TableData data = tableData.get(rowIndex);
        switch (columnIndex) {
        case 0:
            return data.getName();
        case 1:
            return data.getGrade();
        case 2:
            return data.getSubject();
        case 3:
            return data.getStaff();
        default:
            return null;
        }
    }

}

class TableData {

    private String name;
    private String grade;
    private String subject;
    private String staff;

    public TableData(String name, String grade, String subject, String staff) {
        super();
        this.name = name;
        this.grade = grade;
        this.subject = subject;
        this.staff = staff;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getGrade() {
        return grade;
    }
    public void setGrade(String grade) {
        this.grade = grade;
    }
    public String getSubject() {
        return subject;
    }
    public void setSubject(String subject) {
        this.subject = subject;
    }
    public String getStaff() {
        return staff;
    }
    public void setStaff(String staff) {
        this.staff = staff;
    }
}

class MainDataClass {

    private static MainDataClass mainDataClass;
    private List<TableData> data;

    private MainDataClass() {

    }

    public static MainDataClass getInstance() {
        if(null == mainDataClass) {
            mainDataClass = new MainDataClass();
        }
        return mainDataClass;
    }

    public List<TableData> getData() {
        return data;
    }

    public void setData(List<TableData> data) {
        this.data = data;
    }
}
Amarnath
  • 8,736
  • 10
  • 54
  • 81
  • Thank you Che, this is what I was looking for ... using singleton pattern, very very good idea. – Fabrice Khedadi Mar 09 '13 at 18:46
  • @FabriceKhedadi, This is not how Swing was designed to be used. Was was designed to use MVC programming. See my explanation. – camickr Mar 09 '13 at 20:35
  • @che, NO! You do not remove a column by setting the column widths to zero. The columns still exist in the table. I gave you the proper method to use (although I did give the wrong parameter for the method). I updated my answer with the proper code. – camickr Mar 10 '13 at 03:06
  • @camickr Awesome. I used `removeColumn` method to remove the columns for each. Thanks I have learned something worth today. – Amarnath Mar 10 '13 at 15:53
2

You need to register TableModelListener to the Tablemodel of both JTables.. So that whenever one of the table's cell value is changed the same could be reflected in other via repaint() method of JTable. For example consider the code given below:
enter image description here

import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.JScrollPane;
import javax.swing.event.TableModelListener;
import javax.swing.event.TableModelEvent;
import javax.swing.table.AbstractTableModel;
import java.awt.Container;
import java.awt.GridLayout;
import java.util.ArrayList;
public class TablesHavingSameData extends JFrame implements TableModelListener
{
    MyTableModel model1;
    MyTableModel model2;
    JTable table1;
    JTable table2;
    ArrayList<ArrayList<String>> data;
    public void createAndShowGUI()
    {
        setTitle("JTables");
        Container c  = getContentPane();
        c.setLayout(new GridLayout(2,1));
        prepareData();
        model1 = new MyTableModel("table1");
        model2 = new MyTableModel("table2");
        table1 = new JTable(model1);
        table2 = new JTable(model2);
        model1.addTableModelListener(this);
        model2.addTableModelListener(this);
        JScrollPane jsTable1 = new JScrollPane(table1);
        JScrollPane jsTable2 = new JScrollPane(table2);
        c.add(jsTable1);
        c.add(jsTable2);
        setSize(500,300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }
    @Override
    public void tableChanged(TableModelEvent evt)
    {
        AbstractTableModel model = (MyTableModel)evt.getSource();
        if (model == model1)
        {
            table2.repaint();
        }
        else
            table1.repaint();
    }
    private void prepareData()
    {
        data = new ArrayList<ArrayList<String>>();
        data.add(new ArrayList<String>(){{add("1");add("Michael");}});
        data.add(new ArrayList<String>(){{add("2");add("Derake");}});
        data.add(new ArrayList<String>(){{add("3");add("Archie");}});
    }
    private class MyTableModel extends AbstractTableModel
    {
        String columns[] ;
        String sTableName;
        public MyTableModel(String tableName)
        {
            sTableName = tableName;
            if ("table1".equals(sTableName))
            {
                columns = new String[] {"Roll No.","Name"};
            }
            else
            {
                columns = new String[] {"Emp ID.","Employee Name"};
            }
        }
        @Override
        public String getColumnName(int columnIndex)
        {
            return columns[columnIndex];
        }
        @Override
        public int getRowCount()
        {
            return data.size();
        }
        @Override 
        public int getColumnCount()
        {
            return columns.length;
        }
        @Override
        public Object getValueAt(int row, int col)
        {
            return data.get(row).get(col);
        }
        @Override
        public void setValueAt(Object aValue, int rowIndex, int colIndex)
        {
            data.get(rowIndex).set(colIndex,(String)aValue);
            fireTableCellUpdated(rowIndex,colIndex);
        }
        @Override
        public boolean isCellEditable(int row, int col)
        {
            return true;
        }
    }
    public static void main(String[] args) 
    {
        SwingUtilities.invokeLater( new Runnable()
        {
            @Override
            public void run()
            {
                TablesHavingSameData ths = new TablesHavingSameData();
                ths.createAndShowGUI();
            }
        });
    }
}
Vishal K
  • 12,976
  • 2
  • 27
  • 38
1

Small example of the same data with different column names:

import java.awt.BorderLayout;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;

public class TestTable {

    public static class MyModel extends AbstractTableModel {

        private List<Object[]> data;
        private List<String> columnNames;

        public MyModel(List<String> columnNames, List<Object[]> data) {
            super();
            this.columnNames = columnNames;
            this.data = data;
        }

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

        @Override
        public int getColumnCount() {
            return columnNames.size();
        }

        @Override
        public String getColumnName(int column) {
            return columnNames.get(column);
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            return data.get(rowIndex)[columnIndex];
        }

    }

    protected void initUI() {
        JFrame frame = new JFrame(TestTable.class.getSimpleName());
        List<String> columns = Arrays.asList("Name", "Age");
        List<String> columns2 = Arrays.asList("Label", "Price");
        List<Object[]> data = new ArrayList<Object[]>();
        for (int i = 0; i < 50; i++) {
            Object[] value = new Object[2];
            value[0] = "Something-" + i;
            value[1] = 12 + i;
            data.add(value);
        }
        JTable table = new JTable(new MyModel(columns, data));
        JTable table2 = new JTable(new MyModel(columns2, data));
        frame.add(new JScrollPane(table), BorderLayout.WEST);
        frame.add(new JScrollPane(table2), BorderLayout.EAST);
        frame.pack();
        frame.setVisible(true);
    }

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

            @Override
            public void run() {
                new TestTable().initUI();
            }
        });
    }
}
Guillaume Polet
  • 47,259
  • 4
  • 83
  • 117