Synchronize the view of two JTables

I have two JTables

one in the main viewport and one in the footer viewport using JideScrollPane

. the problem is when the main JTable

view is set up, the footer JTable

stays the same, is there a way to keep their view in sync?

thank.

unsynch

+3


source to share


3 answers


EDIT: Here's a demo that will sync the resizing of two tables with similar columns. The idea is this:

  • Create a custom one TableColumnModelListener

    for each table column model.
  • Keep the column widths in sync when resizing. You will have to temporarily disable the other listener while this is happening.
  • To move columns, implement this logic in columnMoved(...)

    [left as an exercise]


This shows two-way sync:

import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;

public class JTableResizeColumnsDemo implements Runnable
{
  JTable table1, table2;
  TableColumnModelListener columnListener1, columnListener2;
  Map<JTable, TableColumnModelListener> map;

  public static void main(String[] args)
  {
    SwingUtilities.invokeLater(new JTableResizeColumnsDemo());
  }

  public void run()
  {
    Vector<String> names = new Vector<String>();
    names.add("One");
    names.add("Two");
    names.add("Three");

    table1 = new JTable(null, names);
    table2 = new JTable(null, names);

    columnListener1 = new ColumnChangeListener(table1, table2);
    columnListener2 = new ColumnChangeListener(table2, table1);

    table1.getColumnModel().addColumnModelListener(columnListener1);
    table2.getColumnModel().addColumnModelListener(columnListener2);

    map = new HashMap<JTable, TableColumnModelListener>();
    map.put(table1, columnListener1);
    map.put(table2, columnListener2);

    JPanel p = new JPanel(new GridLayout(2,1));
    p.add(new JScrollPane(table1));
    p.add(new JScrollPane(table2));

    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(p);
    frame.setSize(300, 200);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  class ColumnChangeListener implements TableColumnModelListener
  {
    JTable sourceTable;
    JTable targetTable;

    public ColumnChangeListener(JTable source, JTable target)
    {
      this.sourceTable = source;
      this.targetTable = target;
    }

    public void columnAdded(TableColumnModelEvent e) {}
    public void columnSelectionChanged(ListSelectionEvent e) {}
    public void columnRemoved(TableColumnModelEvent e) {}
    public void columnMoved(TableColumnModelEvent e) {}

    public void columnMarginChanged(ChangeEvent e)
    {
      TableColumnModel sourceModel = sourceTable.getColumnModel();
      TableColumnModel targetModel = targetTable.getColumnModel();
      TableColumnModelListener listener = map.get(targetTable);

      targetModel.removeColumnModelListener(listener);

      for (int i = 0; i < sourceModel.getColumnCount(); i++)
      {
        targetModel.getColumn(i).setPreferredWidth(sourceModel.getColumn(i).getWidth());
      }

      targetModel.addColumnModelListener(listener);
    }
  }
}

      

+4


source


You can apply the Observer pattern : the first JTable observes the second and vice versa. Then you add a list for both tables so that when a user is "configured" the other is notified. Basically, the "notification" consists of calling a method that updates the JTable. To do this, you have two options:



  • You define the Observer class with the "register" method and the "notify" method. When you create a JTable, you register it with an Observer. Then the listener you create and associate with each JTable will call the "notify" observer method, which informs any other JTables registered changes
  • You define a kind of "callback" method in the class that contains and declares the JTable. This notify method is called on the list and updates the correct JTable. You can also create two methods, one for updating one JTable and one for another JTable
+1


source


This is usually done using the same model for different ui components. Unfortunately, it JTable

contains a bug that will cause problems when sharing TableColumnModel

.

But you can get around it using this JTable

class ShareableColumnModelTable extends JTable {

    /**
     * Fixes http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4816146 and
     * more...
     * 
     */
    @Override
    public void columnMarginChanged(ChangeEvent e) {
        if (isEditing()) {
            removeEditor();
        }
        TableColumn resizingColumn = null;
        if (tableHeader != null) {
            resizingColumn = tableHeader.getResizingColumn();
        }
        if (resizingColumn != null) {
            if (autoResizeMode == AUTO_RESIZE_OFF) {
                resizingColumn.setPreferredWidth(resizingColumn.getWidth());
            } else { // this else block is missing in jdk1.4 as compared to
                        // 1.3
                TableColumnModel columnModel = getColumnModel();

                /**
                 * Temporarily disconnects this column listener to prevent
                 * stackoverflows if the column model is shared between
                 * multiple JTables.
                 */
                columnModel.removeColumnModelListener(this);
                try {
                    doLayout();
                } finally {
                    columnModel.addColumnModelListener(this);
                }

                repaint();
                return;
            }
        }
        resizeAndRepaint();
    }

}

      

With the above, ShareableColumnModelTable

you can share one column model with multiple tables.

public static void main(String[] args) {
    JFrame frame = new JFrame("Column Sync");

    Container contentPane = frame.getContentPane();
    JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
    splitPane.setResizeWeight(0.5d);
    contentPane.add(splitPane);

    JTable table1 = new ShareableColumnModelTable();
    JTable table2 = new ShareableColumnModelTable();

    TableColumnModel tableColumnModel = createTableColumnModel();

    table1.setModel(createTableModel1());
    table2.setModel(createTableModel2());

    table1.setColumnModel(tableColumnModel);
    table2.setColumnModel(tableColumnModel);

    splitPane.setLeftComponent(new JScrollPane(table1));
    splitPane.setRightComponent(new JScrollPane(table2));

    showFrame(frame);
}

private static TableColumnModel createTableColumnModel() {
    TableColumnModel tableColumnModel = new DefaultTableColumnModel();

    TableColumn column1 = new TableColumn(0);
    column1.setHeaderValue("1. column");
    tableColumnModel.addColumn(column1);

    TableColumn column2 = new TableColumn(1);
    column2.setHeaderValue("2. column");
    tableColumnModel.addColumn(column2);

    return tableColumnModel;
}

private static TableModel createTableModel1() {
    DefaultTableModel tableModel = new DefaultTableModel();
    tableModel.setColumnCount(2);
    tableModel.addRow(new Object[] { "a", "b" });
    return tableModel;
}

private static TableModel createTableModel2() {
    DefaultTableModel tableModel = new DefaultTableModel();
    tableModel.setColumnCount(2);
    tableModel.addRow(new Object[] { "c", "d" });
    return tableModel;
}

private static void showFrame(JFrame frame) {
    frame.setSize(240, 400);
    frame.setLocationRelativeTo(null);
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.setVisible(true);
}

      

enter image description here

0


source







All Articles