Swing RowSorter für (negative) Integer / Floats - JTable

Jannik

Mitglied
Hallo zusammen,

ich sitze jetzt schon seit gefühlt 3 Monaten daran, die Spalten einen JTables richtig zu sortieren. Bei Strings ist das kein Problem, doch Integer werden mir so sortiert:

1
10
100
...

das ist ja nunmal ganz eindeutig falsch. Zahlreiche Foren habe ich durchsucht, doch zu ner wirklichen Lösung komme ich nicht! 🙁

Ich hoffe, ihr könnt mir helfen.

Meine MAIN-Klasse:

Java:
package de.szut.dqi;
import info.clearthought.layout.TableLayout;
import info.monitorenter.gui.chart.Chart2D;
import info.monitorenter.gui.chart.ITrace2D;
import info.monitorenter.gui.chart.traces.Trace2DSimple;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Properties;
import java.util.Random;

import javax.swing.AbstractAction;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.GroupLayout;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.LayoutStyle;

import javax.swing.WindowConstants;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.SwingUtilities;


/**
 * This code was edited or generated using CloudGarden's Jigloo
 * SWT/Swing GUI Builder, which is free for non-commercial
 * use. If Jigloo is being used commercially (ie, by a corporation,
 * company or business for any purpose whatever) then you
 * should purchase a license for each developer using Jigloo.
 * Please visit [url=http://www.cloudgarden.com]Cloud Garden (Java Resources)[/url] for details.
 * Use of Jigloo implies acceptance of these licensing terms.
 * A COMMERCIAL LICENSE HAS NOT BEEN PURCHASED FOR
 * THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED
 * LEGALLY FOR ANY CORPORATE OR COMMERCIAL PURPOSE.
 */
public class View extends javax.swing.JFrame {
	private JTabbedPane jTabbedPane1;
	private JPanel jPanel1;
	//private Chart2D chart2D_IL;
	private JMenu jMenu1;
	private JMenuBar jMenuBar1;
	private Chart2D chart;
	private Filechooser filechooser = new Filechooser();
	private Properties properties = new Properties();
	private Connection conn;
	private Statement state;
	private ResultSet rs;
	private ResultSetMetaData rsmd;
	private Boolean closed;
	private String tableName;
	private WeatherTableModel tablemodel;
	private AbstractAction openCSVAbstractAction;
	private JComboBox jComboBox;
	private JPanel jPanel4;
	private JScrollPane jScrollPane1;
	private JPanel jPanel3;
	private JLabel errorLabel;
	private JTable jTable;
	private JPanel jPanel2;
	private AbstractAction openDBAbstractAction;
	private JMenuItem openCSVLabel;
	private JMenuItem openDBMenuItem;
	private Boolean error = false;
	private ArrayList<String> tableNames;
	private int selectedColumn;
	private ArrayList<Float> columnData;
	
