2013-09-08 2 views
0

Я пытаюсь получить свой JTable для сортировки нулевых значений в конце таблицы. Это похоже на поток, найденный в SO (How can i sort java JTable with an empty Row and force the Empty row always be last?) и OTN (https://forums.oracle.com/thread/1351003), но ответы в этих потоках мне не очень понятны.Как сортировать jtable с нулевыми значениями всегда в конце

Я сделал большой прогресс, используя эти ответы, хотя, и я дошел до SSCCE, размещенного ниже. Но я все еще пытаюсь выяснить, как получить нулевые значения (или, в опубликованном SSCCE, NullClassFiller), чтобы всегда идти в нижней части сортировки. Я чувствую, что если бы я мог в пределах обычаев Comparator как-то знал, какое направление сортируется (по восходящему или нисходящему), я мог бы легко это сделать. Но Comparator не знает направления сортировки ...

Кто-нибудь?

import java.awt.Component; 
import java.util.Comparator; 
import javax.swing.DefaultRowSorter; 
import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.table.DefaultTableCellRenderer; 
import javax.swing.table.DefaultTableModel; 

public class Test { 

    public static void main(String args[]) { 
     JFrame frame = new JFrame(); 
     JTable table = new JTable(); 
     Object[][] data = new Object[8][3]; 
     data[0][0] = 6.5d; data[0][1] = "Name1"; 
     data[1][0] = new NullClassFiller(); data[1][1] = "Name2"; 
     data[2][0] = 2.6d; data[2][1] = "Name3"; 
     data[3][0] = 0d; data[3][1] = "Name4"; 
     data[4][0] = new NullClassFiller(); data[4][1] = "Name5"; 
     data[5][0] = -4d; data[5][1] = "Name6"; 
     data[6][0] = 0d; data[6][1] = "Name7"; 
     data[7][0] = -4.3d; data[7][1] = "Name8"; 
     table.setModel(new DefaultTableModel(data, new String[]{"One", "Two"})); 
     table.setAutoCreateRowSorter(true); 
     DefaultRowSorter<?, ?> sorter = (DefaultRowSorter<?, ?>) table.getRowSorter(); 
     sorter.setComparator(0, new CustomComparator()); 
     table.getColumnModel().getColumn(0).setCellRenderer(new CustomRenderer()); 
     JScrollPane pane = new JScrollPane(table); 
     frame.add(pane); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setSize(500, 500); 
     frame.setVisible(true); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 

    static class CustomComparator implements Comparator<Object> { 
     @Override 
     public int compare(Object d1, Object d2) { 
      if (d1 instanceof NullClassFiller) { 
       return -1; 
      } else if (d2 instanceof NullClassFiller) { 
       return -1; 
      } else { 
       return ((Comparable<Object>) d1).compareTo(d2); 
      } 
     } 
    } 

    static class NullClassFiller {} 

    static class CustomRenderer extends DefaultTableCellRenderer { 

     @Override 
     public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 
      DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); 

      if(value instanceof NullClassFiller) 
       renderer.setText(""); 

      return renderer; 
     } 

    } 
} 
+0

