Hallo zusammen,
ich stehe zur Zeit vor einem Problem mit der Sortierung in JTables.
Mein Ziel war es eine Tabelle zu gestalten, bei der alle Spalten (in Abhängigkeit von den maximalen SortKeys) sortierbar sind. Das hat auch soweit funktioniert. Zusätzlich möchte ich auch die Spalten verschieben können. Grundsätzlich funktioniert das auch. Das Problem ergibt sich bei mir aus der Kombination. Hier erstmal der BeispielCode:
Sind z.B. die Spalten A und B sortiert und ich verschiebe die Spalte C zwischen A und B, dann passieren meiner Meinung nach 2 Fehler:
Der Sortierungspfeil der Spalte B wandert nicht mit der Spalte (das Problem habe ich versucht durch den ResortingColumnModelListener zu beheben).
Viel schlimmer ist jedoch, dass etwas im Model nicht mehr stimmt. Ein weiterer Klick auf Spalte B (jetzt 3. Spalte) sortiert nun die Spalte C (jetzt 2. Spalte).
Was mache ich falsch?
ich stehe zur Zeit vor einem Problem mit der Sortierung in JTables.
Mein Ziel war es eine Tabelle zu gestalten, bei der alle Spalten (in Abhängigkeit von den maximalen SortKeys) sortierbar sind. Das hat auch soweit funktioniert. Zusätzlich möchte ich auch die Spalten verschieben können. Grundsätzlich funktioniert das auch. Das Problem ergibt sich bei mir aus der Kombination. Hier erstmal der BeispielCode:
Java:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import javax.swing.RowSorter.SortKey;
import javax.swing.border.BevelBorder;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
public class TestTableDemo extends JFrame
{
private TableRowSorter<TableModel> rowSorter = null;
private JScrollPane scrollPane = null;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new TestTableDemo().setVisible(true);
}
});
}
public TestTableDemo()
{
super("TableDemo");
setDefaultCloseOperation(EXIT_ON_CLOSE);
getContentPane().add( getScrollPaneSpieler() );
pack();
}
private JScrollPane getScrollPaneSpieler()
{
if (scrollPane == null)
{
scrollPane = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_NEVER,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setOpaque(false);
scrollPane.setBounds(new Rectangle(10, 130, 500, 300));
scrollPane.setViewportView(getTable());
scrollPane.getViewport().setOpaque(false);
scrollPane.getVerticalScrollBar().setOpaque(false);
scrollPane.setBorder(new BevelBorder(BevelBorder.RAISED));
scrollPane.setVisible(true);
}
return scrollPane;
}
public JTable getTable()
{
JTable table = null;
Object[][] data = new Object[][]{
{1, 5, 8, 9, 0},
{2, 4, 7, 7, 5},
{3, 3, 6, 8, 6},
{7, 5, 8, 7, 7},
{8, 1, 1, 1, 8},
{8, 1, 9, 3, 1},
{8, 2, 9, 3, 4},
{8, 8, 2, 1, 8},
{7, 5, 8, 9, 5}
};
String[] columnNames = new String[]{
"Spalte A", "Spalte B", "Spalte C", "Spalte D", "Spalte E"
};
table = new JTable( data, columnNames );
table.setLayout(new BoxLayout(table, BoxLayout.Y_AXIS));
table.setOpaque(false);
table.setPreferredSize(new Dimension(400,250));
table.getTableHeader().setOpaque(false);
table.setBorder(new LineBorder(Color.gray));
table.setAutoCreateRowSorter(true);
rowSorter = new TableRowSorter<TableModel>(table.getModel());
rowSorter.setMaxSortKeys(2);
table.setRowSorter(rowSorter);
table.getColumnModel().addColumnModelListener(new ResortingColumnModelListener(table));
TableColumn tableColumnA = table.getColumn("Spalte A");
tableColumnA.setResizable(false);
tableColumnA.setCellRenderer(new CellRenderer());
tableColumnA.setHeaderRenderer(new HeaderRenderer(table));
TableColumn tableColumnB = table.getColumn("Spalte B");
tableColumnB.setResizable(false);
tableColumnB.setCellRenderer(new CellRenderer());
tableColumnB.setHeaderRenderer(new HeaderRenderer(table));
TableColumn tableColumnC = table.getColumn("Spalte C");
tableColumnC.setResizable(false);
tableColumnC.setCellRenderer(new CellRenderer());
tableColumnC.setHeaderRenderer(new HeaderRenderer(table));
TableColumn tableColumnD = table.getColumn("Spalte D");
tableColumnD.setResizable(false);
tableColumnD.setCellRenderer(new CellRenderer());
tableColumnD.setHeaderRenderer(new HeaderRenderer(table));
TableColumn tableColumnE = table.getColumn("Spalte E");
tableColumnE.setResizable(false);
tableColumnE.setCellRenderer(new CellRenderer());
tableColumnE.setHeaderRenderer(new HeaderRenderer(table));
return table;
}
public class ResortingColumnModelListener implements TableColumnModelListener
{
private JTable table = null;
public ResortingColumnModelListener(JTable _table)
{
table = _table;
}
public void columnMoved(TableColumnModelEvent e)
{
RowSorter<?> sorter = null;
List<? extends SortKey> oldKeys = null;
List<SortKey> newKeys = null;
int fromView = e.getFromIndex(); //Index im View Herkunft
int toView = e.getToIndex(); //Index im View neue Stelle
if (fromView != toView)
{
// Vertauschen der SortKeys der Spalten from und to, und
// Übernahme aller anderen aus der alten Sortierung
sorter = table.getRowSorter();
oldKeys = sorter.getSortKeys();
newKeys = new ArrayList<SortKey>();
for (SortKey key : oldKeys)
{
if (fromView == key.getColumn())
{
newKeys.add(new RowSorter.SortKey(toView, key.getSortOrder()));
}
else if (toView == key.getColumn())
{
newKeys.add(new RowSorter.SortKey(fromView, key.getSortOrder()));
}
else
{
newKeys.add(new RowSorter.SortKey(key.getColumn(), key.getSortOrder()));
}
}
sorter.setSortKeys(newKeys);
}
}
@Override
public void columnAdded(TableColumnModelEvent e)
{
}
@Override
public void columnMarginChanged(ChangeEvent e)
{
}
@Override
public void columnRemoved(TableColumnModelEvent e)
{
}
@Override
public void columnSelectionChanged(ListSelectionEvent e)
{
}
}
public class CellRenderer extends DefaultTableCellRenderer implements TableCellRenderer {
public CellRenderer()
{
this.setHorizontalAlignment(JLabel.LEFT);
this.setForeground(Color.black);
this.setFont(new Font("Helvetica", Font.PLAIN,12));
this.setOpaque(false);
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col)
{
this.setText(value.toString());
this.setSize(table.getCellRect(row, col, true).width, 16);
return this;
}
}
public class HeaderRenderer extends DefaultTableCellRenderer implements TableCellRenderer {
private Icon mAscending = new AscendingIcon();
private Icon mDescending = new DescendingIcon();
private Icon mNull = new NullIcon();
List<? extends SortKey> skeys = null;
public HeaderRenderer(JTable table)
{
this.setHorizontalAlignment(JLabel.LEFT);
this.setForeground(Color.blue);
this.setFont(new Font("Helvetica", Font.BOLD,12));
this.setOpaque(false);
this.setHorizontalAlignment(JLabel.CENTER);
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col)
{
this.setText(value.toString());
skeys = table.getRowSorter().getSortKeys();
if (skeys != null)
{
for (SortKey sortKey : skeys)
{
if (col == sortKey.getColumn())
{
if(sortKey.getSortOrder() == SortOrder.ASCENDING)
{
setIcon(mAscending);
return this;
}
else if (sortKey.getSortOrder() == SortOrder.DESCENDING)
{
setIcon(mDescending);
return this;
}
}
}
}
setIcon(mNull);
return this;
}
}
public class NullIcon implements Icon
{
public int getIconHeight()
{
return 6;
}
public int getIconWidth()
{
return 6;
}
public void paintIcon(Component pComponent, Graphics pGraphics, int pX, int pY)
{
}
}
public class AscendingIcon extends NullIcon
{
public void paintIcon(Component pComponent, Graphics pGraphics, int pX, int pY)
{
int[] xx = {pX, pX + 3, pX + 6};
int[] yy = {pY + 6, pY, pY + 6};
Color initialColor = pGraphics.getColor();
float[] initial = Color.RGBtoHSB(initialColor.getRed(), initialColor.getGreen(), initialColor.getBlue(), null);
boolean need = initial[2] < .5f;
initial[2] = invertAsNeed(initial[2], need);
Color line = Color.getHSBColor(initial[0], initial[1], invertAsNeed(initial[2] * .7f, need));
Color fill = Color.getHSBColor(initial[0], initial[1], invertAsNeed(initial[2] * .35f, need));
pGraphics.setColor(fill);
pGraphics.fillPolygon(xx, yy, 3);
pGraphics.setColor(line);
pGraphics.drawPolygon(xx, yy, 3);
}
private float invertAsNeed(float pBright, boolean pNeed)
{
return pNeed ? 1 - pBright : pBright;
}
}
public class DescendingIcon extends NullIcon {
public void paintIcon(Component pComponent, Graphics pGraphics, int pX,
int pY) {
int[] xx = {pX, pX + 3, pX + 6};
int[] yy = {pY, pY + 6, pY + 0};
Color initialColor = pGraphics.getColor();
float[] initial = Color.RGBtoHSB(initialColor.getRed(),
initialColor.getGreen(), initialColor.getBlue(), null);
boolean need = initial[2] < .5f;
initial[2] = invertAsNeed(initial[2], need);
Color line = Color.getHSBColor(initial[0], initial[1],
invertAsNeed(initial[2] * .7f, need));
Color fill = Color.getHSBColor(initial[0], initial[1],
invertAsNeed(initial[2] * .35f, need));
pGraphics.setColor(fill);
pGraphics.fillPolygon(xx, yy, 3);
pGraphics.setColor(line);
pGraphics.drawPolygon(xx, yy, 3);
}
private float invertAsNeed(float pBright, boolean pNeed)
{
return pNeed ? 1 - pBright : pBright;
}
}
}
Sind z.B. die Spalten A und B sortiert und ich verschiebe die Spalte C zwischen A und B, dann passieren meiner Meinung nach 2 Fehler:
Der Sortierungspfeil der Spalte B wandert nicht mit der Spalte (das Problem habe ich versucht durch den ResortingColumnModelListener zu beheben).
Viel schlimmer ist jedoch, dass etwas im Model nicht mehr stimmt. Ein weiterer Klick auf Spalte B (jetzt 3. Spalte) sortiert nun die Spalte C (jetzt 2. Spalte).
Was mache ich falsch?