JTable与JPopupMenu

我怎样才能防止触发和显示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); } }); } } 

这是一个有趣的问题,因为它突出显示了JComponent上缺less的api 🙂

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

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

什么是缺失(实际上需要这个要求)是

 JPopupMenu getComponentPopupMenu(MouseEvent); 

getComponentPopup() 之后调用getPopupLocation(由LAF深处的AWTEventHelper) 这个缺点更加恼人。 因此,存储最后一个可能触发popup窗口的鼠标事件,然后决定是否返回popup窗口是没有余地的。 并返回null的位置只会导致显示在鼠标位置

唯一的(肮脏的)黑客(围绕我完全不情愿让我的手弄脏一个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(); } }; 

副作用是只要鼠标位于桌子上方的任何位置,popup式显示不会被键盘触发,这可能或不是问题。

你是否正在寻找这样的事情?

仅显示选定行的popup窗口

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

或者相反,为了防止popup窗口只显示选定的行:

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