如何在两个JTable之间同步选择,排序和过滤

问题描述 投票:0回答:1

我一直在尝试获取两个在排序和筛选(RowSorter)和选择(SelectionModel)中基本上完全同步的表。为了实现这一目标,我做了两节课。这些是SelectionModelRowSorter的包装器类。他们基本上只是委派了每个改变状态的公共方法。在下面,您可以看到它们的简化版本,其中仅包含一个覆盖的二传手。但是,其他所有内容也将被覆盖。我不想夸大这个问题。

MirrorableRowSorter(短路):

public class MirrorableRowSorter<M extends TableModel> extends TableRowSorter<M>
{
  private MirrorableRowSorter<M> delegate;

  /**
   * @param delegate the delegate to set
   */
  public void setDelegate( MirrorableRowSorter<M> delegate )
  {
    this.delegate = delegate;
  }

  @Override
  public void setSortKeys( List<? extends SortKey> sortKeys )
  {
    if ( delegate != null )
    {
      delegate.setSortKeysNonDelegating( sortKeys );
    }
    super.setSortKeys( sortKeys );
  }

  private void setSortKeysNonDelegating( List<? extends SortKey> sortKeys )
  {
    super.setSortKeys( sortKeys );
  }

  //... other methods
}

MirrorableSelectionModel(短路):

public class MirrorableSelectionModel extends DefaultListSelectionModel
{
  private MirrorableSelectionModel delegate = null;

  /**
   * @param delegate the delegate to set
   */
  public void setDelegate( final MirrorableSelectionModel delegate )
  {
    this.delegate = delegate;
  }

  @Override
  public void setSelectionInterval( final int index0, final int index1 )
  {
    if ( delegate != null )
    {
      delegate.setSelectionIntervalNonDelegating( index0, index1 );
    }
    super.setSelectionInterval( index0, index1 );
  }

  private void setSelectionIntervalNonDelegating( final int index0, final int index1 )
  {
    super.setSelectionInterval( index0, index1 );
  }

  //... other methods

总是有一个委派和一个非委派的方法。我这样做是为了避免两个对象之间发生乒乓。

然后我写了一个带有两个表的小例子:

import java.awt.BorderLayout;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.RowFilter;

public class ExampleMirroredTables
{
  public static void main( String[] args )
  {
    JFrame frame = new JFrame();
    frame.setLayout( new BorderLayout() );
    final JTable tableOne = new JTable( new Object[][]{
        new Object[]{ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
        new Object[]{ "2", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
        new Object[]{ "3", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
        new Object[]{ "4", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
        new Object[]{ "5", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
        new Object[]{ "6", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
        new Object[]{ "7", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
        new Object[]{ "8", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
        new Object[]{ "9", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
        new Object[]{ "10", "2", "3", "4", "5", "6", "7", "8", "9", "10" }
    }, new Object[]{ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" } );
    final JTable tableTwo = new JTable( new Object[][]{
        new Object[]{ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
        new Object[]{ "2", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
        new Object[]{ "3", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
        new Object[]{ "4", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
        new Object[]{ "5", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
        new Object[]{ "6", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
        new Object[]{ "7", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
        new Object[]{ "8", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
        new Object[]{ "9", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
        new Object[]{ "10", "2", "3", "4", "5", "6", "7", "8", "9", "10" }
    }, new Object[]{ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" } );


    final MirrorableSelectionModel mirrorModelOne = new MirrorableSelectionModel();
    final MirrorableSelectionModel mirrorModelTwo = new MirrorableSelectionModel();
    mirrorModelOne.setDelegate( mirrorModelTwo );
    mirrorModelTwo.setDelegate( mirrorModelOne );
    tableOne.setSelectionModel( mirrorModelOne );
    tableTwo.setSelectionModel( mirrorModelTwo );

    final MirrorableRowSorter mirrorSorterOne = new MirrorableRowSorter();
    final MirrorableRowSorter mirrorSorterTwo = new MirrorableRowSorter();
    mirrorSorterOne.setDelegate( mirrorSorterTwo );
    mirrorSorterTwo.setDelegate( mirrorSorterOne );
    mirrorSorterOne.setModel( tableOne.getModel() );
    mirrorSorterTwo.setModel( tableTwo.getModel() );
    tableOne.setRowSorter( mirrorSorterOne );
    tableTwo.setRowSorter( mirrorSorterTwo );

    JButton filterButton = new JButton( "Filter randomize" );
    AtomicBoolean even = new AtomicBoolean( true );
    filterButton.addActionListener( __ ->
    {
      even.set( !even.get() );
      System.out.println( Arrays.toString( tableOne.getSelectedRows() ) );
      mirrorSorterTwo.setRowFilter( new RowFilter()
      {
        @Override
        public boolean include( Entry entry )
        {
          final int moduloResult = ((Integer) entry.getIdentifier()) % 2;
          return even.get() ? moduloResult == 0 : moduloResult != 0;
        }
      } );
      System.out.println( Arrays.toString( tableOne.getSelectedRows() ) );
    } );

    frame.add( filterButton, BorderLayout.NORTH );
    frame.add( tableOne, BorderLayout.WEST );
    frame.add( new JLabel( "  THE MIRROR  " ), BorderLayout.CENTER );
    frame.add( tableTwo, BorderLayout.EAST );

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

您将可以看到是否使用了选择,它将始终完美地反映出来。但是,如果现在在选择所有行(Ctrl + A)之后单击顶部的筛选器按钮,则在所选的10行中,将仅保留索引01。我不仅要保留已选择的10个过滤器中的5个,还要保留其他(现已隐藏)的过滤器,并在再次更改过滤器后仍然看到选择。这样做的原因是,我们有一个模仿树的JTable。如果我们在该树中折叠一个项目并事先选择了父级及其子级,我们希望在再次扩展父级后仍选择它们。我认为这是可能的,因为在使用镜像选择模型时这似乎可行,但是我不确定为什么。

我不确定我要实现的目标是否完全可能,如果可以,我不知道我是否采取了正确的方法。

这里是所有文件的摘要:https://gist.github.com/Bios-Marcel/ada8781c79b7f13b3e0b3d8486462913

[如果有一个用于同步表的东西(库),我也愿意研究一下,如果能得到任何提示,那将是很好的。

java swing jtable filtering selection
1个回答
0
投票

如果能得到任何提示,那就太好了。

通常,一个模型可以被多个视图共享。

tableTwo.setSelectionModel( tableOne.getSelectionModel() );

不确定每个模型中的行数不同时会发生什么。

但是,由于您正在使用多个TableModel,因此不能将相同的方法用于排序/过滤。

因此,也许另一种方法是使用一个具有20列的TableModel。然后,您将拥有两个具有2个不同模型视图的表。

第一个表将显示前10列,第二个表将显示后10列。

基本概念证明:

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

public class TableSync extends JPanel
{
    public TableSync()
    {
        setLayout( new BorderLayout() );

        String[] columnNames = {"Date", "String", "Integer", "Boolean"};

        Object[][] data =
        {
            {new Date(), "A", Integer.valueOf(1), Boolean.TRUE },
            {new Date(), "B", Integer.valueOf(2), Boolean.FALSE},
            {new Date(), "C", Integer.valueOf(12), Boolean.TRUE },
            {new Date(), "D", Integer.valueOf(5124), Boolean.FALSE}
        };

        DefaultTableModel model = createTableModel(data, columnNames);

        JTable table1 = new JTable( model );
        table1.removeColumn( table1.getColumnModel().getColumn(2) );
        table1.removeColumn( table1.getColumnModel().getColumn(2) );

        JTable table2 = new JTable( model );
        table2.removeColumn( table2.getColumnModel().getColumn(0) );
        table2.removeColumn( table2.getColumnModel().getColumn(0) );

        table2.setSelectionModel( table1.getSelectionModel() );

        table1.setAutoCreateRowSorter(true);
        table2.setRowSorter( table1.getRowSorter() );

        table1.setPreferredScrollableViewportSize(table1.getPreferredSize());
        add(new JScrollPane(table1), BorderLayout.LINE_START);
        table2.setPreferredScrollableViewportSize(table2.getPreferredSize());
        add(new JScrollPane(table2), BorderLayout.LINE_END);
    }

    private DefaultTableModel createTableModel(Object[][] data, String[] columnNames)
    {
        DefaultTableModel model = new DefaultTableModel(data, columnNames)
        {
            //  Returning the Class of each column will allow different
            //  renderers and editors to be used based on Class

            @Override
            public Class getColumnClass(int column)
            {
                for (int row = 0; row < getRowCount(); row++)
                {
                    Object o = getValueAt(row, column);

                    if (o != null)
                        return o.getClass();
                }

                return Object.class;
            }
        };

        return model;
    }

    private static void createAndShowUI()
    {
        JFrame frame = new JFrame("TableSync");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( new TableSync() );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.