2011-09-14 22 views
10

如何防止觸發和顯示JPopupMenu僅是Mouse Cursor在選定JTable'Row的JTable與JPopupMenu的

我的問題:如果有另一種方式爲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); 
      } 
     }); 
    } 
} 
觸發
+2

順便說一下,好的SSCCE。 –

+0

呢。不。子類。的。 _view_。對於。 _模型_。原因。 – kleopatra

+0

最適合我的解決方案(也是由kleopatra)在這裏還沒有鏈接:http://stackoverflow.com/a/17316876/411282 –

回答

7

這是一個有趣的問題,因爲它突出在JComponent上缺少api :-)

衆所周知,推薦的popupMenus註冊方法是使用componentPopupMenu屬性。相關API是

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

缺什麼(和實際需要爲這個要求)是

JPopupMenu getComponentPopupMenu(MouseEvent); 

這種缺乏是更加惱人,因爲getPopupLocation被稱爲(由AWTEventHelper深的LAF) getComponentPopup()。因此,存儲最後一個可能觸發彈出窗口的鼠標事件,然後決定哪個/如果返回彈出窗口是沒有餘地的。並且返回空位置只會導致在鼠標位置顯示它

唯一(髒)黑客(圍繞我完全不願意讓我的手弄髒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(); 
     } 

    }; 

副作用是彈出式的表現不被鍵盤,只要鼠標在桌子上方的任何位置觸發,這可能是或不是一個問題返回。

+0

感謝闡述,學習有多容易....hehehe,確定你的帖子是答案,並關閉另一個我的問題,我的+1 – mKorbel

+0

由於使用嵌入JTable的'JScrollPane',我認爲可能還有一個額外的問題。在過去,我記得在單擊任何行之外的時候,在JTable上沒有發生的事件有問題(但在* JScrollPane中,在空白空間中):我必須在JScrollPane本身上監聽事件(或'JViewport'不記得確切)。所以,也許@mKorbel,你也必須考慮(只要JScrollPane高於JTable就會發生這種情況)。 – jfpoilpret

+0

@jfpoilprepret不知道怎麼可能從鼠標到JViewPort消費事件,你能否提供一個關於從JViewPort收集MouseEvent的例子,因爲我認爲這是完全失聰的JComponent :-) – mKorbel

12

您是否在尋找類似的東西?

要顯示彈出在選定行(S)僅

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儘管我有不同的觀點:)。實際上,你是一個簡單快捷的解決方案。 – Heisenbug

+1

+1 - 一旦你已經用isRowSelected(row)替換了所有循環和手動檢查:-) – kleopatra

+1

對不起。我完全錯了。看來,我想做什麼,是不可能的。但@kleopatra,我想知道:單元格渲染器無法處理鼠標事件的原因是否有很好的理由? – Heisenbug