15

がありJTable、列を並べ替えることができる必要があります。ただし、最初の列を並べ替えられないようにする必要があります。並べ替えを有効にするために、以下を使用しました。

table.getTableHeader().setReorderingAllowed(true);

これで、不要な最初の列を含めて、列を並べ替えることができます。最初の列をロックする方法はありますか?

2つのテーブルを使用し、最初の列が別のテーブルにあるソリューションをいくつか見てきましたが、もっと良い/簡単な方法があるかもしれません。

4

8 に答える 8

8

これは、最初の列が並べ替えられないようにするために使用したソリューションです。

private int columnValue = -1; 
private int columnNewValue = -1; 


tblResults.getColumnModel().addColumnModelListener(new TableColumnModelListener() 
{ 
    public void columnAdded(TableColumnModelEvent e) {} 

    public void columnMarginChanged(ChangeEvent e) {} 

    public void columnMoved(TableColumnModelEvent e) 
    { 
        if (columnValue == -1) 
            columnValue = e.getFromIndex(); 

        columnNewValue = e.getToIndex(); 
    } 

    public void columnRemoved(TableColumnModelEvent e) {} 

    public void columnSelectionChanged(ListSelectionEvent e) {} 
}); 

tblResults.getTableHeader().addMouseListener(new MouseAdapter() 
{ 
    @Override 
    public void mouseReleased(MouseEvent e) 
    { 
        if (columnValue != -1 && (columnValue == 0 || columnNewValue == 0)) 
        tblResults.moveColumn(columnNewValue, columnValue); 

        columnValue = -1; 
        columnNewValue = -1; 
    } 
}); 

乾杯、

于 2010-02-08T02:00:47.287 に答える
5

ほぼ4年経った今でも、最適なソリューションはどこにもありません。

最初の列(および最初の列上の他の列)のドラッグを防ぐためのさらに別の次善のアプローチは、uidelegateによってインストールされたmouseInputListenerがそれらを処理できるようになる前にmouseEventsをインターセプトすることです(最近のQAと同様)。

協力者

  • 最初にインストールされたものにすべてのイベントを委任するカスタムMouseMotionListener。ただし、最初の列の上に別の列が表示される場合はドラッグされます。
  • オリジナルをカスタムに置き換えます
  • LAFが変更されるたびに置換を更新します(元のファイルはUIによって制御されるため)。これには、JTableHeaderのサブクラス化が必要であり、updateUIで配線を行います。

カスタムMouseInputListener:

/**
 * A delegating MouseInputListener to be installed instead of
 * the one registered by the ui-delegate.
 * 
 * It's implemented to prevent dragging the first column or any other
 * column over the first.
 */
public static class DragHook implements MouseInputListener {

    private JTableHeader header;
    private MouseListener mouseDelegate;
    private MouseMotionListener mouseMotionDelegate;
    private int maxX;

    public DragHook(JTableHeader header) {
        this.header = header;
        installHook();
    }

    /**
     * Implemented to do some tweaks/bookkeeping before/after
     * passing the event to the original
     * 
     * - temporarily disallow reordering if hit on first column
     * - calculate the max mouseX that's allowable in dragging to the left
     * 
     */
    @Override
    public void mousePressed(MouseEvent e) {
        int index = header.columnAtPoint(e.getPoint());
        boolean reorderingAllowed = header.getReorderingAllowed();
        if (index == 0) {
            // temporarily disable re-ordering 
            header.setReorderingAllowed(false);
        }
        mouseDelegate.mousePressed(e);
        header.setReorderingAllowed(reorderingAllowed);
        if (header.getDraggedColumn() != null) {
            Rectangle r = header.getHeaderRect(index);
            maxX = header.getColumnModel().getColumn(0).getWidth() 
                    + e.getX() - r.x -1; 
        }
    }

    /**
     * Implemented to pass the event to the original only if the
     * mouseX doesn't lead to dragging the column over the first.
     */
    @Override
    public void mouseDragged(MouseEvent e) {
        TableColumn dragged = header.getDraggedColumn();
        int index = getViewIndexForColumn(header.getColumnModel(), dragged);
        // dragged column is at second position, allow only drags to the right
        if (index == 1) {
            if (e.getX() < maxX) return;
        }
        mouseMotionDelegate.mouseDragged(e);
    }

    //-------- delegating-only methods

    @Override
    public void mouseReleased(MouseEvent e) {
        mouseDelegate.mouseReleased(e);
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        mouseDelegate.mouseClicked(e);
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        mouseDelegate.mouseEntered(e);
    }

    @Override
    public void mouseExited(MouseEvent e) {
        mouseDelegate.mouseExited(e);
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        mouseMotionDelegate.mouseMoved(e);
    }

    //------------ un-/install listeners

    protected void installHook() {
        installMouseHook();
        installMouseMotionHook();
    }

    protected void installMouseMotionHook() {
        MouseMotionListener[] listeners = header.getMouseMotionListeners();
        for (int i = 0; i < listeners.length; i++) {
            MouseMotionListener l = listeners[i];
            if (l.getClass().getName().contains("TableHeaderUI")) {
                this.mouseMotionDelegate = l;
                listeners[i] = this;
            }
            header.removeMouseMotionListener(l);
        }
        for (MouseMotionListener l : listeners) {
            header.addMouseMotionListener(l);
        }
    }

    protected void installMouseHook() {
        MouseListener[] listeners = header.getMouseListeners();
        for (int i = 0; i < listeners.length; i++) {
            MouseListener l = listeners[i];
            if (l.getClass().getName().contains("TableHeaderUI")) {
                this.mouseDelegate = l;
                listeners[i] = this;
            }
            header.removeMouseListener(l);
        }
        for (MouseListener l : listeners) {
            header.addMouseListener(l);
        }
    }

    public void uninstallHook() {
        uninstallMouseHook();
        uninstallMouseMotionHook();
    }

    protected void uninstallMouseMotionHook() {
        MouseMotionListener[] listeners = header.getMouseMotionListeners();
        for (int i = 0; i < listeners.length; i++) {
            MouseMotionListener l = listeners[i];
            if (l == this) {
                listeners[i] = mouseMotionDelegate;
            }
            header.removeMouseMotionListener(l);
        }
        for (MouseMotionListener l : listeners) {
            header.addMouseMotionListener(l);
        }
    }

    protected void uninstallMouseHook() {
        MouseListener[] listeners = header.getMouseListeners();
        for (int i = 0; i < listeners.length; i++) {
            MouseListener l = listeners[i];
            if (l == this) {
                listeners[i] = mouseDelegate;
            }
            header.removeMouseListener(l);
        }
        for (MouseListener l : listeners) {
            header.addMouseListener(l);
        }
    }

}

LAF、fiの切り​​替え後も存続する使用法:

JTable table = new JTable(new AncientSwingTeam()) {

    @Override
    protected JTableHeader createDefaultTableHeader() {
        JTableHeader header = new JTableHeader(getColumnModel()) {
            DragHook hook;

            @Override
            public void updateUI() {
                if (hook != null) {
                    hook.uninstallHook();
                    hook = null;
                }
                super.updateUI();
                hook = new DragHook(this);
            }

         };
        return header;
    }

};
于 2013-01-23T13:31:53.717 に答える
4

columnMoved()のメソッドをオーバーライドする必要があると思いますTableColumnModelListenerTableColumnModelEventクラスには、それが固定列であるかどうかを判断するために確認できるはずのメソッドgetFromIndex()があり、その後、イベントをキャンセルできるはずです。

お役に立てば幸いです。A

于 2009-07-20T18:58:27.483 に答える
2

私も同じ問題を抱えていて、それについて探していました。これまでのところ、私はそれを行う2つの方法を見つけました。

  • 「自分で書き直した場合」の方法:Javaから基本クラスを変更します。

TableColumn「resizingAllowed」のような新しいプロパティが必要になる場合は、「reorderingAllowed」が必要になります。これから、変更は次の場所で行われBasicTableHeaderUIます。

すでにあります:

private static boolean canResize(TableColumn column,
                                 JTableHeader header) {
    return (column != null) && header.getResizingAllowed()
                            && column.getResizable();
}

それも必要です:

private static boolean canMove(TableColumn column,
                               JTableHeader header) {
    return (column != null) && header.getReorderingAllowed()
                                && column.getReorderable();
}

(最初の列だけを移動させたくない場合は、TableColumnsを変更せずに移動できることに注意してください。

private static boolean canMove(TableColumn column,
                                 JTableHeader header) {
    return (column != null) && header.getReorderingAllowed()
                            && header.getColumnModel().getColumnIndex(column.getIdentifier()) != 0;
}

)。

