2016-10-07 4 views
1

내 메인 클래스는 JTable을 포함한 그래픽 구성 요소가 포함 된 창입니다.JTable + JPopupMenu + ActionListener = Nightmare

나는 JPopupMenu의 사용자 지정 구현이며 JMenuItem을 여러 개 포함하는 공용 클래스 ContextMenu을 만들었습니다.

JTable에 mouseListener를 등록하여 마우스 오른쪽 버튼을 클릭했을 때 ContextMenu의 인스턴스를 표시했습니다.

문제는 다음과 같습니다. "선택한 행을 선택한 함수를 다른 행으로 전달하는 방법은 JMenuItem입니까?"

확실한 대답은 내 JMenuItem에 ActionListener를 설정하는 것이지만 JTableJPopupMenu과 다른 클래스/객체에 있다는 것을 기억하십시오.

일부 코드 스 니펫은 수천 단어에 해당합니다.

public class Tab implements ITab { 
private ContextMenu contextMenu; 
private JTable table; 
private List<SomeObject> toProcess; 
--- code -- 
private JScrollPane drawScrollTable() { 
     Object columns[] = { 
      "something", 
      "somethingElse" 
     }; 
     Object rows[][] = {}; 
     table = new JTable(new DefaultTableModel(rows, columns)); 
     JScrollPane scrollPane = new JScrollPane(table); 

     table.setSelectionForeground(Color.BLACK); 
     table.addMouseListener(new MouseAdapter() {   
      @Override 
      public void mouseReleased(MouseEvent e) { 
       int selectedRow = table.rowAtPoint(e.getPoint()); 

       if (selectedRow >= 0 && selectedRow < table.getRowCount()) { 
        if (!table.getSelectionModel().isSelectedIndex(selectedRow)) { 
         table.setRowSelectionInterval(selectedRow, selectedRow); 
        } 
       } 

       if (e.isPopupTrigger() && e.getComponent() instanceof JTable) { 
        this.show(e); 
       } 
      } 

      private void show(MouseEvent e){ 
       contextMenu.show(e.getComponent(), e.getX(), e.getY()); 
      } 
     }); 

     return scrollPane; 
    } 
-- code -- 
} 

public class ContextMenu extends JPopupMenu { 
    JMenuItem item; 

    public ContextMenu(IBurpExtenderCallbacks callbacks){ 
     this.item= new JMenuItem("item"); 

     this.item(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) {  
       // Do action involving the selected row, even better if possible action involving the value hold in the column 0 of the selected row and the toProcess private field 
      } 
     }); 

     add(item); 
    } 
} 

내가 물어 보는 것이 가능한지 나는 모른다.

+0

코드 조각을 게시보다 훨씬 더 나은 - 생성하고 유효한 [mcve]을 게시, 즉 정확한 우리를 위해 * 문제를 당신의 *을 보여줍니다 ** 작은 ** 컴파일 가능한 및 실행 가능한 프로그램입니다. 이렇게하면 괜찮은 대답을 얻을 확률이 크게 높아집니다. 모든 코드와 의사 소통은 링크가 아니라 원래의 질문에서 이뤄져야합니다. –

답변

1

MouseListenerContextMenu에 대한 모든 관련 정보를 수집해야 전송에 포장 :

더러운 방법의 내 Minimal, Complete, and Verifiable example MCV

를 통해 프로그램을 구성 (내부 개인을?) 컨텍스트 메뉴를 실제로 실행하기 전에이 정보를 전달해야합니다.

table.addMouseListener(new MouseAdapter() {   
     @Override 
     public void mouseReleased(MouseEvent e) { 
      int selectedRow = table.rowAtPoint(e.getPoint()); 

      if (selectedRow >= 0 && selectedRow < table.getRowCount()) { 
       if (!table.getSelectionModel().isSelectedIndex(selectedRow)) { 
        table.setRowSelectionInterval(selectedRow, selectedRow); 
       } 
      } 

      if (e.isPopupTrigger() && e.getComponent() instanceof JTable) { 
       this.show(e); 
      } 
     } 

     private void show(MouseEvent e){ 
      int clickedRow=table.rowAtPoint(e.getPoint()); 
      int clickedCol=table.columnAtPoint(e.getPoint()); 
      Object data=table.getValueAt(row, i); 

      DataClickedOnTable transportMeThere=new DataClickedOnTable(
       table, data, clickedRow, clickedColumn 
      ); 
      contextMenu.setDataFromTable(transportMeThere); 
      contextMenu.show(e.getComponent(), e.getX(), e.getY()); 
     } 
    }); 
    ///.... 
    ///... 


// Just an example of structure transporting the data 
// Add whatever data members are relevant 
private /* inner */ class DataClickedOnTable { 
    public TestTable source; 
    public Object data; 
    public int row; 
    public int column; 

    public DataClickedOnTable(
    TestTable source, Object data, int row, int col 
    ) { 
    this.source=source; 
    this.data=data; 
    this.col=col; 
    this.row=row; 
    } 
} 
public class ContextMenu extends JPopupMenu { 
    JMenuItem item1; 
    JMenuItem item2; 

    Object dataFromTable; // make it an Integer 

