# Eigenen RowSorter



## Erloes (29. Mai 2010)

Ich bin schon seit stunden am Suchen nach einem Tutorial oder Beispiel für das definieren eines eigenen RowSorter. Ich habe folgendes 
[Java]
    public class Sortierer extends RowSorter<MyTableModel>{
       List<? extends SortKey> keys = null;

    	@Override
    	public int convertRowIndexToModel(int index) {
    		return index;
    	}
    	@Override
    	public int convertRowIndexToView(int index) {
    		return index;
    	}
    	@Override
    	public MyTableModel getModel() {
    		return null; //Kein Plan wie
    	}
    	@Override
    	public int getModelRowCount() {
    		return 0; //Kein Plan wie
    	}
    	@Override
    	public List<? extends javax.swing.RowSorter.SortKey> getSortKeys() {
    		return keys;
    	}
    	@Override
    	public int getViewRowCount() {
    		return getModelRowCount();
    	}
    	@Override
    	public void modelStructureChanged() {}
    	@Override
    	public void rowsDeleted(int firstRow, int endRow) {}
    	@Override
    	public void rowsInserted(int firstRow, int endRow) {}
    	@Override
    	public void rowsUpdated(int firstRow, int endRow) {}
    	@Override
    	public void rowsUpdated(int firstRow, int endRow, int column) {}
    	@Override
    	public void setSortKeys(List<? extends RowSorter.SortKey> keys) {
    		this.keys = keys;
    	}
    	@Override
    	public void allRowsChanged() {
    		//Hier kommt nocht sortieren
    	}
    	@Override
    	public void toggleSortOrder(int column) {
    		//Hier auch
    	}
    } 
[/Java]

Jetzt mache ich JTable.setRowSorter(Sortierer); Übersetzen funktioniert aber beim testen kommt der Fehler NullPointerException: null (in sun.swing.table.DefaultTableCellHeaderRenderer). Ich verstehe warum jeder den Standard RowSorter benutzt, aber wir müssen das für Uni mit einer eigenen Klasse die von RowSorter erbt machen und es wurden uns keinerlei Informationen dazu gegeben wie man das möglicherweise machen könnte.


----------



## Ebenius (29. Mai 2010)

[c]keys[/c] sollte mit einer leeren Liste initialisiert werden, nicht mit [c]null[/c]. Ansonsten solltest Du Dir die Klasse TableRowSorter erstmal ansehen. Den Source-Code und die API-Documentation findest Du schon.

Ebenius


----------



## Erloes (29. Mai 2010)

Also das hat mir jetzt mal garnicht weitergeholfen. new List() geht nicht da steht java.util.List ist abstrakt , die Dokumentation dazu habe ich schon gefunden RowSorter (Java Platform SE 6) aber das bringt mir nichts, dort steht ja nicht drin was z.B. in der convertRowIndexToView drin stehen muss etc. Mir würde ein einziges Beispiel für einen eigenen RowSorter ausreichen um das dann verstehen und nutzen zu können. Selbst wenn das mit der Fehlermeldung hinbekomme weiß ich immernoch nicht wie man z.B. in toggleSortOrder sortieren kann. Habe schon einen Sortieralgorithmus in einer Methode drin und möchte/muss diesen benutzen.

EDIT: Ich bin jetzt drauf gekommen, java.util.List ist ein Interface. Muss ich dann = new ArrayList(); machen oder new Vector()????? Ich hab das jetzt mit new ArrayList() gemacht und jetzt kommt der Fehler nicht mehr aber die Tabelle ist komplett leer und man kann nicht auf die dinger klicken zum sortieren. Bzw. muss ich implements List machen oder so?


----------



## Erloes (29. Mai 2010)

Sorry Ebenius ich habe dir Unrecht getan, seitdem ich die Liste mit = new ArrayList() gemacht habe ergibt sich alles nacheinander von selbst, vielen Dank. Ich habe jetzt auch wieder die Zeilen, da getModel() und getModelRow() jetzt richtig implementiert sind. Aber auf die Zeilen kann man immernoch nicht klicken und ich weiß auch nicht wie man das sortieren verwenden kann. Ich hab einen Sortieralgorithmus der einen beliebigen Typ von Array annehmen kann und diesen nach einem bestimmten Comparator sortiert.


----------



## Ebenius (30. Mai 2010)

Ich wiederhole einfach nochmal das was ich oben schon schrieb: Schau Dir den Quelltext und die API-Doc von TableRowSorter an. Dann verstehst Du die Funktionsweise besser als ich sie Dir erklären kann. Glaube ich zumindest.

… mühsam ernährt sich das Eichhörnchen.  

Ebenius


----------



## ISO 9891 (30. Mai 2010)

Kann mir vielleicht einer verraten, wo der Quelltext zur TableRowSort zu finden ist? Bei der Suche danach bin ich hier bei euch gelandet. Die API-Dokumentation nutzt nämlich nichts


----------



## eRaaaa (30. Mai 2010)

javax.swing.table: TableRowSorter.java

ansonsten findet man die sourcen oft auch in "pfad zu java/src.zip"


----------



## ISO 9891 (30. Mai 2010)

Aha, danke.

Nun sagt mir aber die Aufgabenstellung (ich glaube Erloes und ich studieren zusammen, weil so eine blöde Aufgabenstellung gibt es bestimmt nicht zwei mal), dass das Sortieren durch den Aufruf von allRowsChanged, setSortKeys und toggleSortOrder geschehen soll.
Die tauchen in TableRowSorter nicht auf, allerdings in DefaultRowSorter. Das scheint mir aber kein gutes Muster zu sein daraus werde ich auch nicht schlauer.

Ich habe keine Ahnung, was in diese Methoden rein soll und werde aus der Dokumentation nicht wirklich schlau.

Eine Sortiermethode habe ich (wie Erloes auch  schon schrieb).

Es wäre sehr nett, wenn mir irgendwer weiterhelfen könnte (Ich suche Hilfe immer erst, wenn es wirklich brenzlig wird).
Naja, vielleicht kann ja einer aus dem Stegreif helfen, ohne sich groß vertiefen zu müssen. Ich gebe daneben mein Bestes selbst auf eine Lösung zu kommen


und mal ne andere Frage:
Wie komme ich an Klassen wie TableRowSorter oder DefaultRowSorter ran OHNE sie abschreiben zu müssen? copy+paste geht ja nicht, weil da immer die Zeilennummern dranhängen. Das würde vielleicht mal zum Verständnis beitragen, wenn man die selbst Testen könnte.


----------



## Erloes (30. Mai 2010)

Also bei mir siehts auch so aus, jetzt versuche ich den DefaultRowSorter so Nachzubauen wie ich ihn brauche auch wenn ich den garnicht verstehe. Mein Problem ist bei private Row[] viewToModel; ein Fehler kommt das Row unbekannt ist, ich hab überall gesucht und die Klasse nicht gefunden also was muss ich importieren damit das klappt?


----------



## Ebenius (30. Mai 2010)

So Kinders, hier mal ein lieblos runtergeschriebener, innefizienter RowSorter, der nur Integer und toString()-Rückgabewerte (ignore case) sortieren kann. Er sortiert immer alles, auch bei jedem Update aus dem Tabellenmodell. Es ist definitiv nicht zu empfehlen, diesen RowSorter irgendwo produktiv einzusetzen, aber er funktioniert und ist nicht so sehr kompliziert:


```
/* (@)SimpleTableRowSorter.java */

/* Copyright 2010 Sebastian Haufe

 * Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       [url]http://www.apache.org/licenses/LICENSE-2.0[/url]

 * Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

package com.ebenius;

import java.util.*;

import javax.swing.RowSorter;
import javax.swing.SortOrder;
import javax.swing.table.TableModel;

/**
 * Simple, inefficient row sorter implementation, comparing Integers and
 * toString() result. Always does complete sorting. Sorts (completely!) on
 * update!
 * <p>
 * Never use this class for production, it is intended to demonstrate the way
 * row sorters might work.
 * 
 * @version $Revision$ as of $Date$
 * @author Sebastian Haufe
 */
public class SimpleTableRowSorter extends RowSorter<TableModel>
  implements java.io.Serializable {

  /** Serial version UID */
  private static final long serialVersionUID = 1L;

  // -------------------------------------------------------------------------
  // Instance fields
  // -------------------------------------------------------------------------

  private final TableModel model;
  private final List<SortKey> sortKeys = new ArrayList<SortKey>();
  private final List<Integer> viewRowToModel = new ArrayList<Integer>();

  // -------------------------------------------------------------------------
  // Constructors
  // -------------------------------------------------------------------------

  /**
   * Creates a new <code>SimpleTableRowSorter</code>.
   * 
   * @param model the data model to wrap
   */
  public SimpleTableRowSorter(TableModel model) {
    this.model = model;
    sort();
  }

  // -------------------------------------------------------------------------
  // Simple sorting implementation
  // -------------------------------------------------------------------------

  @SuppressWarnings("boxing")
  private void sort() {
    final int modelRowCount = getModelRowCount();

    /* highly inefficient; completely rebuild the mapping list */

    viewRowToModel.clear();
    for (int i = 0; i < modelRowCount; i++) {
      viewRowToModel.add(i);
    }

    /* if we don't have sort keys, don't do any sorting */
    if (!sortKeys.isEmpty()) {
      final TableModel tableModel = this.model;
      final Iterable<? extends SortKey> sortKeys = this.sortKeys;
      Collections.sort(viewRowToModel, new Comparator<Integer>() {

        public int compare(Integer modelRow1, Integer modelRow2) {
          for (SortKey key : sortKeys) {
            final int modelColumn = key.getColumn();

            /* reverse the result, if sorting is DESCENDING */
            final SortOrder sortOrder = key.getSortOrder();
            final boolean reverse;
            switch (sortOrder) {
            case ASCENDING:
              reverse = false;
              break;
            case DESCENDING:
              reverse = true;
              break;
            default:
              continue;
            }

            /* compare the values; just Integer and toString() */
            Object val1 = tableModel.getValueAt(modelRow1, modelColumn);
            Object val2 = tableModel.getValueAt(modelRow2, modelColumn);
            final int result;
            if (val1 instanceof Integer && val2 instanceof Integer) {
              result = ((Integer) val1).compareTo((Integer) val2);
            } else {

              /* no integer, then compare the toString() result ign. case */
              final String s1 = val1 == null ? "" : val1.toString();
              final String s2 = val2 == null ? "" : val2.toString();

              if (s1 == null) {
                result = -1;
              } else if (s2 == null) {
                result = 1;
              } else {
                result = s1.compareToIgnoreCase(s2);
              }

            }

            /* we have a result; return... */
            if (result != 0) {
              return reverse ? -result : result;
            }
          }

          return 0;
        }
      });
    }
  }

  // -------------------------------------------------------------------------
  // RowSorter :: Index mapping
  // -------------------------------------------------------------------------

  @SuppressWarnings("boxing")
  @Override
  public int convertRowIndexToModel(int index) {
    return viewRowToModel.get(index);
  }

  @SuppressWarnings("boxing")
  @Override
  public int convertRowIndexToView(int index) {
    return viewRowToModel.indexOf(index);
  }

  @Override
  public int getViewRowCount() {
    return viewRowToModel.size();
  }

  @Override
  public int getModelRowCount() {
    return model.getRowCount();
  }

  // -------------------------------------------------------------------------
  // RowSorter :: Changes in the data model
  // -------------------------------------------------------------------------

  @Override
  public void allRowsChanged() {
    sort();
    fireRowSorterChanged(null);
  }

  @Override
  public void modelStructureChanged() {
    sort();
    fireRowSorterChanged(null);
  }

  @Override
  public void rowsDeleted(int firstRow, int endRow) {
    sort();
    fireRowSorterChanged(null);
  }

  @Override
  public void rowsInserted(int firstRow, int endRow) {
    sort();
    fireRowSorterChanged(null);
  }

  @Override
  public void rowsUpdated(int firstRow, int endRow) {
    sort();
    fireRowSorterChanged(null);
  }

  @Override
  public void rowsUpdated(int firstRow, int endRow, int column) {
    sort();
    fireRowSorterChanged(null);
  }

  // -------------------------------------------------------------------------
  // RowSorter :: Sorting by columns (called by the table header)
  // -------------------------------------------------------------------------

  @Override
  public void toggleSortOrder(int column) {
    SortOrder order = SortOrder.UNSORTED;
    for (ListIterator<SortKey> it = sortKeys.listIterator(); it.hasNext();) {
      final int keyIndex = it.nextIndex();
      final SortKey key = it.next();
      if (key.getColumn() == column) {
        it.remove();

        /* toggle sort order on first level only. all others toggle to
           ASCENDING */
        if (keyIndex == 0) {
          order = key.getSortOrder();
        }

        break;
      }
    }

    /* from old order to new order */
    switch (order) {
    case ASCENDING:
      order = SortOrder.DESCENDING;
      break;
    case DESCENDING:
      order = SortOrder.UNSORTED;
      break;
    case UNSORTED:
      order = SortOrder.ASCENDING;
      break;
    }

    sortKeys.add(0, new SortKey(column, order));
    sort();
    fireSortOrderChanged();
  }

  // -------------------------------------------------------------------------
  // Bean getters and setters
  // -------------------------------------------------------------------------

  @Override
  public TableModel getModel() {
    return model;
  }

  @Override
  public List<SortKey> getSortKeys() {
    return sortKeys;
  }

  @Override
  public void setSortKeys(List<? extends SortKey> keys) {
    this.sortKeys.clear();
    this.sortKeys.addAll(keys);
    sort();
    fireSortOrderChanged();
  }
}
```
Hier eine TestGui dazu:

```
/* (@)SimpleTableRowSorterTestGui.java */

/* Copyright 2010 Sebastian Haufe

 * Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       [url]http://www.apache.org/licenses/LICENSE-2.0[/url]

 * Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

package com.ebenius;

import java.awt.BorderLayout;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;

/**
 * TODO: Javadoc me!
 * 
 * @version $Revision$ as of $Date$
 * @author Sebastian Haufe
 */
public class SimpleTableRowSorterTestGui {

  /** Creates the GUI. Call on EDT, only! */
  static void createAndShowGui() {
    final TableModel model =
          new DefaultTableModel(new Object[][] { //
                { "Huhu", Integer.valueOf(0) },
                  { "Hallo", Integer.valueOf(-4) },
                  { "Moin", Integer.valueOf(16) },
                  { "Guten Tag", Integer.valueOf(20) },
                  { "Ave", Integer.valueOf(-10) },
                  { "Servus", Integer.valueOf(-4) }, }, //
                new String[] { "Text", "Zahl" }) {

            /** Serial version UID */
            private static final long serialVersionUID = 1L;

            @Override
            public Class<?> getColumnClass(int columnIndex) {
              switch (columnIndex) {
              case 1:
                return Integer.class;

              default:
                return String.class;
              }
            }
          };

    final JTable table = new JTable(model);
    table.setRowSorter(new SimpleTableRowSorter(model));

    final JPanel contentPane = new JPanel(new BorderLayout(6, 6));
    contentPane.add(new JScrollPane(table));

    final JFrame f = new JFrame("Test Frame: SimpleTableRowSorterTestGui"); //$NON-NLS-1$
    f.setContentPane(contentPane);
    f.pack();
    f.setLocationRelativeTo(null);
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.setVisible(true);
  }

  /** @param args ignored */
  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {

      public void run() {
        createAndShowGui();
      }
    });
  }
}
```
Ebenius


----------



## Erloes (31. Mai 2010)

Ey vielen Dank das du den hier reingeschrieben hast, aber genau und ich meine fast genau nachdem ich es mit sehr viel rumprobieren irgendwie hinbekommen habe so das ich bei Methoden wie convertRowIndexToModel einfach return index gemacht habe etc. Aber das toggleSortOrder konnte ich aus dem DefaultRowSorter rekonstruieren, also bei mir sieht das etwas anders aus aber es funktioniert auch (toggleSortOrder ruft bei mir einfach setSortKeys auf). Trotzdem danke, da dies mir bei den anderen Methoden weiterhilft und das kann man dann später fürs Filtern nutzen.


----------



## Ebenius (31. Mai 2010)

Na denn mal: Happy Hacking! 

Ebenius


----------