	/**
	 * Auto-generated main method to display this JFrame
	 */
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				View inst = new View();
				inst.setLocationRelativeTo(null);
				inst.setVisible(true);
			}
		});
	}

	public View() {
		super();
		closed = true;
		System.out.println(System.getProperty("user.dir"));
		try {
			File file = new File("jdbc.properties");
			FileInputStream fis = new FileInputStream(file);
			properties.load(fis);
			Class.forName(properties.getProperty("jdbc.driver"));
		} catch (Exception e) {
			System.out.println("Could not load properties file");
		}
		initGUI();
	}

	private void initGUI() {
		try {
			setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
			GroupLayout thisLayout = new GroupLayout((JComponent)getContentPane());
			getContentPane().setLayout(thisLayout);
			thisLayout.setVerticalGroup(thisLayout.createSequentialGroup()
					.addComponent(getJPanel2(), 0, 383, Short.MAX_VALUE)
					.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED));
			thisLayout.setHorizontalGroup(thisLayout.createParallelGroup()
					.addComponent(getJPanel2(), GroupLayout.Alignment.LEADING, 0, 770, Short.MAX_VALUE));
			{
				jMenuBar1 = new JMenuBar();
				setJMenuBar(jMenuBar1);
				{
					jMenu1 = new JMenu();
					jMenuBar1.add(jMenu1);
					jMenu1.setText("jMenu1");
					{
						openDBMenuItem = new JMenuItem();
						jMenu1.add(openDBMenuItem);
						openDBMenuItem.setText("Open DB File...");
						openDBMenuItem.setAction(getOpenDBAbstractAction());
					}
					{
						openCSVLabel = new JMenuItem();
						jMenu1.add(openCSVLabel);
						openCSVLabel.setText("Open CSV...");
						openCSVLabel.setAction(getOpenCSVAbstractAction());
					}
				}
			}
			pack();
			this.setSize(786, 448);
		} catch (Exception e) {
			//add your error handling code here
			e.printStackTrace();
		}
		
	}

	public void getDB() {

		try {
			String dbName = filechooser.openFile();

			if (dbName != "") {

				String db_url = properties.getProperty("jdbc.url") + dbName;

				conn = DriverManager.getConnection(db_url);
				state = conn.createStatement();


				state.execute("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;");

				rs = state.getResultSet();
				rsmd = rs.getMetaData();
				//generate JTreeModel
				DefaultMutableTreeNode child = null;
				tableNames = new ArrayList<String>();
				while (rs.next()) {
					tableNames.add(rs.getString(1));
					System.out.println(rs.getString(1));
				}

				//get table name out of returned string from filechooser
				String[] pieces = db_url.split("\\\\");
				tableName = tableNames.get(0);				

				closed = false;
				//				//Enable all buttons
				//				//setButtonsEnabled();
				//
				//				loadLabel.setText("Database " + dbName + " loaded");
				//				loadLabel.setForeground(Color.GREEN);
				//
				//				closed = false;
			}

		} catch (SQLException e) {
			errorLabel.setText(e.toString());
			errorLabel.setForeground(Color.RED);
			error = true;
		}
	}
	
	
	public void buildChart() {
		ITrace2D trace = new Trace2DSimple();
		chart.addTrace(trace);
		
		if (selectedColumn != jComboBox.getSelectedIndex()) {
			selectedColumn = jComboBox.getSelectedIndex();
			tablemodel.getColumnName(selectedColumn);
			
			for (int i = 0; i < tablemodel.getRowCount(); i++) {
				System.out.println(tablemodel.getValueAt(i, selectedColumn+1));
				trace.addPoint(i, Float.valueOf(tablemodel.getValueAt(i, selectedColumn+1).toString()));
			}
		}  
	}

	public void buildTable() {
		if (closed == false) { //do only, when connection to db is established
			System.out.println("build");
			if (tableName != null) {
				try {
					clearTable(); //clear table (delete old entrys of jTable)
					state.execute("Select Count(*) from " + tableName); //get number of all rows in the table
					rs = state.getResultSet();
					String anzahl = rs.getString(1);
					int rowCount = Integer.valueOf(anzahl);

					System.out.println(tableName);
					state.execute("Select * from " + tableName); //to get everything out of table


					rs = state.getResultSet();
					rsmd = rs.getMetaData();

					tablemodel = (WeatherTableModel) jTable.getModel();		
					
					int columncount = rsmd.getColumnCount();
					for (int i = 1; i < rsmd.getColumnCount() + 1; i++) {
						tablemodel.addColumn(rsmd.getColumnName(i).replace('_', ' '));
						if (i > 1 & i < rsmd.getColumnCount()) {
							jComboBox.addItem(rsmd.getColumnName(i));
						}
						System.out.println(i);
						System.out.println(rsmd.getColumnName(i));
					}


					//generate zeros in front of rec no's for correct order
					//f.e. 1 is at 1000 entries = 0001
					Integer nullCount = 0;
					while (rowCount > 9) { //only when there are more than 9 entries
						nullCount++;
						rowCount = rowCount / 10; //divide with 10 to get all 10-steps
					}


					Object[] rowData = new Object[columncount]; //columncount + 1, because there
					Object[] emptyRow = new Object[columncount+1];
					String nullString = "";						  //is the rec-no column
					String recNo = "";
					String nr;
					int n = 1;

					//check for limit statement

					//get all entries (limit is not selected)
					int durchlauf = 0;
					while (rs.next()) {	
						System.out.println("untere while");
						nr = String.valueOf(n);
						int j = 0;
						//calculate for leading zeros of rec-no
						if (nr.length() > 1) {
							if (String.valueOf(n).charAt(0) == '1') {
								String substr = nr.substring(1);
								for (int i = 0; i < substr.length(); i++) {
									if (substr.charAt(i) == '0') {
										j++;
									}
								}
								if (j == substr.length()) {
									nullCount--; //if is 10 or 100 or 1000, decrement the nullcount
								}
							}

						}
						nullString = "";
						for (int i = nullCount; i > 0; i--) {
							nullString += "0"; //add zero(s) in front of the rec-no
						}


						recNo = nullString + String.valueOf(n);
						rowData[0] = recNo;
						tablemodel.addRow(emptyRow);

						for (int i = 0; i < tablemodel.getColumnCount(); i++) {
							rowData[i] = rs.getString(i+1); //get content of table (row)
							System.out.println(rowData[i].toString());
							System.out.println("iiiiiii:" + i);

							
							try {
								Integer zahl = Integer.valueOf(rowData[i].toString());
								tablemodel.setValueAt(zahl, durchlauf, i);
								System.out.println("Int");

							} catch (Exception ClassCastException) {
								try {
									float flo = Float.valueOf(rowData[i].toString());
									tablemodel.setValueAt(flo, durchlauf, i);
									System.out.println("Float!");
								} catch (Exception e) {
									String str = (String) rowData[i];
									System.out.println("String");
								}

								tablemodel.setValueAt(rowData[i], durchlauf, i);
							}
						}
						//tablemodel.addRow(rowData);

						n++;
						durchlauf++;
					}
					jTable.setModel(tablemodel);
					//addRowSorter();
					
					
					
					//check for errors (for highlighting error-label
					if (error == false) { 
						errorLabel.setText("no errors");
						errorLabel.setForeground(Color.BLACK);
					} 
					error = false; //set error automatic to false, after a new selection / user-statement


				} catch (SQLException e) {
					//show SQL-Error in the error label an highlight it red
//					errorLabel.setText(e.toString());
//					errorLabel.setForeground(Color.RED);
//					buildTable();
					System.out.println(e);
				}
			}

		}
	}

	public void clearTable() {
		tablemodel = new WeatherTableModel();
		jTable.setModel(tablemodel);
		//addRowSorter();
	}

	public void addRowSorter() {
//		SimpleTableRowSorter rowSorter = new SimpleTableRowSorter(jTable.getModel());
//		if (tablemodel.getRowCount() > 0) {
//			rowSorter.setComparator(0, new TableComparator());
//			
//		}
		
		jTable.setRowSorter(new TableRowSorter<TableModel>(jTable.getModel()) );
		
	}

	private AbstractAction getOpenDBAbstractAction() {
		if(openDBAbstractAction == null) {
			openDBAbstractAction = new AbstractAction("Open DB File...", null) {
				public void actionPerformed(ActionEvent evt) {
					getDB();
					buildTable();
				}
			};
		}
		return openDBAbstractAction;
	}

	private AbstractAction getOpenCSVAbstractAction() {
		if(openCSVAbstractAction == null) {
			openCSVAbstractAction = new AbstractAction("Open CSV File...", null) {
				public void actionPerformed(ActionEvent evt) {
				}
			};
		}
		return openCSVAbstractAction;
	}

	private JPanel getJPanel2() {
		if(jPanel2 == null) {
			jPanel2 = new JPanel();
			GroupLayout jPanel2Layout = new GroupLayout((JComponent)jPanel2);
			jPanel2.setLayout(jPanel2Layout);
			{
				jTabbedPane1 = new JTabbedPane();
				jTabbedPane1.addTab("jScrollPane1", null, getJScrollPane1(), null);
				jTabbedPane1.addTab("jPanel3", null, getJPanel3(), null);
				{
					jPanel1 = new JPanel();
					GroupLayout jPanel1Layout = new GroupLayout((JComponent)jPanel1);
					jPanel1.setLayout(jPanel1Layout);
					jPanel1Layout.setHorizontalGroup(jPanel1Layout.createSequentialGroup()
							.addComponent(getJLabel1(), 0, 770, Short.MAX_VALUE));
					jPanel1Layout.setVerticalGroup(jPanel1Layout.createSequentialGroup()
							.addComponent(getJLabel1(), GroupLayout.PREFERRED_SIZE, 14, GroupLayout.PREFERRED_SIZE));
				}
			}
			jPanel2Layout.setHorizontalGroup(jPanel2Layout.createParallelGroup()
				.addComponent(jTabbedPane1, GroupLayout.Alignment.LEADING, 0, 770, Short.MAX_VALUE)
				.addComponent(jPanel1, GroupLayout.Alignment.LEADING, GroupLayout.PREFERRED_SIZE, 770, GroupLayout.PREFERRED_SIZE)
				.addComponent(getJPanel4(), GroupLayout.Alignment.LEADING, GroupLayout.PREFERRED_SIZE, 770, GroupLayout.PREFERRED_SIZE));
			jPanel2Layout.setVerticalGroup(jPanel2Layout.createSequentialGroup()
				.addComponent(getJPanel4(), GroupLayout.PREFERRED_SIZE, 31, GroupLayout.PREFERRED_SIZE)
				.addComponent(jTabbedPane1, 0, 338, Short.MAX_VALUE)
				.addComponent(jPanel1, GroupLayout.PREFERRED_SIZE, 14, GroupLayout.PREFERRED_SIZE));
		}
		return jPanel2;
	}

	private JTable getJTable() {
		if(jTable == null) {
			TableModel jTableModel = 
				new WeatherTableModel( );
			jTable = new JTable();
			jTable.setAutoCreateRowSorter(true);
			jTable.getTableHeader().setReorderingAllowed(false);
		}
		return jTable;
	}

	private JLabel getJLabel1() {
		if(errorLabel == null) {
			errorLabel = new JLabel();
			errorLabel.setText("errorLabel");
		}
		return errorLabel;
	}

	private JPanel getJPanel3() {
		if(jPanel3 == null) {
			jPanel3 = new JPanel();
			GroupLayout jPanel3Layout = new GroupLayout((JComponent)jPanel3);
			jPanel3.setLayout(jPanel3Layout);
			{
				chart = new Chart2D();
			}
			jPanel3Layout.setHorizontalGroup(jPanel3Layout.createSequentialGroup()
					.addComponent(chart, 0, 765, Short.MAX_VALUE));
			jPanel3Layout.setVerticalGroup(jPanel3Layout.createSequentialGroup()
					.addComponent(chart, 0, 341, Short.MAX_VALUE));
		}
		return jPanel3;
	}

	private JScrollPane getJScrollPane1() {
		if(jScrollPane1 == null) {
			jScrollPane1 = new JScrollPane();
			jScrollPane1.setPreferredSize(new java.awt.Dimension(765, 341));
			jScrollPane1.setViewportView(getJTable());
		}
		return jScrollPane1;
	}
	
	private JPanel getJPanel4() {
		if(jPanel4 == null) {
			jPanel4 = new JPanel();
			GroupLayout jPanel4Layout = new GroupLayout((JComponent)jPanel4);
			jPanel4.setLayout(jPanel4Layout);
			jPanel4Layout.setHorizontalGroup(jPanel4Layout.createSequentialGroup()
				.addContainerGap(552, Short.MAX_VALUE)
				.addComponent(getJComboBox1(), GroupLayout.PREFERRED_SIZE, 218, GroupLayout.PREFERRED_SIZE));
			jPanel4Layout.setVerticalGroup(jPanel4Layout.createSequentialGroup()
				.addComponent(getJComboBox1(), 0, 31, Short.MAX_VALUE));
		}
		return jPanel4;
	}
	
	public JComboBox getJComboBox1() {
		if(jComboBox == null) {
			jComboBox = new JComboBox();
		}
		jComboBox.addItemListener(new DefaultItemListener(this));
		return jComboBox;
	}

}


