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
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.
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:
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();
}
});
}
}
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.
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;
}
}
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();
}
});
}
}
来源:https://stackoverflow.com/questions/15313240/java-same-arraylist-for-multiple-table-model