4

2 つの列で構成される JTable にいくつかの結果を表示しています。

ファイル - 結果

コピー エントリを表示する JPopupMenu を実装し、右クリックしたセルの値をコピーしようとしました。

filelistTable.addMouseListener(new MouseAdapter() {
    @Override
    public void mouseClicked(MouseEvent e) {
         if(SwingUtilities.isRightMouseButton(e))
         {
             TablePopupMenu popup = new TablePopupMenu(filelistTable, e.getPoint());
             filelistTable.setComponentPopupMenu(popup);
         }
    }
});

--

    public TablePopupMenu(JTable table, Point p) {

        this.table = table;
        this.p = p;

        JMenuItem mntmKopieren = new JMenuItem("Kopieren");
        mntmKopieren.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                copyCellToClipboard();
            }
        });
        add(mntmKopieren);
    }

    public void copyCellToClipboard()
    {
        int r = table.rowAtPoint(p);
        int c = table.columnAtPoint(p);
        System.out.println(table.getValueAt(table.convertRowIndexToView(r), 
                table.convertRowIndexToView(c)));
        StringSelection entry = new StringSelection(table.getValueAt(table.convertRowIndexToView(r), 
                table.convertRowIndexToView(c)).toString());
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        clipboard.setContents( entry, this );

    }

とにかく、これは少数のテストでのみ機能します。私は何か間違ったことをしたか、何か不足していましたか?セルが正しく選択されないかのように見えます。

4

1 に答える 1

5

2 つの点が少しずれています。

  • clicked で componentPopup を設定するのは、mouseEvents のシーケンスでは遅すぎます (ポップアップは通常、クリックの前に発生する押されたまたは離されたときにトリガーされます)。
  • 値が間違ったセルから取得されます: JTable のすべての座標はビュー座標系にあり、それらをビュー座標に変換すると完全にオフになります

つまり、セル座標関連のコンテキストの取得はサポートが不十分です。多くの場合、最善の策は (以下のコード スニペット) です。

  • getPopupLocation(MouseEvent) をオーバーライドし、場所をどこかに保存します
  • 場所にアクセスするためのポップアップ/アクションを実装する

(正常に動作するアプリケーションで行う必要があるように) ポップアップがキーボードによってトリガーされる可能性がある場合は失敗します。その場合は、操作する他のマーカー (フォーカスされたセル) を提供する必要があります。

final String popupLocation = "table.popupLocation";
final JTable table = new JXTable(new AncientSwingTeam()) {

    @Override
    public Point getPopupLocation(MouseEvent event) {
        // event may be null if triggered by keyboard, f.i.
        // thanks to @Mad for the heads up!
        ((JComponent) event.getComponent()).putClientProperty(
                popupLocation, event != null ? event.getPoint() : null);
        return super.getPopupLocation(event);
    }

};
JPopupMenu popup = new JPopupMenu();
Action printLocation = new AbstractAction("print cell") {

    @Override
    public void actionPerformed(ActionEvent e) {
       Point p = (Point) table.getClientProperty(popupLocation);
       if (p != null) { // popup triggered by mouse
           int row = table.rowAtPoint(p);
           int column = table.columnAtPoint(p);
           LOG.info("" + table.getValueAt(row, column)); 
       } else { // popup triggered otherwise
           // could choose f.i. by leadRow/ColumnSelection
           ...
       }
    }

};
popup.add(printLocation);
table.setComponentPopupMenu(popup);

編集(マッドのコメントがきっかけ):

トリガーポイントはプラットフォームに依存するため、MouseEvent.isPopupTrigger を確認する必要があります。これは、mousePressed、mouseReleased、および mouseClicked を監視する必要があることを意味します。

いいえ、それは必要ありません (チェックしただけです :-): mouseEvent に応答して componentPopup を表示するメカニズム - BasicLookAndFeel.AWTEventHelper で発生します - popupTrigger の場合にのみそうします

api doc (昨日すべきだった ;-) をもう一度読むと、メソッドは常にcomponentPopup を表示する前に呼び出されることがわかります。その場合、イベント パラメータは null であり、元のコードは失敗します。明るい面では、その保証があれば、ターゲット セルを見つけるためのすべてのロジックをそのメソッドに移動できます。ただし、試していないため、実行可能ではない可能性があります(その時点でまだ完全に処理されていない可能性のある LeadRow/ColumnSelection に基づいて場所を指定する必要がある場合)

于 2012-09-19T11:14:51.427 に答える