Home > database >  In Java Swing (using swingx) how to sort rows in one table in same order as another table
In Java Swing (using swingx) how to sort rows in one table in same order as another table

Time:02-12

I have a table with x num of rows, I have a second table with the same number of rows but different columns and metadata, they have different table models. but each row represents the same object (a song).

I want to synchronize row sorting between the two tables so for example if I sort on column 2 of table 1 then rows of the table will be sorted in the same order. But currently, I just have sorted by matching sort keys so sort on the same column (but because different data get different results)

e.g

Starting point

Table 1
1    tom    
2    jane
3    fred
4    steve
5    jim

Table 2
1    oranges
2    apples
3    pears
4    lemons
5    plums

If I sort by table 1, column 2 Ascending I want to get

Table 1
2    jane
5    jim
3    fred
4    steve
1    tom

Table 2
2    apples
5    plums
3    pears
4    lemons
1    oranges

but I get

Table 1
2    jane
5    jim
3    fred
4    steve
1    tom

Table 2
2    apples
4    lemons
1    oranges
3    pears
5    plums

My sorting is done by calling setSortKeys() on table 2 to the getSortKeys() of table 1 and vice versa. I can see why it doesn't work, I am telling table 2 to sort by column 2 ascending the same as table 1 but of course these columns have different data in each table. But I can't work out a way to get table 2 to sort to the final order of table 1 instead.

One solution would be for both tables to share the same table model and just show the columns relevant to their table, but that would require a major rework of the code, so I am hoping for a more specific solution just to resolve the sorting issue.

I am using Java 11, and swingx latest version 1.6.4 (i know very old) but this delegates sorting to standard Java (earlier version that I was previously using had its own sorting) so not really a swingx question.

The real world situation, within my application is as follows, each row represents a song, and the tabs show metadata for that song. the tabs under the edit menu all share same model and all work using the setSortKeys() method described above. So here i have sorted on Mood Aggressive column

Edit metadata tab

and if I go to another tab, we see the rows are sorted in same order

Another Edit metadata tab, sorted same order

but if I go to the Edit ID3 tab, we see the rows have been sorted in different order.

ID3 Edit tab sorted different order

This is because ID3 Edit tab shows the metadata in different format (ID3) and has different table model so column x represent in the model stores different data.

Note because all models store the rowno in first column, sorting my the rowno column works for all tabs.

So from a user point of view they are just viewing different tabs of the same table, and therefore would expect sort to be consistent for the tabs

CodePudding user response:

Here is what I meant in the comments:

import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableRowSorter;
import java.awt.*;

public class TablesExample extends JPanel {
    static class MyTableModel extends AbstractTableModel {
        private String[] columnNames = {"Row Id",
                "Person",
                "Fruit"};
        private Object[][] data = {
                {"1", "Tom", "Orange"},
                {"2", "Jane", "Apple"},
                {"3", "Fred", "Pear"},
                {"4", "Steve", "Lemon"},
                {"5", "Jim", "Plum"}
        };

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

        public int getRowCount() {
            return data.length;
        }

        public String getColumnName(int col) {
            return columnNames[col];
        }

        public Object getValueAt(int row, int col) {
            return data[row][col];
        }
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("Tables Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JTabbedPane tabbedPane = new JTabbedPane();
        tabbedPane.setPreferredSize(new Dimension(500, 100));

        TablesExample newContentPane = new TablesExample();
        newContentPane.setOpaque(true);

        MyTableModel model = new MyTableModel();
        TableRowSorter<MyTableModel> sorter = new TableRowSorter<>(model);
        JTable table = new JTable(model);
        table.setRowSorter(sorter);
        TableColumn column2 = table.getColumnModel().getColumn(2);
        column2.setMinWidth(0);
        column2.setMaxWidth(0);
        column2.setWidth(0);

        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setViewportView(table);
        tabbedPane.add("Persons", scrollPane);

        JTable table2 = new JTable(model);
        table2.setRowSorter(sorter);
        TableColumn column1 = table2.getColumnModel().getColumn(1);
        column1.setMinWidth(0);
        column1.setMaxWidth(0);
        column1.setWidth(0);

        JScrollPane scrollPane2 = new JScrollPane();
        scrollPane2.setViewportView(table2);
        tabbedPane.add("Fruits", scrollPane2);

        frame.setContentPane(tabbedPane);

        frame.pack();
        frame.setVisible(true);
    }
}

CodePudding user response:

Have a prototype working.

So using swingx we implement a subclass of TableSortController and override toggleSortOrder() and set this as the rowSorter of the main table

        public void toggleSortOrder(int column)
        {
            .........
            setSortKeys(newKeys);
        
            for(int i=0; i < getModelWrapper().getRowCount(); i  )
            {
                SecondTable.instanceOf().getRealModel()
                    .setValueAt(convertRowIndexToView(i), i, ID3TagNames.INDEX_SYNC_SORT);
            }
        
            newKeys = new ArrayList<>();
            SecondTable.instanceOf().getTable().getRowSorter().setSortKeys(newKeys);
        
            newKeys.add(new SortKey(ID3TagNames.INDEX_SYNC_SORT, this.getFirstInCycle()));
            SecondTable.instanceOf().getTable().getRowSorter().setSortKeys(newKeys);

        }

Logic is does a normal sort on main table, then sets hidden column on second table to store the view index of each row. Then remove any existing sort on second table, then sort by hidden column.

Note the two calls to setSortKey() are needed because if you sort by one column on main table, and then do another sort in both cases will be sorting second table by INDEX_SYNC_SORT ascending and hence the following code in superclass DefaultRowSorter.setSortKeys() will prevent a sort being done because the sortkey will be the same as previous sort

        if (!this.sortKeys.equals(old)) {
            fireSortOrderChanged();
            if (viewToModel == null) {
                // Currently unsorted, use sort so that internal fields
                // are correctly set.
                sort();
            } else {
                sortExistingData();
            }
        }

For now in this prototype we have a default sort controller on the SecondTable as we don't want this to do the special processing as well. But probably want to sort on both and therefore would need the toggleSort() code to check what table they are linked to and act accordingly.

  • Related