JTable + JPopupMenu + ActionListener = 噩梦
JTable + JPopupMenu + ActionListener = Nightmare
我的主要 class 是一个 window,包含图形组件,其中包括一个 JTable
。
我创建了 public class ContextMenu
,它是 JPopupMenu
的自定义实现,包含多个 JMenuItem
.
我已经在 JTable
上注册了一个 mouseListener,以便在检测到右键单击时显示 ContextMenu
的实例。
问题如下:"How to pass the selected rows to different function according to the chosen JMenuItem
?"
显而易见的答案是在我的 JMenuItem
上设置 ActionListener,但请记住 JTable
与 JPopupMenu
.
在不同的 class/object 中
一些代码片段值一千字。
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);
}
}
不知道我问的是否可行
肮脏的方式:传递引用。
更简洁的方式:通过 M-C-V
构建程序
我的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;
}
}
MouseListener
应该为您的 ContextMenu
收集所有相关信息,将其打包在传输中(内部私有?)class 并在实际 [=13= 之前传递此信息]打开上下文菜单。
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)
);
}
}
我的主要 class 是一个 window,包含图形组件,其中包括一个 JTable
。
我创建了 public class ContextMenu
,它是 JPopupMenu
的自定义实现,包含多个 JMenuItem
.
我已经在 JTable
上注册了一个 mouseListener,以便在检测到右键单击时显示 ContextMenu
的实例。
问题如下:"How to pass the selected rows to different function according to the chosen JMenuItem
?"
显而易见的答案是在我的 JMenuItem
上设置 ActionListener,但请记住 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);
}
}
不知道我问的是否可行
肮脏的方式:传递引用。
更简洁的方式:通过 M-C-V
我的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;
}
}
MouseListener
应该为您的 ContextMenu
收集所有相关信息,将其打包在传输中(内部私有?)class 并在实际 [=13= 之前传递此信息]打开上下文菜单。
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)
);
}
}