    public ContextMenu(IBurpExtenderCallbacks callbacks){ 
     this.item1 = new JMenuItem("item"); 
     this.item2 = new JMenuItem("item"); 

     this.item1(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) {  
       // You already have the relevant data in the dataFromTable 
       // Do want you need in this context 
      } 
     }); 
     this.item2(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) {  
       // You already have the relevant data in the dataFromTable 
       // Do want you need to do in this context 
      } 
     }); 

     add(item1); 
     add(item2); 
    } 

    void setDataFromTable(DataClickedOnTable data) { 
     this.dataFromTable=data; 
     // filter possible actions based on the received data - some 
     // actions are possible, some won't. 
     // Example: 
     this.item1.setEnabled(null!=data && (data.row % 2)==0); 
     this.item2.setEnabled(
      null!=data 
     && ((data.row % 2)==1 || data.data instanceof Number) 
    ); 

    } 
} 
+1

이 솔루션에 대한 많은 감사의 말씀, 제 문제를 해결하고 프로젝트를 계속 개발할 수있을 것으로 생각합니다. 그러나,'DataClickedOnTable'이 개인 내부 클래스 여야하는 이유를 이해하지 못합니다. 내'Tab' 공용 클래스 또는 내부 클래스'ContextMenu' 공용 클래스의 내부 클래스? –

+0

@ AresS31 "이유는 DataClickedOnTable이 개인 내부 클래스 여야합니다." 단지 제안 이요, 필수는 아닙니다. 그러나 이것은 MouseListener와 ContextMenu (테이블을 지원하는 프레임의 내부 클래스 모두이어야 함) 사이에서만 데이터를 전송하기위한 것이므로 다른 코드에서는 액세스 할 수 없도록하는 것이 좋습니다. .. 알 필요가있다. –

+1

좋습니다, 내 ContextMenu가 내부 클래스가 아닙니다. 공개 클래스로 만들었 기 때문에 제가 질문을 던졌습니다. ContextMenu에 내부 액세스를 할 수 없기 때문에 내부 클래스를 private로 만들었 기 때문입니다. 방금 모든 것을 공개 수업으로 만들었습니다. 나는 일단 프로젝트를 끝내면 그것을 정리할 것이다. 다시 한 번 감사드립니다! –

1

더러운 방식 : 참조를 전달하십시오.
클리너 방법 :

import java.awt.BorderLayout; 
import java.awt.event.*; 

import javax.swing.*; 
import javax.swing.table.DefaultTableModel; 

public class TableTest extends JPanel { 
    private TableClass tableClass = new TableClass(); 

    public TableTest() { 
     setLayout(new BorderLayout()); 
     add(tableClass); 
    } 

    private static void createAndShowGui() { 
     JFrame frame = new JFrame("TableTest"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(new TableTest()); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(() -> createAndShowGui()); 
    } 
} 

class ContextMenu extends JPopupMenu { 
    private JMenuItem item; 
    private TableClass tableClass; // dirty direct reference ***** 

    public ContextMenu(TableClass tableClass){ 
     this.tableClass = tableClass; 
     this.item= new JMenuItem("item"); 

     this.item.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) {  
       int row = tableClass.getSelectedRow(); 
       JTable table = tableClass.getTable(); 
       System.out.println("row: " + row); 
       StringBuilder sb = new StringBuilder("Data: "); 
       for (int i = 0; i < table.getColumnCount(); i++) { 
        sb.append(table.getValueAt(row, i)); 
        if (i != table.getColumnCount() - 1) { 
         sb.append(", "); 
        } 
       } 
       System.out.println(sb); 
      } 
     }); 

     add(item); 
    } 
} 

class TableClass extends JPanel { 
    // ***** passing **this** into the ContextMenu class 
    private ContextMenu contextMenu = new ContextMenu(this); 
    private static final Integer[][] DATA = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; 
    private static final String[] COLUMN_NAMES = {"A", "B", "C"}; 
    private DefaultTableModel model = new DefaultTableModel(DATA, COLUMN_NAMES); 
    private JTable table = new JTable(model); 

    public TableClass() { 
     table.addMouseListener(new MouseAdapter() { 
      @Override 
      public void mouseReleased(MouseEvent e) { 
       int selectedRow = table.rowAtPoint(e.getPoint()); 
       if (selectedRow >= 0 && selectedRow < table.getRowCount()) { 
        if (!table.getSelectionModel().isSelectedIndex(selectedRow)) { 
         table.setRowSelectionInterval(selectedRow, selectedRow); 
        } 
       } 
       if (e.isPopupTrigger() && e.getComponent() instanceof JTable) { 
        showPopUp(e); 
       } 
      } 

      private void showPopUp(MouseEvent e) { 
       contextMenu.show(e.getComponent(), e.getX(), e.getY());     
      } 
     }); 

     setLayout(new BorderLayout()); 
     add(new JScrollPane(table)); 
    } 

    public int getSelectedRow() { 
     return table.getSelectedRow(); 
    } 

    public int getSelectedColumn() { 
     return table.getSelectedColumn(); 
    } 

    public JTable getTable() { 
     return table; 
    } 
}