在 Java 11(带有 swingx 1.6.6)中,我刚刚实现了多列排序,如下所示:
但是我没有办法重置排序并查看其他一些应用程序,我认为我希望它以以下方式工作:
因此,每当有人单击或 cntl-clicks 都会导致调用
toggleSort()
,但我如何捕获用户已 cntl-clicked 而不是单击,并知道 toggleSort()
可以访问它
仅供参考,修改后的
toggleSort()
方法扩展了
org.jdesktop.swingx.sort.TableSortController
,我修改了 swingx 代码,这样我就可以访问以前的私有方法 getFirstInCycle()
和 getNextInCycle()
)
public void toggleSortOrder(int column)
{
//Are we allowed to this sort column
if (this.isSortable(column))
{
SortOrder firstInCycle = this.getFirstInCycle();
//If all already a column in sort cycle
if (firstInCycle != null)
{
//Make a copy of existing keys
List<SortKey> keys = new ArrayList(this.getSortKeys());
//Look for any existing sort key for column user has clicked on
SortKey sortKey = SortUtils.getFirstSortKeyForColumn((List)keys, column);
//If its the first one
if (((List)keys).indexOf(sortKey) == 0)
{
//Swap the sort order of to next one, i.e ascending to descending
((List)keys).set(0, new SortKey(column, this.getNextInCycle(sortKey.getSortOrder())));
}
else
{
//Add new final sort key for this column
((List)keys).add(new SortKey(column, this.getFirstInCycle()));
}
//Trim the number of keys if we have to many
if (((List)keys).size() > this.getMaxSortKeys()) {
keys = ((List)keys).subList(0, this.getMaxSortKeys());
}
this.setSortKeys((List)keys);
}
}
}
Sooo,我一直在研究代码,我认为你遇到了很多问题。 鼠标单击的处理由 UI 委托(特别是
BaseTableHeaderUI
)执行,它直接调用 TableRowSorter#toggleSortOrder
。 因此,表和表头根本不涉及,因此不存在可以控制此工作流程的注入点。
然后我考虑简单地在
MouseListener
本身添加一个 JTableHeader
。 我最初担心的是,这会与 MouseListener
使用的现有 TableHeaderUI
接口,但如果我们想要做的只是在标题为 Control+Clicked 时删除
SortKey
,那么它“应该” “没关系,但是,您会接到两个电话:toggleSortOrder
现在,我没有使用 SwingX,这只是纯粹的 Swing,但这个概念应该可行 🤞。
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.RowSorter.SortKey;
import static javax.swing.SortOrder.ASCENDING;
import static javax.swing.SortOrder.DESCENDING;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JTable table = new JTable();
DefaultTableModel model = new DefaultTableModel(
new Object[]{"abc", "def", "ghi", "jkl"},
0);
model.addRow(new Object[]{"A", "B", "C", "I"});
model.addRow(new Object[]{"B", "C", "D", "J"});
model.addRow(new Object[]{"C", "D", "E", "K"});
model.addRow(new Object[]{"D", "E", "F", "L"});
model.addRow(new Object[]{"E", "F", "G", "M"});
model.addRow(new Object[]{"F", "G", "H", "N"});
table.setModel(model);
// table.setTableHeader(new CustomTableHeader(table));
table.getTableHeader().setDefaultRenderer(new DefaultTableHeaderCellRenderer());
table.setRowSorter(new TableRowSorter<DefaultTableModel>(model));
JTableHeader header = table.getTableHeader();
header.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (!(e.getSource() instanceof JTableHeader)) {
return;
}
JTableHeader header = (JTableHeader) e.getSource();
JTable table = header.getTable();
RowSorter<? extends TableModel> rowSorter = table.getRowSorter();
if (rowSorter == null) {
return;
}
int column = header.columnAtPoint(e.getPoint());
if (column == -1) {
return;
}
List<? extends SortKey> sortKeys = rowSorter.getSortKeys();
List<SortKey> newSortKeys = new ArrayList<>(sortKeys);
Optional<? extends SortKey> firstMatch = sortKeys
.stream()
.filter(key -> key.getColumn() == column)
.findFirst();
if (e.isControlDown()) {
if (firstMatch.isPresent()) {
SortKey sortKey = firstMatch.get();
newSortKeys.remove(sortKey);
}
}
rowSorter.setSortKeys(newSortKeys);
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DefaultTableHeaderCellRenderer extends DefaultTableCellRenderer {
public DefaultTableHeaderCellRenderer() {
setHorizontalAlignment(CENTER);
setHorizontalTextPosition(LEFT);
setVerticalAlignment(BOTTOM);
setOpaque(false);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value, false, hasFocus, row, column);
JTableHeader tableHeader = table.getTableHeader();
if (tableHeader != null) {
setForeground(tableHeader.getForeground());
}
setIcon(getIcon(table, column));
setBorder(UIManager.getBorder("TableHeader.cellBorder"));
return this;
}
protected Icon getIcon(JTable table, int column) {
SortKey sortKey = getSortKey(table, column);
if (sortKey != null && table.convertColumnIndexToView(sortKey.getColumn()) == column) {
switch (sortKey.getSortOrder()) {
case ASCENDING:
return UIManager.getIcon("Table.ascendingSortIcon");
case DESCENDING:
return UIManager.getIcon("Table.descendingSortIcon");
}
}
return null;
}
protected SortKey getSortKey(JTable table, int column) {
RowSorter rowSorter = table.getRowSorter();
if (rowSorter == null) {
return null;
}
List sortedColumns = rowSorter.getSortKeys();
if (sortedColumns.size() > 0) {
return (SortKey) sortedColumns.get(0);
}
return null;
}
}
}
我在这里看到的问题是弄清楚
JTable
如何切换排序键以及何时通过Control+Clicked事件实际删除排序键之间的区别...
这就是我将双手举在空中,然后在升序、降序和无之间切换排序顺序,所以你只需要点击它即可,但这就是我
决定更好地放弃 cntl-click 想法,而是通过修改
org.jdesktop.swingx.sort,DefaultSortController
from 来恢复三阶段循环
private final static SortOrder[] DEFAULT_CYCLE
= new SortOrder[] {SortOrder.ASCENDING, SortOrder.DESCENDING};
到
private final static SortOrder[] DEFAULT_CYCLE
= new SortOrder[] {SortOrder.ASCENDING, SortOrder.DESCENDING,SortOrder.UNSORTED};
然后这是我的自定义排序控制器中的toggleSortOrder()方法
/**
* If new sort key sort ascending as after other existing sort keys
* If existing sort key and ascending cycle change to descending
* If existing sort key and descending remove the sort key
* If already at MAX_SORT_COLUMNS the ignore
*
* @param column
*/
@Override
public void toggleSortOrder(int column)
{
//Are we allowed to this sort column
if (this.isSortable(column))
{
SortOrder firstInCycle = this.getFirstInCycle();
//If all already a column in sort cycle
if (firstInCycle != null)
{
//Make a copy of existing keys
List<SortKey> newKeys = new ArrayList(this.getSortKeys());
//Look for any existing sort key for column user has clicked on
SortKey sortKey = SortUtils.getFirstSortKeyForColumn(newKeys, column);
//Existing Key
if(sortKey!=null)
{
//Get next in cycle
SortOrder nextSortOrder = this.getNextInCycle(sortKey.getSortOrder());
//Swap to descending/ascending
if(nextSortOrder==SortOrder.DESCENDING || nextSortOrder==SortOrder.ASCENDING)
{
newKeys.set((newKeys).indexOf(sortKey), new SortKey(column, nextSortOrder));
}
//Remove from sort
else
{
newKeys.remove(sortKey);
}
}
//New Key
else
{
(newKeys).add(new SortKey(column, this.getFirstInCycle()));
}
//Trim the number of keys if we have too many
if ((newKeys).size() > this.getMaxSortKeys()) {
newKeys = ((List)newKeys).subList(0, this.getMaxSortKeys());
}
this.setSortKeys(newKeys);
}
}
}
我有解决您问题的正确方法。您必须禁用自动排序并指示排序器以正确的顺序对正确的列进行排序。完成您需要的一切:
public class RndDefaultTableHeaderCell extends JPanel implements TableCellRenderer {
private static final long serialVersionUID = 1L;
final private JLabel title = new JLabel();
final private JLabel icon = new JLabel();
final private JLabel ordinal = new JLabel();
final private Icon ascIcon = UIManager.getIcon("Table.ascendingSortIcon");
final private Icon descIcon = UIManager.getIcon("Table.descendingSortIcon");
public RndDefaultTableHeaderCell() {
super();
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(Box.createHorizontalGlue());
add(title);
add(icon);
add(ordinal);
add(Box.createHorizontalGlue());
setBorder(UIManager.getBorder("TableHeader.cellBorder"));
Font f = ordinal.getFont();
ordinal.setFont(f.deriveFont(f.getStyle() & ~Font.BOLD));
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
icon.setIcon(null);
title.setText(value.toString());
ordinal.setText(null);
List<? extends SortKey> sortKeys = table.getRowSorter().getSortKeys();
for (int i = 0; i < sortKeys.size(); i++) {
SortKey sortKey = sortKeys.get(i);
if (sortKey.getColumn() == table.convertColumnIndexToModel(column)) {
icon.setIcon(sortKey.getSortOrder() == SortOrder.ASCENDING ? ascIcon : descIcon);
if (sortKeys.size() > 1)
ordinal.setText("(" + (i + 1) + ")");
break;
}
}
return this;
}
}
上面的渲染器将向上/向下箭头放置在每个有序列的列标题之后,以及在括号之间的有序列的序数之后。
...
JTable table = new JTable(myModel);
TableRowSorter<MyModel> sorter = new TableRowSorter<MyModel>(myModel);
for (int i = 0; i < table.getColumnCount(); i++)
sorter.setSortable(i, false);
table.setRowSorter(sorter);
JTableHeader header = table.getTableHeader();
header.setDefaultRenderer(new RndDefaultTableHeaderCell());
header.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int column = table.convertColumnIndexToModel(header.columnAtPoint(e.getPoint()));
SortKey sortKeyAscending = new SortKey(column, SortOrder.ASCENDING);
SortKey sortKeyDescending = new SortKey(column, SortOrder.DESCENDING);
List<? extends SortKey> oldSortKeys = sorter.getSortKeys();
List<SortKey> newSortKeys;
if (e.isShiftDown()) {
newSortKeys = new ArrayList<>(oldSortKeys);
int index;
if ((index = oldSortKeys.indexOf(sortKeyAscending)) != -1)
newSortKeys.set(index, sortKeyDescending);
else if ((index = oldSortKeys.indexOf(sortKeyDescending)) != -1)
newSortKeys.set(index, sortKeyAscending);
else
newSortKeys.add(sortKeyAscending);
} else {
newSortKeys = new ArrayList<>();
if (oldSortKeys.contains(sortKeyAscending))
newSortKeys.add(sortKeyDescending);
else
newSortKeys.add(sortKeyAscending);
}
sorter.setSortKeys(newSortKeys);
}
});
使用提供的代码,您将获得下图所示的结果: 结果示例 为了实现上述排序,我在 Prog 上单击了两次(第一次单击升序,第二次单击降序),然后在 Exchange 上单击按住 CONTROL 一次。