Das Model:

Java:
package de.szut.dqi;

import javax.swing.table.DefaultTableModel;

public class WeatherTableModel extends DefaultTableModel {

	@Override
	public boolean isCellEditable(int row, int col) {
		
		return false;	
	}
}

So, dann habe ich es hin und wieder mal ausprobiert, einen eigenen Comparator zu schreiben, der hat bei den Integer funktioniert, nur leider musste man immer zweimal klicken damit er seine Sortierung von aufsteigend auf absteigend ändert, das heißt, das erscheinenden Dreieck im TableHeader zeigt immer nach oben, wenn korrekt sortiert wurde! Noch schlimmer dabei war, dass, wenn ich andere Spalten sortieren lassen habe, z.B. eine String-Spalte, dann gerieten die Spalten durcheinander.

Hiernochmal mein nicht funktionierender Comparator:

Java:
package de.szut.dqi;

import java.util.Comparator;

public class TableComparator implements Comparator<Object> {
	private Float f1;
	private Float f2;
	private Integer i1;
	private Integer i2;

	public int compare(Integer arg0, Integer arg1) {
		// TODO Auto-generated method stub
		System.out.println("Integer Ueberpruefung2!");
		if (arg0 > arg1) {
			return arg0 - arg1;
		} else if (arg0 < arg1) {
			return arg1 - arg0;
		} else {
			return 0;
		}
	}
		
	public float compare(Float arg0, Float arg1) {
		if (f1 > f2) {
			return f1 - f2;
		} else if (f1 < f2) {
			return f2 - f1;
		} else {
			return 0;
		}
	}


	@Override
	public int compare(Object arg0, Object arg1) {
		// TODO Auto-generated method stub
		System.out.println("Integer Ueberpruefung!");
		i1 = Integer.valueOf(arg0.toString());
		i2 = Integer.valueOf(arg1.toString());
		
		if (i1 > i2) {
			return i1 - i2;
		} else if (i1 < i2) {
			return i2 - i1;
		} else {
			return 0;
		}
	}
}
 
Zuletzt bearbeitet:
An dem Beispiel was ich gegeben habe nichts, war ein wenig schlecht, sorry.
Es gibt in dem Beispiel alle Zahlen von 1 bis 100.
Sortiert wird aber von ab her

1
10
100, nicht
1
2
3
4
5
 
Erstmal würde ich nur 1(größer), 0(gleich) und -1(kleiner) zurückliefern beim Vergleich, wird irgendwo so glaub ich gefordert.
Sonst sieht das danach aus, als würden die Zahlen als Strings vergleichen werden, da passiert genau das.
Hab aber keine Lust deinen ganzen Code nach den wichtigen Aufrufen des Sortierens zu durchsuchen, poste doch mal die entscheidenden Stellen, an denen sortiert wird.
Dein Comparator mutet sowieso merkwürdig an, wieso hast du den nicht direkt mit Integer erzeugt, anstatt mit Object ?
Wo wird den beim Sortieren zwischen String und Integer unterschieden ?
 
