java 带有 JPopupMenu 的 JTable

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7423533/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 19:55:03  来源:igfitidea点击:

JTable with JPopupMenu

javaswingjtableonmouseoverjpopupmenu

提问by mKorbel

how can I prevent triggering and showing JPopupMenuonly if is Mouse Cursorover selected JTable'Row

如何防止触发和JPopupMenu仅在Mouse Cursor过度选择时显示JTable'Row

my question: if is there another way as getBoundsfrom selected row and determine/compare that with Mouseposition...

我的问题:是否有另一种方式getBounds从所选行开始并确定/与Mouse位置进行比较...

my simple sscce demonstrated just un-wanted opposite status, any row could be selected and JPopupMenuis triggered from whole JTable

我的简单 sscce 展示了不想要的相反状态,可以选择任何行并JPopupMenu从整个触发JTable

import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;

public class TableCheckBox extends JFrame {

    private static final long serialVersionUID = 1L;
    private JTable table;

    public TableCheckBox() {
        Object[] columnNames = {"Type", "Company", "Shares", "Price", "Boolean"};
        Object[][] data = {
            {"Buy", "IBM", new Integer(1000), new Double(80.50), false},
            {"Sell", "MicroSoft", new Integer(2000), new Double(6.25), true},
            {"Sell", "Apple", new Integer(3000), new Double(7.35), true},
            {"Buy", "Nortel", new Integer(4000), new Double(20.00), false}
        };
        DefaultTableModel model = new DefaultTableModel(data, columnNames);
        table = new JTable(model) {

            private static final long serialVersionUID = 1L;

            @Override
            public Class getColumnClass(int column) {
                return getValueAt(0, column).getClass();
            }
        };
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane = new JScrollPane(table);
        add(scrollPane);
        createPopupMenu();
    }

    private void createPopupMenu() {
        JPopupMenu popup = new JPopupMenu();
        JMenuItem myMenuItem1 = new JMenuItem("cccccccccccccccccccccc");
        JMenuItem myMenuItem2 = new JMenuItem("bbbbbbbbbbbbbbbbbbbbbb");
        popup.add(myMenuItem1);
        popup.add(myMenuItem2);
        MouseListener popupListener = new PopupListener(popup);
        table.addMouseListener(popupListener);
    }

    private class PopupListener extends MouseAdapter {

        private JPopupMenu popup;

        PopupListener(JPopupMenu popupMenu) {
            popup = popupMenu;
        }

        @Override
        public void mousePressed(MouseEvent e) {
            maybeShowPopup(e);
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            if (table.getSelectedRow() != -1) {
                maybeShowPopup(e);
            }
        }

        private void maybeShowPopup(MouseEvent e) {
            if (e.isPopupTrigger()) {
                popup.show(e.getComponent(), e.getX(), e.getY());
            }
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                TableCheckBox frame = new TableCheckBox();
                frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocation(150, 150);
                frame.setVisible(true);
            }
        });
    }
}

采纳答案by kleopatra

It's an interesting question, because it highlights missing api on JComponent :-)

这是一个有趣的问题,因为它突出显示了 JComponent 上缺少的 api :-)

As we all know, the recommended way to register popupMenus is to use the componentPopupMenu property. Related api is

众所周知,注册 popupMenus 的推荐方式是使用 componentPopupMenu 属性。相关的api是

 void setComponentPopupMenu(JPopupMenu);
 JPopupMenu getComponentPopupMenu();
 Point getPopupLocation(MouseEvent);

what is missing (and actually needed for this requirement) is

缺少的(并且实际上需要此要求)是

JPopupMenu getComponentPopupMenu(MouseEvent);

this lack is all the more annoying, as the getPopupLocation is called (by AWTEventHelper deep in the LAF) aftergetComponentPopup(). So there's no leeway for a hack like storing the last mouse event which might have triggered the popup and then decide which/if to return popup. And returning null for the location will only result in showing it at the mouse location

这种缺失更加令人讨厌,因为getComponentPopup()之后调用了 getPopupLocation(由 LAF 深处的 AWTEventHelper )。因此,对于像存储可能触发弹出窗口的最后一个鼠标事件,然后决定哪个/是否返回弹出窗口这样的 hack 没有余地。并且为该位置返回 null 只会导致在鼠标位置显示它

The only (dirty) hack (around my utter reluctance to get my hands dirty with a MouseListener ;-) is to override getComponentPopup and decide there whether or not to return it based on current mouse position

唯一的(肮脏的)hack(围绕我完全不愿意用 MouseListener 弄脏我的手;-)是覆盖 getComponentPopup 并根据当前鼠标位置决定是否返回它

    table = new JTable(model) {

        /** 
         * @inherited <p>
         */
        @Override
        public JPopupMenu getComponentPopupMenu() {
            Point p = getMousePosition();
            // mouse over table and valid row
            if (p != null && rowAtPoint(p) >= 0) {
                // condition for showing popup triggered by mouse
                if (isRowSelected(rowAtPoint(p))) {
                    return super.getComponentPopupMenu();
                } else {
                    return null;
                }
            }
            return super.getComponentPopupMenu();
        }

    };

the side-effect is that popup showing isn't triggered by keyboard as long as the mouse is anywhere above the table, which might or not be a problem.

副作用是只要鼠标在桌子上方的任何位置,弹出显示就不会由键盘触发,这可能是也可能不是问题。

回答by Hovercraft Full Of Eels

Are you looking for something like this perhaps?

你在寻找这样的东西吗?

To show popup over selected row(s) only

仅在选定行上显示弹出窗口

  private void maybeShowPopup(MouseEvent e) {
     if (e.isPopupTrigger()) {

        // get row that pointer is over
        int row = table.rowAtPoint(e.getPoint());

        // if pointer is over a selected row, show popup
        if (table.isRowSelected(row)) {
           popup.show(e.getComponent(), e.getX(), e.getY());
        }
     }
  }

Or the converse, to prevent popup from showing over selected rows only:

或者反过来,为了防止弹出窗口只显示在选定的行上:

  private void maybeShowPopup(MouseEvent e) {
     if (e.isPopupTrigger()) {
        int row = table.rowAtPoint(e.getPoint());
        int[] selectedRows = table.getSelectedRows();

        if (!table.isRowSelected(row)) {
           popup.show(e.getComponent(), e.getX(), e.getY());
        }
     }