JTable mit einer Klasse (Struktur) erstellen und sortieren

Status
Nicht offen für weitere Antworten.

thE_29

Top Contributor
Zuerst möchte ich folgendes sagen, das Benis Tutorials wahrscheinleich leichter zu handhaben und zu verstehen sind!

Außerdem haben seine Tutorials eine schöne "Hilfe" dabei, was meines nicht hat, aber trotzdem will ich mein JTable der Welt nicht vorenthalten!

Es wird mitHilfe einer inneren Klasse (Struktur) die Daten abgespeichert und in eine ArrayList geschrieben (nachher ein Objekt)! Diese wird dann sequentiell ausgelesen und mit getValueAt hineingeschrieben!
Als erstes ist der Aufruf (die imports habe ich dort weggelassen!)

Code:
//Aufruf in der anderen Klasse

public void showTable()
{
    TabModel m_tabmod = new TabModel();
    //hier dann Laden, oder sonst wo laden
    m_tabmod.loadFromAFile(new File("/home/test");
    //oder Datenbank
    m_tabmod.loadFromADataBase();
    JTable m_tab = new JTable(m_tabmod);
    JTableHeader hdr = (JTableHeader) m_tab.getTableHeader();
    hdr.addMouseListener(new MouseAdapter()
    {
      public void mousePressed(MouseEvent e)
      {
        if (e.getButton() == MouseEvent.BUTTON1)
        {
          final SortDecorator decorator = new SortDecorator(m_tabmod.getModel().
            getModel());
          TableColumnModel tcm = m_tab.getColumnModel();
	  int vc = tcm.getColumnIndexAtX(column.getX());
	  int mc = m_tab.convertColumnIndexToModel(vc);
	  //sortiert nach angeklickter Spalte
          if(e.getModifiers() == 18) //strg + mausklick!
   	    decorator.sort(mc,true);
          else
            decorator.sort(mc,false);// mausklick + irgendwas (oder nur mausklick)

	  //setzt das neue Model
	  m_tabmod.setModel(decorator);
	  m_tab.getTableHeader().setDefaultRenderer(decorator); //setzt die Pfeile
	}
      }
    }
}

Wie man das Table dann anzeigen lässt (ScrollPane, oder direkt auf ein Panel ist euch überlassen!!!)

Nun kommt die TabModel Klasse, die für euch die Daten in ein JTable schreibt!

Code:
import java.io.*;
import java.util.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;

/*
Es sind nicht alle Funktionen ausprogrammiert (so wie setValueAt(..) usw!

Es sind nur diese Funktionen ausprogrammiert, die man auch braucht fürs auslesen/anzeigen
und für das sortieren!


(das Statement braucht außerdem noch eine Verbindung! - man könntes mitübergeben bei der loadfunktion!)
*/

public class TabModel
    extends AbstractTableModel
{
  String[] columnNames =
      {
      "", "", "", "", "", "", ""}; //ßberschriften der Tabelle

  private Object data[];
  private Statement stm = null;
  private ResultSet rs = null;
  private ArrayList ar = null;
  private boolean bErg = true;

  /**************************************************************************
   * Konstruktor für TabModel, indem die Spaltenbezeichnungen definiert werden
   * und initDateTable wird aufgerufen
   *************************************************************************/
  public TabModel()
  {
    try
    {
      columnNames[0] = "1";
      columnNames[1] = "2";
      columnNames[2] = "3";
      columnNames[3] = "4";
      columnNames[4] = "5";
      columnNames[5] = "6";
      columnNames[6] = "7";
    }
    catch (Exception ex)
    {
      ex.printStackTrace();
    }

  }

  /***************************************************************************
   * Spaltenanzahl
   * @return Anzahl der Spalten
   *************************************************************************/
  public int getColumnCount()
  { //Anzahl der Spalten
    return columnNames.length;
  }

  /***************************************************************************
   * Zeilenanzahl
   * @return Anzahl der Zeilen
   *************************************************************************/
  public int getRowCount()
  { //Anzahl der Zeilen
    if (data == null)
      return 0;
    return (data.length);
  }

  /**************************************************************************
   * Name einer Spalte
   * @param iCol Position der Spalte
   * @return Name der übergebenen Spalte
   *************************************************************************/
  public String getColumnName(int iCol)
  { //Name der Spalten
    return columnNames[iCol];
  }

  /**************************************************************************
   * Wert einer Spalte in einer bestimmten Zeile
   * @param iRow Index der Zeile
   * @param iCol Position der Spalte
   * @return Wert an der Stelle row / col
   *************************************************************************/
  public Object getValueAt(int iRow, int iCol)
  { //Retouniert Wert an bestimmter Stelle
    Object objRet = null;

    if (iRow < data.length && data[iRow] != null) // gibt die Objekte zurück
    {
      Pay_d pl = (Pay_d) data[iRow];
      switch (iCol)
      {
        case 0:
          objRet = Short.toString(pl.Pay_id); 
          break;
        case 1:
          objRet = Short.toString(pl.Pay_sub);
          break;
        case 2:
          objRet = pl.txt;
          break;
        case 3:
          objRet = Short.toString(pl.for_currid);
          break;
        case 4:
          objRet = Short.toString(pl.for_fakt);
          break;
        case 5:
          objRet = Integer.toString(pl.bonuspnkt);
          break;
        case 6:
          objRet = Integer.toString(pl.for_kurs);
          break;

      }
    }
    return objRet;
  }


  /*************************************************************************
   * Hinweis: Je für Programm abänderbar
   * @param row Index der Zeile
   * @param col Position der Spalte
   * @return false für not editable, true für editable
   *************************************************************************/
  public boolean isCellEditable(int row, int col)
  {
    return false;
  }


  /**************************************************************************
   * Lädt die Daten von der Datenbank einmal in datatable und einmal in einen array
   * und danach in data
   *************************************************************************/
  public void loadFromADatabase()
  {
    try
    {
      ar = new ArrayList();

      //führt den SQL Befehl aus
      rs = stm.executeQuery("SELECT * FROM PAY_D"); //man kann die Daten auch anders holen, und zwar File einlesen, usw

      if (!rs.next()) // falls es kein nächstes gibt
        bErg = false;

      if (bErg) // default mäßig auf true, falls es kein Ergebnis gibt geht er nicht rein
      {
        do
        {
          bErg = true;
          Pay_d pl = new Pay_d();
          pl.Pay_id = rs.getShort(1);
          pl.Pay_sub = rs.getShort(2);
          pl.txt = rs.getString(3);
          pl.for_currid = rs.getShort(4);
          pl.bonuspnkt = rs.getInt(5);
          pl.for_kurs = rs.getInt(6);
          pl.for_fakt = rs.getShort(7);

          ar.add(pl); //fügt die Klasse in den Array hinzu

        }
        while (rs.next()); //solange es einen nächsten gibt
      }

      rs.close();
      stm.close();
      data = ar.toArray(); // Array wird in ein Objekt geholt um es nachher für die Table auszugeben
      fireTableDataChanged(); // lässt die Tabelle neu zeichnen
    }
    catch (Exception ex)
    {
      ex.printStackTrace();
    }
  }

  /*************************************************************************
   * Beispiel lädt Daten aus einer Datei die mit ; getrennt sind
   * @param fFile die Datei
   ************************************************************************/
  public void loadFromAFile(File fFile)
  {
    int iAnzToken; // abfrage auf wieviel ; die linie hat
    StringTokenizer token;
    String line = "",buf[];

    try{
      //reader um aus der Datei zu lesen
      BufferedReader br = new BufferedReader(
          new InputStreamReader(
          new FileInputStream(fFile)));

      //Arrayliste neu initialisieren
      ar = new ArrayList();
      while ( (line = br.readLine()) != null)
      {
        token = new StringTokenizer(line, ";", false); //wird davon ausgegangen das es mit ; getrennt ist
        iAnzToken = token.countTokens();
        buf = new String[iAnzToken];
        for(int x = 0; x != iAnzToken && token.hasMoreTokens(); x++)
          buf[x] = token.nextToken();

        Pay_d pl = new Pay_d();
        pl.Pay_id = Short.parseShort(buf[0]);
        pl.Pay_sub = Short.parseShort(buf[1]);
        pl.txt = buf[2];
        pl.for_currid = Short.parseShort(buf[3]);
        pl.for_fakt = Short.parseShort(buf[4]);
        pl.bonuspnkt = Integer.parseInt(buf[5]);
        pl.for_kurs = Integer.parseInt(buf[6]);


        ar.add(pl); //fügt die Klasse in den Array hinzu
      }

     }
     catch(Exception ex)
     {
       ex.printStackTrace();
     }
  }

  /****************************************************************************
   * Funktion liefert ein JTable zurück
   * @return ein JTable objekt
   ***************************************************************************/
  public JTable getModel()
  {
    return new JTable(this);
  }

  /****************************************************************************
   * Setzt das Model neu!
   * @param TableModel1 das tablemodel das gesetzt werden soll
   ***************************************************************************/
  public void setModel(TableModel TableModel1)
  {
    ar = new ArrayList(); //alles neu schreiben
    for (int x = 0; x != TableModel1.getRowCount(); x++)
    {
      //neues Objekt zum Einhängen
      Pay_d pl = new Pay_d();
      for (int y = 0; y != TableModel1.getColumnCount(); y++)
      {
        switch (y)
        {
          case 0:
            pl.Pay_id = Short.parseShort(TableModel1.getValueAt(x, y).toString());
            break;
          case 1:
            pl.Pay_sub = Short.parseShort(TableModel1.getValueAt(x, y).toString());
            break;
          case 2:
            pl.txt = TableModel1.getValueAt(x, y).toString();
            break;
          case 3:
            pl.for_currid = Short.parseShort(TableModel1.getValueAt(x, y).toString());
            break;
          case 4:
            pl.for_fakt = Short.parseShort(TableModel1.getValueAt(x, y).toString());
            break;
          case 5:
            pl.bonuspnkt = Integer.parseInt(TableModel1.getValueAt(x, y).toString());
            break;
          case 6:
            pl.for_kurs = Integer.parseInt(TableModel1.getValueAt(x, y).toString());
            break;
        }
      }
      ar.add(lV);
    }

    data = ar.toArray(); // Array wird in ein Objekt gespeichert um es nachher für die Table auszugeben
  }




  /**************************************************************************
   * Hilfsklasse, da die existierende Klasse nicht genommen werden kann,
   * wegen eines Subsselects
   *************************************************************************/
  class Pay_d
  {
    short Pay_id; //Pay_id aus Datenbank           Pay_d
    short Pay_sub; //Pay_sub aus Datenbank          Pay_d
    String txt; // Bezeichnung aus Datenbank       Pay_d
    short for_currid; //Fremdwährungs Nummer aus Datenbank    Pay_d
    short for_fakt; // Faktor für Kommazeichen      Kurse
    int bonuspnkt; // Bonuspunkte aus Datenbank     Pay_d
    int for_kurs; // Kurs ohne Kommazeichen        Kurse
  }
}


Es sind 2 Funktionen zum Laden drinnen! Einmal von einer Datenbank und einmal aus einer Datei, falls ihr die Daten per Hand in die Struktur schreiben wollt, könnt ihr das auch tun, aber für das brauch ich woll kein Beispiel geben!


Nun der SortDecorator der euch die Tabelle auch schön brav nach ABC sortiert und die Pfeile reinmacht (die Pfeile wurden von Benis Beispiel genommen - Danke!)

Code:
import java.util.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;


public class SortDecorator
    extends DefaultTableCellRenderer
    implements TableModel, TableModelListener
{
  private TableModel realModel;
  private int indexes[];
  private static int iColumn = 0;
  private static boolean bDescending = true;
  private static ArrayList arSorter = null;
  private static final double FACTOR = 0.95;

  /****************************************************************************
   * Konstruktor fürs Sortieren
   * @param model model das übergeben wird
   ***************************************************************************/
  public SortDecorator(TableModel model)
  {
    if (model == null)
      throw new IllegalArgumentException("null models are not allowed");
    this.realModel = model;
    realModel.addTableModelListener(this);
    allocate();
  }



  /****************************************************************************
   * wenn sich was ändert
   * @param tableModelEvent t
   ***************************************************************************/
  public void tableChanged(TableModelEvent tableModelEvent)
  {
    allocate();
  }



  /****************************************************************************
   * neue indexes werden allociert
   ***************************************************************************/
  private void allocate()
  {
    indexes = new int[getRowCount()];

    for (int i = 0; i < indexes.length; i++)
    {
      indexes[i] = i;
    }

  }



  /****************************************************************************
   * Funktion die nach der übergebenen Spalte sortiert
   * @param column Spalte zum Sortieren
   * @param bSorter ob mehrere Spalten sortiert werden sollen
   ***************************************************************************/
  public void sort(int column,boolean bSorter)
  {
    GregorianCalendar zeit = new GregorianCalendar();
    //wenn mehrere Spalten sortiert werden sollen!
    if(bColumnAdd)
    {
      if(arSorter == null)
        arSorter = new ArrayList();
      if(!arSorter.contains(new Integer(column))) //wenn es noch nicht drinnen ist!
         arSorter.add(new Integer(column));
    }
    else
      arSorter = null;


    bDescending = column != iColumn ? true : !bDescending;
    //Zuweisung der Spalte
    iColumn = column;
    Date jetzt = new Date();
    System.out.println(bDescending);
    //ruft den Quicksort mit rowcount -1 auf
    try
    {
      quicksort(0, realModel.getRowCount() - 1); //Achtung es wird von 0 weggezählt, daher -1
    }
    catch (Exception ex)
    {
      ex.printStackTrace();
    }

    GregorianCalendar zeit2 = new GregorianCalendar();
    //Ausgabe wielange er fürs sortieren gebraucht hat in Millisekunden
    System.out.println("Fürs SORTIEREN gebrauchte Millsekunden: " +
                       ( (zeit2.getTimeInMillis() - zeit.getTimeInMillis())));
  }

  /***************************************************************************
   * Führt den Quicksort durch
   * @param lo niedrigstes
   * @param hi höchstes
   **************************************************************************/
  private void quicksort(int lo, int hi)
  {
    int i = lo, j = hi;
    //holt sich den mittleren String
    String a = "";
    if(arSorter == null) //wenn die ArrayList null ist, dann hole es normal
    a = ( (String) realModel.getValueAt(indexes[ (lo + hi) / 2], iColumn)).
        toLowerCase();
    else
      for(int y = 0; arSorter != null && y != arSorter.size(); y++) //ansonsten dazuzählen
      {
        int z = ((Integer)arSorter.get(y)).intValue();
        a += ( ( String) realModel.getValueAt(indexes[( lo + hi) /2],z)).toLowerCase(); //anhängen!
      }

        toLowerCase();
    //  Aufteilung
    while (i <= j)
    {
      if(bDescending)
        while (get(indexes[i]).compareTo(a) < 0) //solange der mittlere String kleiner ist, wird erhöht
          i++;
      else
        while (get(indexes[i]).compareTo(a) > 0) //solange der mittlere String größer ist, wird erhöht
          i++;
      if(bDescending)
        while (get(indexes[j]).compareTo(a) > 0)       //solange der mittlere String größer ist, wird erniedrigt
          j--;
      else
        while (get(indexes[j]).compareTo(a) < 0)       //solange der mittlere String kleiner ist, wird erniedrigt
          j--;
      //wenn i kleiner als j ist wird getauscht
      if (i <= j)
      {
        swap(i, j);
        i++;
        j--;
      }
    }
    // Rekursion
    if (lo < j)
      quicksort(lo, j);
    if (i < hi)
      quicksort(i, hi);
  }


  /***************************************************************************
   * Funktion gibt einen String an der gewünschten Stelle zurück!
   * Spalte wurde im sort vorgemerkt
   * @param x welche Reihe
   * @return den String
   ***************************************************************************/
  private String get(int x)
  {
    String str = "";
    try
    {
      if(arSorter == null) //normal den String holen
        str = ( (String) realModel.getValueAt(x, iColumn)).toLowerCase();
      else
      { //holt sich mehrere Strings
        for(int y = 0; arSorter != null && y != arSorter.size(); y++)
        {
          int z = ((Integer)arSorter.get(y)).intValue();
          str += ( ( String) realModel.getValueAt(x,z)).toLowerCase();
        }
      }

    }
    catch (Exception ex)
    {
      ex.printStackTrace();
    }
    finally
    {
      return str;
    }
  }

  /****************************************************************************
   * Funktion die das austauschen 2er Objekte mittles index vornimmt
   * @param i index 1
   * @param j index 2
   ***************************************************************************/
  public void swap(int i, int j)
  {
    int tmp = indexes[i];
    indexes[i] = indexes[j];
    indexes[j] = tmp;
  }


  /****************************************************************************
   * Liefert die Zeilen zurück
   * @return die Zeilen
   ***************************************************************************/
  public int getRowCount()
  {
    return realModel.getRowCount();
  }


  /****************************************************************************
   * Liefert die Spaltenanzahl zurück
   * @return Spaltenanzahl
   ***************************************************************************/
  public int getColumnCount()
  {
    return realModel.getColumnCount();
  }


  /****************************************************************************
   * Liefert den Spaltennamen zurück
   * @param int0 welche Spalte
   * @return den Namen der Spalte
   ***************************************************************************/
  public String getColumnName(int int0)
  {
    return realModel.getColumnName(int0);
  }



  /****************************************************************************
   * Liefert die Spaltenklasse zurück
   * @param int0 welche Spalte
   * @return die Klasse der gewählten Spalte
   ***************************************************************************/
  public Class getColumnClass(int int0)
  {
    return realModel.getColumnClass(int0);
  }


  /****************************************************************************
   * Liefert zurück ob die Zelle editierbar ist oder nicht
   * @param int0 x Koordinate
   * @param int1 y Koordinate
   * @return true oder false
   ***************************************************************************/
  public boolean isCellEditable(int int0, int int1)
  {
    return realModel.isCellEditable(int0, int1);
  }



  /****************************************************************************
   * Liefert einen Wert zu einer bestimmten x und y Koordinate zurück
   * @param int0 x Koordinate
   * @param int1 y Koordinate
   * @return Objekt auf den Koordinaten
   ***************************************************************************/
  public Object getValueAt(int int0, int int1)
  {
    return realModel.getValueAt(indexes[int0], int1);
  }


  /****************************************************************************
   * Setzt ein Objekt an der gewissen stelle
   * @param object welches objekt
   * @param int1 x koordinate
   * @param int2 y koordinate
   ***************************************************************************/
  public void setValueAt(Object object, int int1, int int2)
  {
    realModel.setValueAt(object, indexes[int1], int2);
  }


  /****************************************************************************
   * added einen neuen TableModelListener
   * @param tableModelListener welchen Listener
   ***************************************************************************/
  public void addTableModelListener(TableModelListener tableModelListener)
  {
    realModel.addTableModelListener(tableModelListener);
  }


  /****************************************************************************
   * Removed den alten TableModellistener
   * @param tableModelListener welcher listener
   ***************************************************************************/
  public void removeTableModelListener(TableModelListener tableModelListener)
  {
    realModel.removeTableModelListener(tableModelListener);
  }

  /***************************************************************************
   * Funktion gibt das Aussehen für den geklickt header zurück
   * @param table die Table
   * @param value das Objekt
   * @param isSelected ob selektiert oder nicht
   * @param hasFocus focus
   * @param row reihe
   * @param column spalte
   * @return Komponente
   **************************************************************************/
  public Component getTableCellRendererComponent(JTable table, Object value,
                                                 boolean isSelected, boolean hasFocus, int row, int column)
  {

    if (table != null) {
      JTableHeader header = table.getTableHeader();
      if (header != null) {
        setForeground(header.getForeground());
        setBackground(header.getBackground());
        setFont(header.getFont());
      }
    }

    setText((value == null) ? "" : value.toString());

    if(arSorter == null)
      if( table.convertColumnIndexToModel( column ) == this.iColumn ){
        setBorder( BorderFactory.createRaisedBevelBorder() );
        if( bDescending )
          setIcon( createAscendingIcon() );
        else
          setIcon( createDescendingIcon() );
      }
      else{
        setIcon( null );
        setBorder( BorderFactory.createEmptyBorder() );
      }
    else
    {
      for (int x = 0; arSorter != null && x != arSorter.size(); x++)
      {
        int z = ( (Integer) arSorter.get(x)).intValue();
        if (table.convertColumnIndexToModel(column) == z)
        {
          setBorder(BorderFactory.createRaisedBevelBorder());
          Color color = getBackground();
         //ist eigentlich die darker funktion, nur kann man sich seinen Factor selber setzen!
          for(int i = x; i != arSorter.size(); i++) 
          {
            color = new Color((int)Math.max((int)color.getRed() * FACTOR,0),
                              (int)Math.max((int)color.getGreen() * FACTOR,0),
                              (int)Math.max((int)color.getBlue()* FACTOR,0));
          }
          setBackground(color);
          if (bDescending)
            setIcon(createAscendingIcon());
          else
            setIcon(createDescendingIcon());
        }
        else if (!arSorter.contains(new Integer(column)))
        {
          setIcon(null);
          setBorder(BorderFactory.createEmptyBorder());
        }
      }


    return this;
  }
  /***************************************************************************
   * Funktion zeichnet das Icon und gibt es danach zurück
   * @return das Icon
   **************************************************************************/
  protected Icon createAscendingIcon(){
    return new Icon(){
      public int getIconHeight() {
        return 3;
      }

      public int getIconWidth() {
        return 5;
      }

      public void paintIcon(Component c, Graphics g, int x, int y) {
        g.setColor( Color.BLACK );
        g.drawLine( x, y, x+4, y );
        g.drawLine( x+1, y+1, x+3, y+1 );
        g.drawLine( x+2, y+2, x+2, y+2 );
      }
    };
  }
  /****************************************************************************
   * Funktion zeichnet das Icon und gibt es zurück
   * @return das Icon
   ***************************************************************************/
  protected Icon createDescendingIcon()
  {
    return new Icon(){
      public int getIconHeight() {
        return 3;
      }

      public int getIconWidth() {
        return 5;
      }

      public void paintIcon(Component c, Graphics g, int x, int y) {
        g.setColor( Color.BLACK );
        g.drawLine( x, y+2, x+4, y+2 );
        g.drawLine( x+1, y+1, x+3, y+1 );
        g.drawLine( x+2, y, x+2, y );
      }
    };
  }
}

Hatte früher hier den BubbleSort welcher bei ca. 100000 Zeilen sehr sehr lange gebraucht hat, aber der QuickSort ist huiiii ;)

Also, hoffe es klappt (habs net ausprobiert, da ich viele Funktionen rausgenommen habe, die nur ich brauche)!
 

thE_29

Top Contributor
So!

Habe den Aufruf und den Sortdecorator umgebaut!

Da PEACEMAKER eine JTable gesucht hat, die nach mehreren Spalten sortiert habe ich das schnell eingebaut!

Wenn man STRG + Mausklick auf die Spalte macht, sortiert er mehrere zusammen! Vielleicht mache ich noch färblich einen Unterschied, welche die erste Spalte ist!

Das Prinzip ist jenes, das er die Strings zusammenhängt und dann erst vergleicht!

Achja, ich habe auch ein tolowerCase drinnen, also wenn jemand case Sensitive haben will, bitte ausbauen!

Desweiteren wären vielleicht tests schön, da ich es (in der Form, meine hat noch mehr Funktionen) noch nicht getestet habe!

Naja, hoffe es kann jemand brauchen :)


edit: Nachtrag, habe nun eingebaut, das die Farbe am dünkelsten beim Haupteintrag ist und immer heller
wird destoe weiterhinten die Spalte beim Sortieren ist! Kann natürlich abgeändert werden!
 
Status
Nicht offen für weitere Antworten.

Oben