Java:
public int compare(Integer arg0, Integer arg1) {
        // TODO Auto-generated method stub
        System.out.println("Integer Ueberpruefung2!");
        if (arg0 > arg1) {
            return arg0 - arg1;
        } else if (arg0 < arg1) {
            return arg1 - arg0;
        } else {
            return 0;
        }
    }

Sieht mir ziemlich suspekt aus.

Schreib doch dafür mal einen Unit-Test. NetBeans und Eclipse sollten die nötige Unterstützung mitbringen.

Java:
public void testFirstSmallerThenSecond(){
TableComperator comperator = new TableComperator();
int result = comperator.compare(1,2);
int expected = -1;
assertEquals(expected, result);
}

public void testFirstBiggerThenSecond(){
TableComperator comperator = new TableComperator();
int result = comperator.compare(2,1);
int expected = 1;
assertEquals(expected, result);
}

Poste dann bitte mal das Ergebnis dieses Tests.
Für Float und Objekt, kannst du dann auch gleich weitere Tests schreiben.

Tipp:
[JAVA=41]
return compare(i1,i2);
[/code]

Ein weiterer Tipp:
Integer und Float besitzen eine compareTo()-Methode.

Aber bevor es an die Tipps geht, erstmal Tests schreiben!
 
Java:
public int compare(Integer arg0, Integer arg1) {
        // TODO Auto-generated method stub
        System.out.println("Integer Ueberpruefung2!");
        if (arg0 > arg1) {
            return arg0 - arg1;
        } else if (arg0 < arg1) {
            return arg1 - arg0;
        } else {
            return 0;
        }
    }

Wo hast du das denn gefunden?
Du lieferst immer einen positiven Wert, oder bei Gleichheit "0" zurück.

Sinn dieser Implementation soll aber sein:
Diese Methode bekommt 2 -was auch immer- Objekte übergeben (bei dir Integer???!!!) und du sollst sagen, ob diese beiden Objekte größer, oder kleiner, oder gleich sind.

Versuch mal folgenden Code:
Java:
public int compare(Integer arg0, Integer arg1) {
        // TODO Auto-generated method stub
        System.out.println("Integer Ueberpruefung2!");
        if (arg0 > arg1) {
            return 1;
        } else if (arg0 < arg1) {
            return -1;
        } else {
            return 0;
        }
    }

EDIT: evtl. sollte man auch die anderen Anworten lesen...das wurde ja auch schon gesagt, sorry 🙂
 
Zuletzt bearbeitet:

Zurück
Oben