2016-10-07 3 views
1

Мой главный класс - это окно, содержащее графические компоненты, включая JTable.JTable + JPopupMenu + ActionListener = Nightmare

Я создал публичный класс ContextMenu, который является специальной реализацией JPopupMenu и содержит несколько JMenuItem.

Я зарегистрировал mouseListener на своем JTable, чтобы показать экземпляр ContextMenu, когда обнаружен щелчок правой кнопкой мыши.

Проблема заключается в следующем: «Как передать выбранные строки в разные функции в соответствии с выбранными JMenuItem

Очевидным ответом было бы установить ActionListener на моем JMenuItem, но помните, что JTable находится в другом классе/объекте, чем JPopupMenu.

Некоторые снайперы кода стоят тысячи слов.

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

MouseListener должен собрать всю необходимую информацию для вашего ContextMenu, упаковать его в транспорте (внутренний частным?) класса и передать эту информацию до фактического show в контекстном меню.

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 (который должен быть как внутренними классами фрейма, поддерживающим вашу таблицу), это хорошая практика не сделать его доступным для другого кода, который не ... ummm. .. надо знать. –

+1

Хорошо, я вижу, что мой ContextMenu не является внутренним классом, я сделал его публичным классом, поэтому я задал этот вопрос, потому что когда я сделал его частным внутренним, ContextMenu не имел доступа к нему. Я просто сделал все публичным классом. Я очищу это после завершения проекта. Еще раз спасибо! –

1

Грязный способ: передать ссылки.
уборщик путь: структурировать вашу программу с помощью MCV

Моих Minimal, Complete, and Verifiable example грязных образом:

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; 
    } 
} 
Смежные вопросы