JTable:如何对特定行始终为第一行的 table 进行排序?
JTable: How to sort a table where a specific row is always the first row?
如何创建排序器,使特定行始终排在第一行,无论该列是按升序还是降序排序?我的代码如下。单击 "name" 2 次 "FIRSTROW" 每次都排在第一行。单击 "age" 直到 FIRSTROW 不再排在第一位,然后单击返回 "name",FIRSTROW 不再排在第一位。我希望每次单击 "name" 时首先对 FIRSTROW 进行排序,我该怎么做?
示例代码如下:
import java.awt.BorderLayout;
import java.util.Comparator;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
public class TableTest implements Comparator<String> {
@Override
public int compare(String obj1, String obj2) {
if (obj1 == obj2) {
return 0;
}
if (obj1 == null) {
return -1;
}
if (obj2 == null) {
return -1;
}
if (obj2 instanceof String && obj2.trim( ).equals("FIRSTROW")) {
return 0;
}
if (obj1 instanceof String && obj1.trim( ).equals("FIRSTROW")) {
return 0;
}
return obj1.compareTo(obj2);
}
public static void main(String args[]) {
JFrame frame = new JFrame("Fixed First Row");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String rows[][] = { { "FIRSTROW", "23" }, { "R", "24", }, { "E", "21", }, { "D", "27", }, { "A", "25", },
{ "S", "22", }, };
/* Specify column names */
String columns[] = { "Name", "Age" };
/* Create a TableModel */
DefaultTableModel model = new DefaultTableModel(rows, columns) {
@Override
public Class getColumnClass(int column) {
Class returnValue;
if ((column >= 0) && (column < getColumnCount())) {
returnValue = getValueAt(0, column).getClass();
} else {
returnValue = Object.class;
}
return returnValue;
}
};
JTable table = new JTable(model);
TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
table.setRowSorter(sorter);
sorter.setComparator( 0, new TableTest() ); // Field column uses the random string comparator.
JScrollPane pane = new JScrollPane(table);
frame.add(pane, BorderLayout.CENTER);
frame.setSize(300, 150);
frame.setVisible(true);
}
}
如果您只是进行简单的文本比较,您会在比较器中进行 return stringA.compareTo(stringB);
。要确保某个值始终排在最前面,您需要明确地使其如此。
不过要小心,强制比较远离 "natural ordering" 很容易导致比较 "contract violations"。
编辑:
public int compare(String obj1, String obj2) {
if (obj1 == obj2) {// if they are the same object
return 0;
}
if (obj1 == null) {// sort null above not null
return -1;
}
if (obj2 == null) {// sort not null below null
return 1;
}
if (obj1.trim().toUpperCase().equals("B") &&
!obj2.trim().toUpperCase().equals("B")) {// sort B above not-B
return -1;
}
if (!obj1.trim().toUpperCase().equals("B") &&
obj2.trim().toUpperCase().equals("B")) {// sort not-B below B
return 1;
}
return obj1.compareTo(obj2);
}
当你想在选择后将一行保留在顶部时,你可能不会只使用它的一个属性来做到这一点,因为它可能与另一个相同,最好的方法是对象本身。
为此:
- 获取选中的行
- 根据需要使用其中一个对象属性对列表进行排序//
- 从列表中删除所选行
- 将所选行添加到列表顶部。
以下是此行为的测试示例:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import com.sun.prism.impl.Disposer.Record;
import javax.swing.JButton;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Toolkit;
import javax.swing.JTextField;
import javax.swing.JComboBox;
import javax.swing.DefaultComboBoxModel;
import traitement.CustomRenderer;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class TestSort extends JFrame implements ActionListener{
private JTable table1;
private JButton btnSort;
private int selectedCombCriteria=-1;
private JComboBox combCriteria;
private Boolean showSelection=false;
public static void main(String[] args) {
// TODO Auto-generated method stub
TestSort ts=new TestSort();
ts.setVisible(true);
}
TestSort()
{
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
this.setLocation(dim.width/2-this.getSize().width/2, dim.height/2-this.getSize().height/2);
setSize(new Dimension(439, 325));
setPreferredSize(new Dimension(600,400));
JPanel pt=new JPanel();
getContentPane().add(pt);
pt.setLayout(null);
combCriteria = new JComboBox();
combCriteria.setModel(new DefaultComboBoxModel(new String[] {"Age", "Score"}));
combCriteria.setSelectedIndex(0);
combCriteria.setBounds(115, 205, 67, 20);
combCriteria.addActionListener(this);
pt.add(combCriteria);
btnSort = new JButton("Sort");
btnSort.addActionListener(this);
btnSort.setBounds(324, 204, 89, 23);
pt.add(btnSort);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(20, 41, 393, 127);
pt.add(scrollPane);
table1 = new JTable();
SortModel sm=new SortModel();
table1.setModel(sm);
table1.setBounds(50, 26, 329, 130);
scrollPane.setViewportView(table1);
table1.getSelectionModel().addListSelectionListener(
new ListSelectionListener() {
public void valueChanged(ListSelectionEvent event) {
SortModel.selectedRecord=((SortModel)table1.getModel()).getRowAt(table1.getSelectedRow());
showSelection=true;
}
});
table1.setDefaultRenderer(Object.class, new DefaultTableCellRenderer()
{
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
final Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
c.setBackground(row==0?Color.YELLOW:isSelected&&showSelection?Color.lightGray:Color.white);
return c;
}
});
JLabel lblSelectARow = new JLabel("Select a row to keep at the top and sort using one of the sorting criteria");
lblSelectARow.setFont(new Font("Traditional Arabic", Font.PLAIN, 14));
lblSelectARow.setHorizontalAlignment(SwingConstants.CENTER);
lblSelectARow.setBounds(20, 11, 393, 23);
pt.add(lblSelectARow);
JLabel lblSortCreteria = new JLabel("Sorting criteria:");
lblSortCreteria.setBounds(20, 208, 96, 14);
pt.add(lblSortCreteria);
}
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource()==btnSort)
if(SortModel.selectedRecord!=null)
{
((SortModel)table1.getModel()).sort(selectedCombCriteria);
table1.repaint();
showSelection=false;
}
if(e.getSource()==combCriteria)
{
selectedCombCriteria=combCriteria.getSelectedIndex();
}
}
}
class SortModel extends AbstractTableModel
{
public SortModel(){
data=fillOnce();
}
private String[] columns = {"First Name", "Last Name", "Profession", "Age","Score","Comment"};
public List<MyDataRecord> data=new ArrayList<MyDataRecord>();
public static MyDataRecord selectedRecord;
@Override
public int getRowCount() {
// TODO Auto-generated method stub
return data.size();
}
@Override
public String getColumnName(int column) {
return columns[column];
}
@Override
public int getColumnCount() {
return columns.length;
}
public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0:
return data.get(rowIndex).getfName();
case 1:
return data.get(rowIndex).getlName();
case 2:
return data.get(rowIndex).getProfession();
case 3:
return data.get(rowIndex).getAge();
case 4:
return data.get(rowIndex).getScore();
case 5:
return data.get(rowIndex).getComment();
default:
throw new IllegalArgumentException();
}
}
public MyDataRecord getRowAt(int rowIndex)
{
return data.get(rowIndex);
}
//sorting method
public void sort(int sort)
{
//sort
Collections.sort(data, new Comparator<MyDataRecord>() {
public int compare(MyDataRecord object1, MyDataRecord object2) {
if(sort!=1)
return Integer.compare(object1.getAge(), object2.getAge());
else
return Integer.compare(object1.getScore(), object2.getScore());
}
});
//then remove he selected element
data.remove(selectedRecord);
//put the selected element on the top of the list
if(selectedRecord!=null)
{
data.add(0, selectedRecord);
}
}
public List<MyDataRecord> fillOnce()
{
List<MyDataRecord> tempList=new ArrayList<MyDataRecord>();
Random r = new Random();
for(int i=1;i<=6;i++)
{
MyDataRecord mdr=new MyDataRecord("FNtest"+i, "LNtest"+i, "PROFtest"+i, "COMtest"+i, r.nextInt(100-1) + 1, r.nextInt(100-1) + 1);
tempList.add(mdr);
}
return tempList;
}
}
class MyDataRecord{
private String fName,lName,profession,comment;
private int age,score;
public MyDataRecord(String fName, String lName, String profession,
String comment, int age, int score) {
super();
this.fName = fName;
this.lName = lName;
this.profession = profession;
this.comment = comment;
this.age = age;
this.score = score;
}
public String getfName() {
return fName;
}
public void setfName(String fName) {
this.fName = fName;
}
public String getlName() {
return lName;
}
public void setlName(String lName) {
this.lName = lName;
}
public String getProfession() {
return profession;
}
public void setProfession(String profession) {
this.profession = profession;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
已经制作了一个 CustomRowSorter,基本上是默认 DefaultRowSorter 的副本。
我无法扩展 class,因为我必须对排序方面的私有函数进行一些更改。
此外,我还必须制作自己的 TableRowSorter 副本,它使用了新的 CustomRowSorter。然后,我的 table 将使用 CustomTableRowSorter 来完成工作。这不是一个很好的实现,因为复制这两个文件是 1.5k 行的更改。
如何创建排序器,使特定行始终排在第一行,无论该列是按升序还是降序排序?我的代码如下。单击 "name" 2 次 "FIRSTROW" 每次都排在第一行。单击 "age" 直到 FIRSTROW 不再排在第一位,然后单击返回 "name",FIRSTROW 不再排在第一位。我希望每次单击 "name" 时首先对 FIRSTROW 进行排序,我该怎么做?
示例代码如下:
import java.awt.BorderLayout;
import java.util.Comparator;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
public class TableTest implements Comparator<String> {
@Override
public int compare(String obj1, String obj2) {
if (obj1 == obj2) {
return 0;
}
if (obj1 == null) {
return -1;
}
if (obj2 == null) {
return -1;
}
if (obj2 instanceof String && obj2.trim( ).equals("FIRSTROW")) {
return 0;
}
if (obj1 instanceof String && obj1.trim( ).equals("FIRSTROW")) {
return 0;
}
return obj1.compareTo(obj2);
}
public static void main(String args[]) {
JFrame frame = new JFrame("Fixed First Row");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String rows[][] = { { "FIRSTROW", "23" }, { "R", "24", }, { "E", "21", }, { "D", "27", }, { "A", "25", },
{ "S", "22", }, };
/* Specify column names */
String columns[] = { "Name", "Age" };
/* Create a TableModel */
DefaultTableModel model = new DefaultTableModel(rows, columns) {
@Override
public Class getColumnClass(int column) {
Class returnValue;
if ((column >= 0) && (column < getColumnCount())) {
returnValue = getValueAt(0, column).getClass();
} else {
returnValue = Object.class;
}
return returnValue;
}
};
JTable table = new JTable(model);
TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
table.setRowSorter(sorter);
sorter.setComparator( 0, new TableTest() ); // Field column uses the random string comparator.
JScrollPane pane = new JScrollPane(table);
frame.add(pane, BorderLayout.CENTER);
frame.setSize(300, 150);
frame.setVisible(true);
}
}
如果您只是进行简单的文本比较,您会在比较器中进行 return stringA.compareTo(stringB);
。要确保某个值始终排在最前面,您需要明确地使其如此。
不过要小心,强制比较远离 "natural ordering" 很容易导致比较 "contract violations"。
编辑:
public int compare(String obj1, String obj2) {
if (obj1 == obj2) {// if they are the same object
return 0;
}
if (obj1 == null) {// sort null above not null
return -1;
}
if (obj2 == null) {// sort not null below null
return 1;
}
if (obj1.trim().toUpperCase().equals("B") &&
!obj2.trim().toUpperCase().equals("B")) {// sort B above not-B
return -1;
}
if (!obj1.trim().toUpperCase().equals("B") &&
obj2.trim().toUpperCase().equals("B")) {// sort not-B below B
return 1;
}
return obj1.compareTo(obj2);
}
当你想在选择后将一行保留在顶部时,你可能不会只使用它的一个属性来做到这一点,因为它可能与另一个相同,最好的方法是对象本身。
为此:
- 获取选中的行
- 根据需要使用其中一个对象属性对列表进行排序//
- 从列表中删除所选行
- 将所选行添加到列表顶部。
以下是此行为的测试示例:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import com.sun.prism.impl.Disposer.Record;
import javax.swing.JButton;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Toolkit;
import javax.swing.JTextField;
import javax.swing.JComboBox;
import javax.swing.DefaultComboBoxModel;
import traitement.CustomRenderer;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class TestSort extends JFrame implements ActionListener{
private JTable table1;
private JButton btnSort;
private int selectedCombCriteria=-1;
private JComboBox combCriteria;
private Boolean showSelection=false;
public static void main(String[] args) {
// TODO Auto-generated method stub
TestSort ts=new TestSort();
ts.setVisible(true);
}
TestSort()
{
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
this.setLocation(dim.width/2-this.getSize().width/2, dim.height/2-this.getSize().height/2);
setSize(new Dimension(439, 325));
setPreferredSize(new Dimension(600,400));
JPanel pt=new JPanel();
getContentPane().add(pt);
pt.setLayout(null);
combCriteria = new JComboBox();
combCriteria.setModel(new DefaultComboBoxModel(new String[] {"Age", "Score"}));
combCriteria.setSelectedIndex(0);
combCriteria.setBounds(115, 205, 67, 20);
combCriteria.addActionListener(this);
pt.add(combCriteria);
btnSort = new JButton("Sort");
btnSort.addActionListener(this);
btnSort.setBounds(324, 204, 89, 23);
pt.add(btnSort);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(20, 41, 393, 127);
pt.add(scrollPane);
table1 = new JTable();
SortModel sm=new SortModel();
table1.setModel(sm);
table1.setBounds(50, 26, 329, 130);
scrollPane.setViewportView(table1);
table1.getSelectionModel().addListSelectionListener(
new ListSelectionListener() {
public void valueChanged(ListSelectionEvent event) {
SortModel.selectedRecord=((SortModel)table1.getModel()).getRowAt(table1.getSelectedRow());
showSelection=true;
}
});
table1.setDefaultRenderer(Object.class, new DefaultTableCellRenderer()
{
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
final Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
c.setBackground(row==0?Color.YELLOW:isSelected&&showSelection?Color.lightGray:Color.white);
return c;
}
});
JLabel lblSelectARow = new JLabel("Select a row to keep at the top and sort using one of the sorting criteria");
lblSelectARow.setFont(new Font("Traditional Arabic", Font.PLAIN, 14));
lblSelectARow.setHorizontalAlignment(SwingConstants.CENTER);
lblSelectARow.setBounds(20, 11, 393, 23);
pt.add(lblSelectARow);
JLabel lblSortCreteria = new JLabel("Sorting criteria:");
lblSortCreteria.setBounds(20, 208, 96, 14);
pt.add(lblSortCreteria);
}
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource()==btnSort)
if(SortModel.selectedRecord!=null)
{
((SortModel)table1.getModel()).sort(selectedCombCriteria);
table1.repaint();
showSelection=false;
}
if(e.getSource()==combCriteria)
{
selectedCombCriteria=combCriteria.getSelectedIndex();
}
}
}
class SortModel extends AbstractTableModel
{
public SortModel(){
data=fillOnce();
}
private String[] columns = {"First Name", "Last Name", "Profession", "Age","Score","Comment"};
public List<MyDataRecord> data=new ArrayList<MyDataRecord>();
public static MyDataRecord selectedRecord;
@Override
public int getRowCount() {
// TODO Auto-generated method stub
return data.size();
}
@Override
public String getColumnName(int column) {
return columns[column];
}
@Override
public int getColumnCount() {
return columns.length;
}
public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0:
return data.get(rowIndex).getfName();
case 1:
return data.get(rowIndex).getlName();
case 2:
return data.get(rowIndex).getProfession();
case 3:
return data.get(rowIndex).getAge();
case 4:
return data.get(rowIndex).getScore();
case 5:
return data.get(rowIndex).getComment();
default:
throw new IllegalArgumentException();
}
}
public MyDataRecord getRowAt(int rowIndex)
{
return data.get(rowIndex);
}
//sorting method
public void sort(int sort)
{
//sort
Collections.sort(data, new Comparator<MyDataRecord>() {
public int compare(MyDataRecord object1, MyDataRecord object2) {
if(sort!=1)
return Integer.compare(object1.getAge(), object2.getAge());
else
return Integer.compare(object1.getScore(), object2.getScore());
}
});
//then remove he selected element
data.remove(selectedRecord);
//put the selected element on the top of the list
if(selectedRecord!=null)
{
data.add(0, selectedRecord);
}
}
public List<MyDataRecord> fillOnce()
{
List<MyDataRecord> tempList=new ArrayList<MyDataRecord>();
Random r = new Random();
for(int i=1;i<=6;i++)
{
MyDataRecord mdr=new MyDataRecord("FNtest"+i, "LNtest"+i, "PROFtest"+i, "COMtest"+i, r.nextInt(100-1) + 1, r.nextInt(100-1) + 1);
tempList.add(mdr);
}
return tempList;
}
}
class MyDataRecord{
private String fName,lName,profession,comment;
private int age,score;
public MyDataRecord(String fName, String lName, String profession,
String comment, int age, int score) {
super();
this.fName = fName;
this.lName = lName;
this.profession = profession;
this.comment = comment;
this.age = age;
this.score = score;
}
public String getfName() {
return fName;
}
public void setfName(String fName) {
this.fName = fName;
}
public String getlName() {
return lName;
}
public void setlName(String lName) {
this.lName = lName;
}
public String getProfession() {
return profession;
}
public void setProfession(String profession) {
this.profession = profession;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
已经制作了一个 CustomRowSorter,基本上是默认 DefaultRowSorter 的副本。 我无法扩展 class,因为我必须对排序方面的私有函数进行一些更改。
此外,我还必须制作自己的 TableRowSorter 副本,它使用了新的 CustomRowSorter。然后,我的 table 将使用 CustomTableRowSorter 来完成工作。这不是一个很好的实现,因为复制这两个文件是 1.5k 行的更改。