Возможный дубликат [Java Comparator всегда считывает значения как строки] (http://stackoverflow.com/questions/18680682/java-comparator-always-reading-values-as-stri ngs) – mKorbel

+1

Хмм, не совсем понимаю вашу проблему с ответом/с в OTN - это просто невозможно сделать чистым способом, за исключением полной перезаписи DefaultRowSorter и TableRowSorter. Все остальные хаки рано или поздно будут ломаться. – kleopatra

+0

@ kleopatra, проблема с (рабочими) решениями в OTN: их беспокоит только одна единственная пустая строка в конце, поэтому большинство из них - это хаки, которые включают нечто вроде public static final Object EMPTY_ROW = ""; , Это не работает для меня, потому что у меня много пустых строк. Вы говорите: «это просто невозможно сделать чистым способом, за исключением полной перезаписи DefaultRowSorter и TableRowSorter». что здорово, я готов укусить пулю и полностью переписать, я просто не знаю, как это сделать. Это моя попытка сделать именно это. – ryvantage

ответ

0

Насколько все, кажется, ненавидят мои вопросы, я надеюсь, что эти вопросы дадут некоторую пользу другим в долгосрочной перспективе. Я очень много работаю, чтобы задавать соответствующие вопросы, поэтому мои извинения, если они запутывают или слишком специфичны для моих потребностей, могут оказать какую-либо помощь другим. Опять же, я считаю, что они будут.

В любом случае, я решил проблему благодаря @MadProgrammer и @kleopatra через следующий вопрос (Java Comparator always reading values as Strings) У меня было.

Ответ создать пользовательский Comparator, который может определить, каким образом таблица сортируется, а затем возвращает правильное значение соответственно (если сортировка ASCENDING затем o1 должен возвращать 1 и -1 наоборот, и o2 является точно наоборот).

На мой взгляд, это не стоит многого, это не ТРУДНО, а решает мою проблему, поэтому я доволен, даже если другие нет.

Вот полный код моего решения:

import java.awt.Component; 
import java.util.Comparator; 
import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.SortOrder; 
import javax.swing.table.DefaultTableCellRenderer; 
import javax.swing.table.DefaultTableModel; 
import javax.swing.table.TableModel; 
import javax.swing.table.TableRowSorter; 

public class Test { 

    public static void main(String args[]) { 
     JFrame frame = new JFrame(); 
     Object[][] data = new Object[8][3]; 
     data[0][0] = 6.5d; data[0][1] = "Name1"; 
     data[1][0] = new NullClassFiller(); data[1][1] = "Name2"; 
     data[2][0] = 2.6d; data[2][1] = "Name3"; 
     data[3][0] = 0d; data[3][1] = "Name4"; 
     data[4][0] = new NullClassFiller(); data[4][1] = "Name5"; 
     data[5][0] = -4d; data[5][1] = "Name6"; 
     data[6][0] = 0d; data[6][1] = "Name7"; 
     data[7][0] = -4.3d; data[7][1] = "Name8"; 
     JTable table = new JTable(); 
     table.setModel(new DefaultTableModel(data, new String[]{"One", "Two"}) { 
      @Override 
      public Class<?> getColumnClass(int column) { 
       return column == 0 ? Double.class : String.class; 
      } 
      @Override 
      public boolean isCellEditable(int row, int column) { 
       return false; 
      } 
     }); 

     TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(table.getModel()) { 
      @Override 
      public Comparator<?> getComparator(final int column) { 
       Comparator c = new Comparator() { 
        @Override 
        public int compare(Object o1, Object o2) { 
         boolean ascending = getSortKeys().get(column).getSortOrder() == SortOrder.ASCENDING; 
         System.out.println(o1.getClass() + " - " + o2.getClass()); 
         if (o1 instanceof NullClassFiller) { 
          if(ascending) 
           return 1; 
          else 
           return -1; 
         } else if (o2 instanceof NullClassFiller) { 
          if(ascending) 
           return -1; 
          else 
           return 1; 
         } else { 
          return ((Comparable<Object>) o1).compareTo(o2); 
         } 

        } 
       }; 
       return c; 
      } 
     }; 
     table.setRowSorter(sorter); 
     table.getColumnModel().getColumn(0).setCellRenderer(new CustomRenderer()); 
     JScrollPane pane = new JScrollPane(table); 
     frame.add(pane); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setSize(500, 500); 
     frame.setVisible(true); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 

    static class NullClassFiller {} 

    static class CustomRenderer extends DefaultTableCellRenderer { 

     @Override 
     public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 
      DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); 

      if(value instanceof NullClassFiller) 
       renderer.setText(""); 

      return renderer; 
     } 

    } 
} 

В моей должности, я создавал обычай Comparator, но он не имел доступа к getSortKeys(). Итак, я переписал метод getComparator() в TableRowSorter, чтобы получить доступ к getSortKeys(). Оно работает.

+1

извините, это все еще неправильно, пожалуйста, внимательно прочитайте мой ответ на свой другой вопрос (здесь вы разрешаете только 1 из 3 пуль). Кроме того, я не понимаю, почему вы не используете повторно [оберточное решение Уолтера] (https://forums.oracle.com/message/5691827#5691827) - это, безусловно, второе место (не переписывая Сортировщик), которое я когда-либо видел и действительно решал ваш прецедент (без необходимости использования nullFiller). – kleopatra

+0

плюс ваша реализация модели очень неправильная: если модель возвращает тип столбца, отличный от объекта, он должен ** гарантировать, что этот тип должен содержать только этот тип. Ваш не для первого ... – kleopatra

+0

_by far the second best_, за исключением того, что он имеет небольшую ошибку: оболочка должна возвращать EMPTY_LAST_ROW (против NULL_VALUE), если значение реальной модели равно нулю – kleopatra

0

Вызов getSortKeys().get() должен использовать 0 (то есть главный ключ сортировки), а не столбец:

boolean ascending = getSortKeys().get(0).getSortOrder() == SortOrder.ASCENDING; 

Если пользователь нажимает, например, через колонку номер 12 или 7, вы нужен первый ключ сортировки (будет максимум 3, если пользователь нажал перед другими столбцами, чтобы выполнить сортировку нескольких столбцов).Этот ключ сортировки будет иметь два атрибута:

  1. сортировку (восходящие, нисходящие, UNORDERED)

    getSortKeys().get(0).getSortOrder() 
    
  2. Индекс столбца (12 или 7, например)

    getSortKeys().get(0).getColumn()