簡體   English   中英

Java JTable通過始終對固定列進行排序並允許用戶對任何輔助列進行排序來將行凍結在頂部

[英]Java JTable freeze rows to top by always sorting fixed column and allowing user to sort any secondary column

我正在使用顯示多個可排序列的JTable。 無論用戶如何對其余列表進行排序,我都需要將任何包含特定狀態的行凍結到列表頂部。 例如,使用以下未排序列表:未排序

當對文件大小頭的用戶點擊,它應與地位的文件大小列在這里看到“下載”到頂部,然后排序凍結任何行: 排序表

可以通過簡單地使用兩個JTables來解決此問題,但是這樣做看起來很丑陋,並提出了自己的挑戰:

  1. 調整列大小需要在調整第一個表的列大小時需要某種偵聽器來調整第二個表的列大小
  2. 排序需要某種偵聽器來對第二張表進行排序
  3. 需要隨着狀態值的變化在表之間不斷地來回移動數據行

我認為這種方法是不可接受的,並考慮了另一種方法:將一個隱藏的Position列添加到頂部,將要凍結的任何行的值都設置為'1',將所有其他狀態的值添加為'2',並永久保持此列的排序升序排列。 我能夠使用帶有多個SortKeys的TableRowSorter在初始加載時以這種方式對數據進行排序; 但是,我無法讓Position列排序發生在用戶選擇的列排序之前,因為沒有機制可以在SortKey之前添加前綴。 嘗試添加另一個SortKey總是將其添加到現有SortKey之后。

我首先嘗試將RowSorterListener添加到TableRowSorter,然后首先在Position列上對表格進行排序,然后在sorterChanged()事件上的用戶選擇列上對表進行重新排序,但是這沒有用,因為由於sorterChanged()而創建了一個無限循環每當有任何與排序順序相關的事件觸發該事件。

接下來,我嘗試將MouseListener添加到TableHeader中,並根據用戶單擊的列對表進行手動排序。 這一半有效,但最終失敗,因為JTable內置的排序程序代碼仍然會觸發。 因此,當用戶單擊標題時,它將通過我的代碼對其進行一次排序,然后通過JTable內部排序代碼對其進行相反的排序。 因此根本沒有排序。 除了完全禁用TableHeader之外,我沒有辦法使用或阻止此內部事件。 但是,這是不可接受的,因為它還會使用戶無法調整列的大小,並且不再顯示方向箭頭。

在進行一些在線搜索時,我遇到了一個功能完美的解決方案( https://stackoverflow.com/a/37721594/6143124 ),但最終無法使用,因為在將來的Java版本中將不支持該解決方案,並打印警告詳細信息為在Java 9上有很多:

WARNING: An illegal reflective access operation has occurred 
WARNING: Illegal reflective access by pkg.PredefinedRowSorter to field javax.swing.DefaultRowSorter.sortKeys WARNING: Please consider reporting this to the maintainers of pkg.PredefinedRowSorter 
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

我被困在一個更好的公園一周的時間里,將不勝感激任何幫助或指導。

謝謝,賽德

通過創建自己的TableRowSorter並重寫toggleSortOrder()方法,我能夠實現所需的結果。

import java.util.ArrayList;
import java.util.List;

import javax.swing.SortOrder;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;

public class PredefinedTableRowSorter<M extends TableModel> extends TableRowSorter<TableModel>
{
    public PredefinedTableRowSorter (TableModel model)
    {
        super(model);
    }

    @Override
    public void toggleSortOrder (int column)
    {
        List<SortKey> newSortKeys = new ArrayList<>();
        newSortKeys.add(new SortKey(0, SortOrder.ASCENDING));

        SortKey currentKey = getSortKey(column);
        SortOrder sortOrder = SortOrder.ASCENDING;

        if (currentKey != null) {
            sortOrder = currentKey.getSortOrder() == SortOrder.ASCENDING ? SortOrder.DESCENDING : SortOrder.ASCENDING;
        }

        currentKey = new SortKey(column, sortOrder);
        newSortKeys.add(currentKey);

        super.setSortKeys(newSortKeys);

        super.sort();
    }

    private SortKey getSortKey (int column)
    {
        for (SortKey key : super.getSortKeys()) {
            if (key.getColumn() == column) {
                return key;
            }
        }

        return null;
    }
}

該解決方案提出了一個新問題:排序箭頭圖標僅出現在已排序的第一列上。 我通過編寫自定義DefaultTableCellRenderer並將其應用到表格標題中來解決了這個問題,但這與系統的外觀和風格不符(Windows 10通常在標題的頂部中間顯示排序箭頭,而將其放置在我的自定義渲染器中的文本)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM