【问题标题】:JTable with JPopupMenu带有 JPopupMenu 的 JTable
【发布时间】:2011-11-17 10:07:06
【问题描述】:

我如何才能防止触发和显示JPopupMenu 仅当Mouse Cursor 超过选择JTable'Row

我的问题:是否有另一种方式作为 getBounds 从选定行中确定/比较 Mouse 位置...

我的简单 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);
            }
        });
    }
}

【问题讨论】:

  • 做。不是。子类。这。 查看 。为了。 模型。原因。
  • 最适合我的解决方案(也由 kleopatra 提供)尚未在此处链接:stackoverflow.com/a/17316876/411282

标签: java swing jtable onmouseover jpopupmenu


【解决方案1】:

您是否正在寻找类似的东西?

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

  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());
        }
     }
  }

反之亦然,以防止弹出窗口仅显示在选定的行上:

  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());
        }
     }

【讨论】:

  • +1 尽管我的观点不同 :) 。实际上,您的解决方案是一个简单快速的好解决方案。
  • +1 - 一旦你将所有循环和手动检查替换为 isRowSelected(row) :-)
  • 对不起大家。我完全错了。看来我想做的,是不可能的。但是@kleopatra,我想知道:单元格渲染器无法处理鼠标事件这一事实有什么好的理由吗?
  • @Heisenbug - 它们不是容器层次结构的一部分
  • @Hovercraft Full Of Eels 感谢您的帖子直接解决了我的问题,但珍妮特的回答也解决了我的另一个问题,只是 +1
【解决方案2】:

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

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

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

缺少的(以及此要求实际需要的)是

JPopupMenu getComponentPopupMenu(MouseEvent);

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

唯一的(肮脏的)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();
        }

    };

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

【讨论】:

  • 感谢您的详细说明,学习多么容易......呵呵,确定您的帖子是回答并关闭另一个我的问题,我的 +1
  • 我认为,由于使用了嵌入JTableJScrollPane,可能还有一个问题。过去,我记得在单击任何行外部(但 inside JScrollPane,在空白处)时,JTable 上未发生事件时遇到问题:我必须在JScrollPane 本身(或 JViewport 记不清了)。所以也许@mKorbel,您还必须考虑这一点(只要JScrollPane 高于JTable,就会发生这种情况)。
  • @jfpoilpret 不知道如何使用从 Mouse 到 JViewPort 的事件,您能否提供一个关于从/到 JViewPort 使用 MouseEvents 的示例,因为我认为这是完全聋的 JComponent :-)跨度>
  • @jfpoilpret hmm ...不太明白你的意思是什么问题:你可以根据需要调整 if-show-what 的逻辑。如今,无论如何,所有表格都配置为适合视口高度(SwingX 默认情况下会这样做,没有人抱怨 - 这本身就是一个相当显着的事实,因为大多数都是天生抱怨的类型:-)
  • @kleopatra 您可以为JTable 设置最小可见行数,以便它适合您想要的表单布局。但是,有时实际表格内容小于这个最小值,然后表格下方出现一个空白区域,位于JScrollPane 边界内;这个空白空间不属于JTable,但您可能需要它来显示弹出窗口(例如,带有“创建新行...”项的弹出窗口)。请注意,我已经提到我不记得是否必须将 Mouselistener 添加到 JScrollPaneJViewport,但除了 JTable 本身之外,我还需要将其添加到其他位置。
猜你喜欢
  • 2017-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-13
相关资源
最近更新 更多