その後、MouseInputListener:で変更する2つの場所

  • で、の代わりにmousePressed呼び出します。これにより、移動してはならない列が移動しないことが保証されます。canMove()header.getReorderingAllowed()
  • ただし、これだけでは不十分です。別の列をドラッグしているときに、動かない列が移動しないようにする必要があります。mouseDragged「newColumnIndex」を取得するときにも、を変更する必要があります。

    if(0 <newColumnIndex && newColumnIndex <cm.getColumnCount())

たとえば「canMove()」メソッドを使用して、この新しいインデックスを移動できる場合は、条件を追加する必要があります。このように、列をこの不動の列にドラッグする場合でも、列をドラッグしますが、列を入れ替えることはありません。

このメソッドでは、JTableに使用されるJTableHeaderのUIを明示的に設定する必要があることに注意してください。これは、実際には理想的ではありません。しかし、これは想定されている場所の問題を扱っているため、最も適しています。


  • 「実際にあるもので通常の動作をブロックしてみましょう」メソッド:UIを変更せずに、このメソッドはJTableHeaderに焦点を合わせて、UIによって作成されたコマンドをブロックします。

まず、最初の列のドラッグをブロックするには、このオーバーライドされたメソッドを使用して、JTableHeaderのサブクラスが必要です。

@Override
public void setDraggedColumn(TableColumn pAColumn)
{
    int lIndex  = -1;
    if (pAColumn != null)
        lIndex = getColumnModel().getColumnIndex(pAColumn.getIdentifier());
    if (lIndex != 0)
        super.setDraggedColumn(pAColumn);
}

これにより、ユーザーが最初の列をドラッグできなくなります。ただし、前述のように、これは問題の一部にすぎません。別のドラッグされた列がこの最初の列とスワップしないようにする必要があります。

これまでのところ、これに対する正しい方法はありません。TableColumnModelをサブクラス化し、moveColumn()メソッドをオーバーライドしてみました。

@Override
public void moveColumn(int pColumnIndex, int pNewIndex)
{
    //Move only if the first column is not concerned
    if (pColumnIndex =! 0 && pNewIndex != 0)
        super.moveColumn(pColumnIndex, pNewIndex);
}

ただし、これは機能しません。UIはmouseDraggedメソッド内のマウスの位置を更新するため、ドラッグした列から別の場所にジャンプします。

それで私はまだ探しています、そして誰かがこの部分に関して提案を持っているかどうか疑問に思います。

于 2009-08-12T16:07:00.847 に答える
2

まず、より適切で簡単な方法を定義する必要があります。2テーブルアプローチの何が好きではありませんか?

列がすでに移動された「後に」イベントが発生するため、TableColumnModelListenerを使用することはできません。

列をドラッグするためのコードは、BasicTableHeaderUIにあります。したがって、そこでコードをオーバーライドしてみることができますが、その場合はすべてのLAFに対してオーバーライドする必要があります。

上記のコードは、mousePressedイベントでJTableHeader.getReorderingAllowed()を呼び出して、列の並べ替えが許可されているかどうかを判別します。JTableHeaderでそのメソッドをオーバーライドし、MouseInfoクラスを使用して現在のマウスの場所を取得し、それが最初の列を超えているかどうかを判断して、falseを返すことができると思います。ただし、カスタムテーブルヘッダーを使用するカスタムJTableも作成する必要があります。

もちろん、上記の提案のいずれかを使用すると、最初の列が移動するのを防ぐことができる場合があります。ただし、2番目の列が最初の列の前に挿入されないようにする必要もあることを忘れないでください。私はその質問に対する短い簡単な答えがあるとは思わない。

固定列テーブルは、これが2つのテーブルでどのように実装されるかについての私のバージョンです。いいですか?わかりませんが、1行のコードで使用できるので簡単です。

于 2009-07-20T23:31:33.670 に答える
1

最初は、TableColumnModelのサブクラス化とmoveColumnのオーバーライドで構成される、最後のGnoupiの提案を使用しましたが、それでも厄介なジャンプがいくつかありました。

これは「私の」完全に機能し、厄介なジャンプのないテスト済みのソリューションであり、主にStanislavKoとkleopatraの提案に依存しています。マウスボタンを離したときに不要な動きを元に戻すためのより複雑なメカニズムを追加しました。

