Java JTable:将主列设置为始终按第一排序 [英] Java JTable: Setting a primary column to always sort by first

查看:74
本文介绍了Java JTable:将主列设置为始终按第一排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的JTable有3列,显示有关文件和文件夹的信息:

I'm using a JTable with say 3 columns, displaying information about files and folders:

Col1:文件"或文件夹"(字符串)
Col2:文件或文件夹的名称(字符串)
第3列:创建日期(即时贴)

Col1: Either "file" or "folder" (String)
Col2: Name of the file or folder (String)
Col3: Creation date (Timstamp)

我可以轻松地按任何列对表格进行排序.但是我无法实现以下期望的行为:

I can easily sort the table by any column. But I'm not able to achieve the following desired behavior:

无论用户单击哪个列标题,文件夹都应始终显示在文件之前.因此,基本上不可能按Col1以降序以外的任何其他顺序进行排序.另外,如果按Col3排序,则无论其时间戳如何,任何文件夹都应仍显示在文件之前.

No matter what column header the user clicks, folders should always display before files. So basically sorting by Col1 in any order other than descending should not be possible. Also, if sorted by Col3, any folders should still display before files, regardless of their timestamp.

任何有关如何执行此操作的提示都将不胜感激.

Any hint to how to do this is greatly appreciated.

您的

安德烈亚斯(Andreas)

Andreas

推荐答案

好了,这个问题很旧,但是当我执行类似的任务时,Google将此页面退给了我.因此,我将在这里发布我的解决方案.希望对别人有帮助.

Well, the question is old but Google returned this page to me when I had a similar task. So, I'll post here my solution. Hope that it would help someone.

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.swing.DefaultRowSorter;
import javax.swing.JTable;
import javax.swing.RowSorter.SortKey;
import javax.swing.SortOrder;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import org.apache.log4j.Logger;

public class PredefinedRowSorter extends TableRowSorter< TableModel > {
  private static final Logger LOGGER = Logger.getLogger( PredefinedRowSorter.class );
  private static final SortKey EMPTY_ARRAY[] = new SortKey[ 0 ];

  private final JTable table;
  private SortKey preColumns[] = EMPTY_ARRAY;
  private SortKey postColumns[] = EMPTY_ARRAY;

  public PredefinedRowSorter( JTable table ) {
    super( table.getModel() );
    this.table = table;
  }

  private void check( SortKey modelColumns[], SortKey crossCheckColumns[], boolean post ) {
    TableModel tm = table.getModel();
    int max = tm.getColumnCount();
    Set< Integer > used = new HashSet< Integer >();
    for ( SortKey key : modelColumns ) {
      if ( key == null )
        throw new IllegalArgumentException( "SortKey must be non-null" );
      if ( key.getColumn() < 0 )
        throw new IllegalArgumentException( "SortKey column must be non-negative" );
      if ( key.getColumn() >= max )
        throw new IllegalArgumentException( "SortKey column is too high (out of model scope)" );
      if ( key.getSortOrder() == SortOrder.UNSORTED )
        throw new IllegalArgumentException( "SortKey must be ordered (ascending or descending)" );
      if ( !used.add( key.getColumn() ) )
        throw new IllegalArgumentException( "SortKey column must be unique (column " + key.getColumn() + " is repeating)" );
    }
    for ( SortKey key : crossCheckColumns )
      if ( used.contains( key.getColumn() ) )
        throw new IllegalArgumentException( "SortKey column must be unique (column " + key.getColumn() + " is already contained in " + ( post ? "post" : "pre" ) + " columns list)" );
  }

  public PredefinedRowSorter withPreColumns( SortKey... modelColumns ) {
    if ( modelColumns == null )
      modelColumns = EMPTY_ARRAY;
    if ( !Arrays.equals( preColumns, modelColumns ) ) {
      check( modelColumns, postColumns, true );
      preColumns = modelColumns;
      setSortKeys( getSortKeys() );
    }
    return this;
  }

  public PredefinedRowSorter withPostColumns( SortKey... modelColumns ) {
    if ( modelColumns == null )
      modelColumns = EMPTY_ARRAY;
    if ( !Arrays.equals( postColumns, modelColumns ) ) {
      check( modelColumns, preColumns, false );
      postColumns = modelColumns;
      setSortKeys( getSortKeys() );
    }
    return this;
  }

  public JTable getTable() {
    return table;
  }

  public SortKey[] getPreColumns() {
    return preColumns.length == 0 ? preColumns : preColumns.clone();
  }

  public SortKey[] getPostColumns() {
    return postColumns.length == 0 ? postColumns : postColumns.clone();
  }

  private void setSortKeysInternal( List< ? extends SortKey > sortKeys ) {
    try {
      Field field = DefaultRowSorter.class.getDeclaredField( "sortKeys" );
      boolean accessible = field.isAccessible();
      if ( !accessible )
        field.setAccessible( true );
      field.set( this, sortKeys );
      if ( !accessible )
        field.setAccessible( false );
    } catch ( IllegalAccessException e ) {
      LOGGER.error( null, e );
    } catch ( IllegalArgumentException e ) {
      LOGGER.error( null, e );
    } catch ( NoSuchFieldException e ) {
      LOGGER.error( null, e );
    } catch ( SecurityException e ) {
      LOGGER.error( null, e );
    }
  }

