First, I will define a DataContainer class that holds all the data I want.
package jtbl_2tbl_abst; /** * * @author Lee */ public class DataContainer { private Object[][] data = { {"Singed", "male", false}, {"Akali", "female", false}, {"Tristina", "female", true}, {"Udyr", "male", false}, {"Janna", "female", true} }; private final String[] columnNames = { "Name", "Sex", "Vegetarin" }; /** * @return the data */ public Object[][] getData() { return data; } /** * @param data the data to set */ public void setData(Object[][] data) { this.data = data; } public void setData(Object data, int row, int col) { this.data[row][col] = data; } /** * @return the columnNames */ public String[] getColumnNames() { return columnNames; } }
Now I want MyTableModel that extends AbstractTableModel.
(otherwise I should redefine MyTableModel for each table.)
package jtbl_2tbl_abst; import javax.swing.table.AbstractTableModel; /** * * @author Lee */ public class MyTableModel extends AbstractTableModel { // holds column names and data from outer source private String[] columnNames; private Object[][] data; public MyTableModel(Object[][] data, String[] columnNames) { this.data = data; this.columnNames = columnNames; } // the explanation is ommitted since I've covered it in the last post // "Using AbstractTableModel" @Override public int getRowCount() { return data.length; } @Override public int getColumnCount() { return columnNames.length; } @Override public Object getValueAt(int row, int col) { return data[row][col]; } @Override public Class getColumnClass(int c) { return getValueAt(0, c).getClass(); } @Override public boolean isCellEditable(int row, int col) { return true; } @Override public void setValueAt(Object value, int row, int col) { data[row][col] = value; fireTableCellUpdated(row, col); } }
now, let's define Table1 class
package jtbl_2tbl_abst; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableModel; import net.miginfocom.swing.MigLayout; /** * * @author Lee */ public class Table1 extends JPanel implements TableModelListener{ // JScrollPane that takes JTable private JScrollPane scrollPane; // This is table private JTable table1; // this holds data from DataContainer DataContainer container = new DataContainer(); // this holds AbstractTableModel from MyTableModel private AbstractTableModel model; public Table1(DataContainer container) { super(new MigLayout()); this.container = container; initComponents(); } private void initComponents() { // initiate the table model model = new MyTableModel(container.getData(), container.getColumnNames()); // initiate the table table1 = new JTable(model); // add TableModelListener so that we can change the data, and the // changed data can be detected table1.getModel().addTableModelListener(this); scrollPane = new JScrollPane(table1); this.add(scrollPane); } @Override public void tableChanged(TableModelEvent e) { // get the first row that has been changed int row = e.getFirstRow(); // get the column that has been changed int column = e.getColumn(); // get the changed model of the table TableModel model = (TableModel)e.getSource(); // tableChanged method throws -1 when theres no change of row and columns // but wants to update the whole table. // And that causes unexpected errors, so I put if(column >=0) to prevent that if(column >= 0 ) { String columnName = model.getColumnName(column); // get the changed data from the table model Object data = model.getValueAt(row, column); // apply the change to the container data container.setData(data, row, column); } } /** * @return the table1 */ public JTable getTable1() { return table1; } /** * @param table1 the table1 to set */ public void setTable1(JTable table1) { this.table1 = table1; } /** * @return the model */ public AbstractTableModel getModel() { return model; } /** * @param model the model to set */ public void setModel(AbstractTableModel model) { this.model = model; } }
Similarly, we need to define Table2. The explanation is omitted since Table2 is identical to Table1
package jtbl_2tbl_abst; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableModel; import net.miginfocom.swing.MigLayout; /** * * @author Lee */ public class Table2 extends JPanel implements TableModelListener{ private JScrollPane scrollPane; private JTable table2; private AbstractTableModel model; DataContainer container = new DataContainer(); public Table2(DataContainer container) { super(new MigLayout()); this.container = container; initComponents(); } public void initComponents() { model = new MyTableModel(container.getData(), container.getColumnNames()); table2 = new JTable(model); table2.getModel().addTableModelListener(this); scrollPane = new JScrollPane(table2); this.add(scrollPane); } @Override public void tableChanged(TableModelEvent e) { int row = e.getFirstRow(); int column = e.getColumn(); TableModel model = (TableModel)e.getSource(); if(column >= 0 ) { String columnName = model.getColumnName(column); Object data = model.getValueAt(row, column); System.out.println("changed data: " + data); container.setData(data, row, column); } } /** * @return the table2 */ public JTable getTable2() { return table2; } /** * @param table2 the table2 to set */ public void setTable2(JTable table2) { this.table2 = table2; } /** * @return the model */ public AbstractTableModel getModel() { return model; } /** * @param model the model to set */ public void setModel(AbstractTableModel model) { this.model = model; } }
Now we need JFrame that holds the two tables.
package jtbl_2tbl_abst; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.SwingUtilities; import net.miginfocom.swing.MigLayout; /** * * @author Lee */ public class Frame { // JFrame that holds Table1 JFrame frame1 = new JFrame(); // JFrame that holds Table2 JFrame frame2 = new JFrame(); // This button will open frame2 with Table2 JButton opnBttn = new JButton("Open Table2"); // This button will close frame2 updating the changed data JButton mdfBttn = new JButton("OK"); // This button will Update frame2(table2) when table1 has been changed JButton udtBttn = new JButton("Update"); DataContainer container = new DataContainer(); Table1 table1Panel; Table2 table2Panel; public Frame() { initTable1(); initTable2(); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new Frame(); } }); } // initiate Table1 public void initTable1() { // add ActionListener to opnBttn opnBttn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent evt) { opnBttnClicked(evt); } }); // add ActionListener to udtBttn udtBttn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent evt) { udtBttnClicked(evt); } }); // initiate Table1 with the sharing data table1Panel = new Table1(container); // setup frame1 frame1.setLayout(new MigLayout()); frame1.add(table1Panel, "span, growx, wrap"); frame1.add(opnBttn); frame1.add(udtBttn); frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame1.pack(); frame1.setVisible(true); } // initiate Table2 public void initTable2() { // add ActionListener to mdfBttn mdfBttn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent evt) { mdfBttnClicked(evt); } }); // initiate Table2 with the sharing data table2Panel = new Table2(container); // set up frame2 frame2.setLayout(new MigLayout()); frame2.add(table2Panel, "wrap"); frame2.add(mdfBttn, "center"); frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame2.pack(); } // when opnBttn is clicked, frame2(table2) become visible public void opnBttnClicked(ActionEvent evt) { // clikcing the opnBttn when one is editing the table cell will cause // data lose since the changed value is still in Editor, not in Renderer. // To send the changed value from Editor to Render, I need the following if (table1Panel.getTable1().isEditing()) { table1Panel.getTable1().getCellEditor().stopCellEditing(); } // open frame2(table2) frame2.setVisible(true); } // when mdfBttn is clicked, frame2 is closed public void mdfBttnClicked(ActionEvent evt) { // same as above if (table2Panel.getTable2().isEditing()) { table2Panel.getTable2().getCellEditor().stopCellEditing(); } frame2.setVisible(false); // notify table1 that the data may have been changed table1Panel.getModel().fireTableDataChanged(); } // when udtBttn is clicked, table2 refreshes public void udtBttnClicked(ActionEvent evt) { if (table1Panel.getTable1().isEditing()) { table1Panel.getTable1().getCellEditor().stopCellEditing(); } table2Panel.getModel().fireTableDataChanged(); } }
No comments:
Post a Comment