table.getTableHeader().setUI(new WindowsTableHeaderUI() {
        @Override
        protected MouseInputListener createMouseInputListener() {
            return new BasicTableHeaderUI.MouseInputHandler() {

                @Override
                public void mouseDragged(MouseEvent e) {
                    if (header.isEnabled() && header.getReorderingAllowed() && header.getDraggedColumn() != null && header.getDraggedColumn().getModelIndex() == frozenColumnModelIndex) {
                        header.setDraggedDistance(0);
                        header.setDraggedColumn(null);
                        return;
                    }
                    super.mouseDragged(e);
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    if (header.isEnabled() && header.getReorderingAllowed() && header.getDraggedColumn() != null &&
                        0 <= illegalTableColumnMoveFromIndex && illegalTableColumnMoveFromIndex < header.getTable().getColumnModel().getColumnCount()) {
                        header.setDraggedDistance(0);
                        header.setDraggedColumn(null);
                        header.getTable().getColumnModel().moveColumn(illegalTableColumnMoveToIndex, illegalTableColumnMoveFromIndex);
                        illegalTableColumnMoveFromIndex = -1;
                        illegalTableColumnMoveToIndex = -1;
                        return;
                    }
                    super.mouseReleased(e);
                }
            };
        }
    });
    table.getColumnModel().addColumnModelListener(new TableColumnModelListener() {
        @Override
        public void columnAdded(TableColumnModelEvent e) {
        }

        @Override
        public void columnRemoved(TableColumnModelEvent e) {
        }

        @Override
        public void columnMoved(TableColumnModelEvent e) {
            if (e.getFromIndex() != e.getToIndex() && table.getColumnModel().getColumn(e.getFromIndex()).getModelIndex() == frozenColumnModelIndex) {
                illegalTableColumnMoveFromIndex = e.getFromIndex();
                illegalTableColumnMoveToIndex = e.getToIndex();
            } else {
                illegalTableColumnMoveFromIndex = -1;
                illegalTableColumnMoveToIndex = -1;
            }
        }

        @Override
        public void columnMarginChanged(ChangeEvent e) {
        }

        @Override
        public void columnSelectionChanged(ListSelectionEvent e) {
        }
    });

列のドラッグを完​​全に元に戻すのではなく、最新の有効な移動が受け入れられることに注意してください。

brokenColumnModelIndexは、テーブルモデルの「凍結」列のインデックスです。

illegalTableColumnMoveFromIndexは、最新の不正な移動が検出されたときに移動された列のインデックスです。

illegalTableColumnMoveToIndexは、最新の不正な移動が検出されたときに移動された列のインデックスです。

mouseDragged内のコードは、フリーズされた列がドラッグされるのを防ぐのに十分であり、残りは、別の列がフリーズされた列にドラッグされるのを防ぐことができます。

WindowsTableHeaderUIを拡張すると、Microsoft Windowsでそのまま機能しますが、リフレクションAPIを使用してテーブルヘッダーUIのマウス入力リスナーを設定し、uninstallerListeners()を呼び出し、最後にheader.addMouseListener(mouseInputListener)とheader.addMouseMotionListener(mouseInputListener)を呼び出します。各テーブルヘッダーUIのクラス名を想定せずに、ソリューションをクロスプラットフォームで駆動するため。

私はそれがkleopatraのソリューションよりも少し堅牢ではないかもしれないことを認めます。皆さんの助けに感謝します。私は本当に感謝しています。そして、共同作業がうまくいくのを見て本当にうれしいです:)

于 2014-05-23T12:27:02.817 に答える
0

私は「「実際にあるもので通常の動作をブロックしよう」という方法を使用しました」というアプローチを使用しました。グヌーピは、問題の2番目の部分を解決しなかったと述べました。Windows XP L&Fのみのソリューションは次のとおりです。

  1. XPStyleクラスを自分自身にコピーします。
  2. 拡張しWindowsTableHeaderUIます。ソースコードを見てください。
  3. これを使って:getTableHeader().setUI(new TreeTableWindowsTableHeaderUI());

努力してくれたGnoupiに感謝します。

于 2009-10-25T07:25:59.160 に答える
0

移動が完了したら、列を元に戻します。だから何かのような。

@Override
public void moveColumn(int from, int to) {
      super.moveColumn(from, to);
      if (from == 0 || to == 0) {
           super.moveColumn(to, from);
      }
}
于 2015-02-16T22:33:40.287 に答える