  private Object getViewToModelInternal() {
    try {
      Field field = DefaultRowSorter.class.getDeclaredField( "viewToModel" );
      boolean accessible = field.isAccessible();
      if ( !accessible )
        field.setAccessible( true );
      Object ret = field.get( this );
      if ( !accessible )
        field.setAccessible( false );
      return ret;
    } catch ( IllegalAccessException e ) {
      LOGGER.error( null, e );
    } catch ( IllegalArgumentException e ) {
      LOGGER.error( null, e );
    } catch ( NoSuchFieldException e ) {
      LOGGER.error( null, e );
    } catch ( SecurityException e ) {
      LOGGER.error( null, e );
    }
    return null;
  }

  private void sortExistingDataInternal() {
    try {
      Method method = DefaultRowSorter.class.getDeclaredMethod( "sortExistingData" );
      boolean accessible = method.isAccessible();
      if ( !accessible )
        method.setAccessible( true );
      method.invoke( this );
      if ( !accessible )
        method.setAccessible( false );
    } catch ( IllegalAccessException e ) {
      LOGGER.error( null, e );
    } catch ( IllegalArgumentException e ) {
      LOGGER.error( null, e );
    } catch ( NoSuchMethodException e ) {
      LOGGER.error( null, e );
    } catch ( InvocationTargetException e ) {
      LOGGER.error( null, e );
      LOGGER.error( null, ( ( InvocationTargetException )e ).getCause() );
    }
  }

  @Override
  public void setSortKeys( List< ? extends SortKey > sortKeys ) {
    List< ? extends SortKey > oldSortKeys = getSortKeys();
    List< ? extends SortKey > newSortKeys;
    if ( sortKeys != null && !sortKeys.isEmpty() ) {
      int max = getModelWrapper().getColumnCount();
      for ( SortKey key : sortKeys )
        if ( key == null || key.getColumn() < 0 || key.getColumn() >= max )
          throw new IllegalArgumentException( "Invalid SortKey" );
      newSortKeys = Collections.unmodifiableList( new ArrayList< SortKey >( sortKeys ) );
    } else
      newSortKeys = Collections.emptyList();
    setSortKeysInternal( newSortKeys );
    if ( !newSortKeys.equals( oldSortKeys ) ) {
      fireSortOrderChanged();
      boolean wasChanged = false;
      if ( preColumns.length > 0 || postColumns.length > 0 ) {
        List< SortKey > editableSortKeys = new ArrayList< SortKey >( newSortKeys );
        for ( int i = preColumns.length - 1; i >= 0; i-- ) {
          int modelColumn = preColumns[ i ].getColumn();
          int idx = indexOfColumn( editableSortKeys, preColumns.length - i - 1, editableSortKeys.size(), modelColumn );
          SortOrder sortOrder = idx < 0 ? preColumns[ i ].getSortOrder() : editableSortKeys.remove( idx ).getSortOrder();
          editableSortKeys.add( 0, new SortKey( modelColumn, sortOrder ) );
        }
        int to = editableSortKeys.size();
        for ( SortKey postColumn : postColumns ) {
          int modelColumn = postColumn.getColumn();
          int idx = indexOfColumn( editableSortKeys, preColumns.length, to, modelColumn );
          SortOrder sortOrder;
          if ( idx < 0 )
            sortOrder = postColumn.getSortOrder();
          else {
            sortOrder = editableSortKeys.remove( idx ).getSortOrder();
            to--;
          }
          editableSortKeys.add( new SortKey( modelColumn, sortOrder ) );
        }
        if ( wasChanged = !editableSortKeys.equals( newSortKeys ) )
          setSortKeysInternal( editableSortKeys );
      }
      if ( getViewToModelInternal() == null )
        sort();
      else
        sortExistingDataInternal();
      if ( wasChanged )
        setSortKeysInternal( newSortKeys );
    }
  }

  private int indexOfColumn( List< SortKey > sortKeys, int fromIncl, int toExcl, int column ) {
    for ( int i = toExcl - 1; i >= fromIncl; i-- )
      if ( sortKeys.get( i ).getColumn() == column )
        return i;
    return -1;
  }
};

用法:

table.setRowSorter( new PredefinedRowSorter( table )
  .withPreColumns( new SortKey( 0, SortOrder.ASCENDING ),
                   new SortKey( 1, SortOrder.ASCENDING ) ) );

这将在前两列中设置前面的排序.

This would set a preceding sorting on first two columns.

可以进行后排序.

最终用户也可以对这两列进行排序,从而切换排序顺序(升/降).

An end-user may sort these two columns too, thus switching the order of sorting (ascending/descending).

此外,此类可作为JBroTable库的一部分提供(

Also, this class is available as a part of JBroTable library (source code).

操作原理是这样的:将预定义的列在排序之前添加到排序列列表中,并在排序后从该列表中删除.添加和删​​除是通过反射执行的,因为DefaultRowSorter实现无法提供对列表的访问.

The principle of action is so: predefined columns are added to a sorting columns list before sorting and removed from this list after sorting. Adding and removal is performed via reflection because DefaultRowSorter implementation doesn't provide an access to the list.

这篇关于Java JTable:将主列设置为始终按第一排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