我正在尝试用 Java 实现 GUI。 我将 JPopupMenu 绑定到 JTable。在 JTable 上单击鼠标右键,JPopupMenu 变得可见。
我设法阻止在 JTable 上单击鼠标左键。 我无法阻止鼠标左键单击 JPopupMenu 的任何项目。 事实上,每个 JMenuItem 都绑定到一个 ActionListener,其 actionPerformed 无法访问鼠标按钮。 我可以将 MouseListener 与 JMenuItem 关联起来吗? 如果这是不可能的,那么我怎样才能让 JPopupMenu 仅监听鼠标右键单击?
我的目标是为与 JPopupMenu 无关的其他任务保留 JTable 上的鼠标左键单击。 我想我需要将 JTable 绑定到另一个监听器。 同一个组件(JTable)可以与两个不同的监听器关联吗?
提前谢谢您。
下面我粘贴我的代码
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.border.EmptyBorder;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import javax.swing.border.EtchedBorder;
import java.awt.Color;
import java.awt.Font;
import java.awt.Dimension;
import java.awt.Point;
import javax.swing.UIManager;
import java.awt.Rectangle;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.JTextField;
import javax.swing.JTextArea;
import javax.swing.border.SoftBevelBorder;
import javax.swing.border.BevelBorder;
import javax.swing.JScrollPane;
import javax.swing.JList;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.AbstractListModel;
import javax.swing.DefaultListModel;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Component;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
//--------- Define ActionListener
class PopupActionListener implements ActionListener
{
public void actionPerformed(ActionEvent actionEvent) {
System.out.println("Selected: " + actionEvent.getActionCommand());
}
}
public class MyNewGUI extends JFrame
{
// INSTANCE VARIABLE/COMPONENTS
private JPanel ctpMain;
private JTextField txtNewPoint;
private JLabel lblNewPoint;
private JButton btnNewPoint;
private JButton btnDeleteAll;
private JButton btnDeleteUnused;
private JScrollPane scrPoints;
private JButton btnExit;
DefaultTableModel pointsTableModel = new DefaultTableModel ();
JTable tblPoints = new JTable(pointsTableModel);
JPopupMenu popupMenu = new JPopupMenu();
JMenuItem menuItemAddBefore;
JMenuItem menuItemAddAfter;
JMenuItem menuItemRemove;
JMenuItem menuItemRename;
/**************************** Launch the application *********************************************/
public static void main(String[] args)
{
try
{
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
} catch (Throwable e)
{
e.printStackTrace();
}
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
MyNewGUI frame = new MyNewGUI();
frame.setVisible(true);
} catch (Exception e)
{
e.printStackTrace();
}
}
});
}
//************************** JFrame Class Constructor --> Create the frame *************************** */
public MyNewGUI()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(new Rectangle(10, 10, 100, 100));
setMinimumSize(new Dimension(100, 100));
setFont(new Font("Arial", Font.BOLD, 16));
setBounds(1050,200,800,800);
setTitle("MyNewGUI");
initComponents();
btnExit = new JButton("Exit GUI");
btnExit.setFont(new Font("Arial", Font.BOLD, 16));
btnExit.setBounds(14, 254, 101, 26);
ctpMain.add(btnExit);
setVisible(true);
createEvents();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This method contains all of the code for creating and initializing components
/////////////////////////////////////////////////////////////////////////////////////////////////////////
private void initComponents()
{
setTitle("MyGUI");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 1041, 779);
ctpMain = new JPanel();
ctpMain.setBounds(new Rectangle(5, 5, 0, 0));
ctpMain.setAlignmentY(5.0f);
ctpMain.setAlignmentX(5.0f);
ctpMain.setSize(new Dimension(10, 10));
ctpMain.setPreferredSize(new Dimension(100, 100));
ctpMain.setLocation(new Point(10, 10));
ctpMain.setFont(new Font("Arial", Font.BOLD, 16));
ctpMain.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
setContentPane(ctpMain);
btnNewPoint = new JButton("Add New Point");
btnNewPoint.setBounds(14, 55, 167, 29);
btnNewPoint.setFont(new Font("Arial", Font.BOLD, 16));
txtNewPoint = new JTextField();
txtNewPoint.setBounds(162, 14, 144, 29);
txtNewPoint.setFont(new Font("Arial", Font.BOLD, 16));
txtNewPoint.setColumns(10);
lblNewPoint = new JLabel(" Point Identifier");
lblNewPoint.setLocation(new Point(14, 19));
lblNewPoint.setSize(new Dimension(136, 19));
lblNewPoint.setDisplayedMnemonicIndex(1);
lblNewPoint.setAutoscrolls(true);
lblNewPoint.setFont(new Font("Arial", Font.BOLD, 16));
JTextArea textArea = new JTextArea();
textArea.setBounds(179, 197, 1, 16);
textArea.setText("");
JPanel pnPoints = new JPanel();
pnPoints.setBounds(321, 21, 211, 668);
pnPoints.setFont(new Font("Arial", Font.BOLD, 24));
pnPoints.setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null), "", TitledBorder.CENTER, TitledBorder.TOP, null, new Color(64, 0, 64)));
ctpMain.setLayout(null);
ctpMain.add(btnNewPoint);
ctpMain.add(txtNewPoint);
ctpMain.add(lblNewPoint);
ctpMain.add(textArea);
ctpMain.add(pnPoints);
pnPoints.setLayout(null);
scrPoints = new JScrollPane();
scrPoints.setBounds(0, 0, 206, 668);
pnPoints.add(scrPoints);
// --------- Initialize JTable Model with points fromCliff's code
pointsTableModel.addColumn("Point Names");
pointsTableModel.insertRow(0, new Object[] { "ONE" });
pointsTableModel.insertRow(0, new Object[] { "TWO" });
pointsTableModel.insertRow(0, new Object[] { "THREE" });
scrPoints.setViewportView(tblPoints);
tblPoints.setFocusable(true);
tblPoints.setRowSelectionAllowed(true);
tblPoints.setVisible(true);
// --------- Initialize popupMenu with items ---
PopupListener myListener = new PopupListener();
menuItemAddBefore = new JMenuItem("Add Point Before");
// menuItemAddBefore.addMouseListener(myListener);
menuItemAddAfter = new JMenuItem("Add Point After");
// menuItemAddAfter.addMouseListener(myListener);
menuItemRemove = new JMenuItem("Remove Current Point");
// menuItemRemove.addMouseListener(myListener);
menuItemRename = new JMenuItem("Rename Current Point");
// menuItemRename.addMouseListener(myListener);
popupMenu.add(menuItemAddBefore);
popupMenu.add(menuItemAddAfter);
popupMenu.add(menuItemRemove);
popupMenu.add(menuItemRename);
// --------- Set popupMenu to tblPoints
tblPoints.setComponentPopupMenu(popupMenu);
tblPoints.addMouseListener(myListener);
// tblPoints.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
btnDeleteAll = new JButton("Delete All Points");
btnDeleteAll.setFont(new Font("Arial", Font.BOLD, 16));
btnDeleteAll.setBounds(14, 192, 167, 26);
ctpMain.add(btnDeleteAll);
btnDeleteUnused = new JButton("Delete Unused Points");
btnDeleteUnused.setFont(new Font("Arial", Font.BOLD, 16));
btnDeleteUnused.setBounds(14, 126, 205, 26);
ctpMain.add(btnDeleteUnused);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This method contains all of the code for creating events
/////////////////////////////////////////////////////////////////////////////////////////////////////////
private void createEvents()
{
//-------- Append Point To Point Names List ------------------------------------------------------------
btnNewPoint.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
String newPoint = txtNewPoint.getText();
pointsTableModel.addRow(new Object[] {newPoint});
txtNewPoint.setText("");
}
});
//-------- Remove Unused Points From Point Names List ---------------------------------------------------
btnDeleteUnused.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
// TO BE DEVELOPED
}
});
//-------- Empty Point Names List --------------------------------------------------------------------------
btnDeleteAll.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
while (pointsTableModel.getRowCount() > 0)
pointsTableModel.removeRow(0);
}
});
//--------------- Button EXIT Handler --------------------------------------------------------------------------------------------------------------------
btnExit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
Object[] options = {"Exit Without Saving", "Exit With Saving","Cancel"}; //Custom button text
int sel = JOptionPane.showOptionDialog(null ,
"Would you like to save your work before exiting ? ",
"EXIT WORK SESSION",
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[2]);
// Process Customer's Selection
if (sel == 0)
{
JOptionPane.showMessageDialog(null, "You chose to exit your work session without saving!");
System.exit(0);
}
if(sel == 1)
{
JOptionPane.showMessageDialog(null, "You chose to save your work session before exiting !");
// if(lstPoints != null && !pointsTableModel.isEmpty()) // If JList contains Points
// {
// pointsList.clear(); // Empty Points storage
// System.out.print("\n pointsList after clear(): " + pointsList); // DEBUG-PURPOSE
// System.out.print("\n pointsTableModel : " + pointsTableModel); // DEBUG-PURPOSE
// System.out.print("\n pointsTableModel size: " + pointsTableModel.size() ); // DEBUG-PURPOSE
// System.out.print("\n");
// for(int i=0; i < pointsTableModel.size(); i++)
// pointsList.add(pointsTableModel.get(i)); // Move Points from JList to Points storage
// System.out.print("Saved Points: " + pointsList + "\n");
// }else
// JOptionPane.showMessageDialog(null, "Your Ponts List is empty!");
// System.exit(0);
}
if(sel == 2)
JOptionPane.showMessageDialog(null, "You changed your mind !");
}
});
//--------------- JMenuItem Handler To Add Item Before Selected JTable Row-------------------------------------------------------------------------------------------------------
menuItemAddBefore.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ev)
{
int row = tblPoints.getSelectedRow();
if (row == -1)
return;
System.out.print("Add Point to tblPoints Before Row: " + row + "\n");
String precedingPointName = JOptionPane.showInputDialog("Enter Following Point Name");
System.out.println(precedingPointName);
pointsTableModel.insertRow(row, new Object[] {precedingPointName});
tblPoints.getSelectionModel().clearSelection();
}
});
//--------------- JMenuItem Handler To Add Item After Selected JTable Row-------------------------------------------------------------------------------------------------------
menuItemAddAfter.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ev)
{
int row = tblPoints.getSelectedRow();
if (row == -1 || !tblPoints.isCellEditable(row,0))
return;
String value = tblPoints.getValueAt(row, 0).toString();
System.out.print("Add Point to tblPoints After PointName: " + value + " On Row: " + row + "\n");
String followingPointName = JOptionPane.showInputDialog("Enter Following Point Name");
System.out.println(followingPointName);
pointsTableModel.insertRow(row +1, new Object[] {followingPointName});
tblPoints.getSelectionModel().clearSelection();
}
});
//--------------- JMenuItem Handler To Remove Selected JTable Row----------------------------------------------------------------------------------------------------------------
menuItemRemove.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ev)
{
int row = tblPoints.getSelectedRow();
if (row == -1)
return;
System.out.print("Remove Point at tblPoints rown: " + row + "\n");
pointsTableModel.removeRow(tblPoints.getSelectedRow());
tblPoints.getSelectionModel().clearSelection();
}
});
//--------------- JMenuItem Handler To Rename Item At Selected JTable Row----------------------------------------------------------------------------------------------------------------
menuItemRename.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ev)
{
int row = tblPoints.getSelectedRow();
if (row == -1)
return;
System.out.print("Rename Point at tblPoints rown: " + row + "\n");
String replacingPointName = JOptionPane.showInputDialog("Enter Current Point Replacing Name");
tblPoints.getModel().setValueAt(replacingPointName, row, 0);
tblPoints.getSelectionModel().clearSelection();
}
});
} //----------------------------------- End Of createEvents() Method ----------------------------------------------------------------------
// ********* Inner classes *********
public class PopupListener extends MouseAdapter
{
public PopupListener() // Default Constructor
{
System.out.print("\n Default PopupListener Constructor engaged \n ");
}
public void mousePressed(MouseEvent e)
{
if(e.getButton() == MouseEvent.BUTTON3)
{
Point p = e.getPoint();
Component c = e.getComponent();
int row = tblPoints.rowAtPoint(p);
System.out.print("\n `Selected row: " + row + "\n");
if (row == -1)
{
tblPoints.getSelectionModel().clearSelection();
return;
}
else
tblPoints.setRowSelectionInterval(row, row);
}
else
tblPoints.getSelectionModel().clearSelection();
}
}
}
在显示弹出菜单之前,如果鼠标指针下方的行尚未选择,您似乎需要右键单击以选择表格行。
为此,您应该删除
tblPoints.setComponentPopupMenu(popupMenu);
并使用您自己的 MouseListener 和键映射自行显示 JPopupMenu。通常,setComponentPopupMenu 会处理所有这些,但您需要自定义该行为。
MouseListener mousePopupListener = new MouseAdapter() {
@Override
public void mousePressed(MouseEvent event) {
showPopup(event);
}
@Override
public void mouseReleased(MouseEvent event) {
showPopup(event);
}
@Override
public void mouseClicked(MouseEvent event) {
showPopup(event);
}
private void showPopup(MouseEvent event) {
int row = tblPoints.rowAtPoint(event.getPoint());
if (row >= 0 && !tblPoints.isRowSelected(row)) {
tblPoints.setRowSelectionInterval(row, row);
}
if (popupMenu.isPopupTrigger(event)) {
popupMenu.show(tblPoints, event.getX(), event.getY());
}
}
};
tblPoints.addMouseListener(mousePopupListener);
响应鼠标按下、鼠标松开和鼠标单击事件至关重要,因为不同的平台对于弹出菜单有不同的行为。
但是……这还不够。 Swing 应用程序需要“可访问”,这意味着它们需要支持使用键盘来激活控件。 (例如,用户可以按 Tab 键选择某个按钮,然后按空格键来“按下”该按钮。)在大多数平台上,可以使用 PC 键盘上的菜单键(通常带有“🗉”符号)来激活弹出菜单, Java 表示为 KeyEvent.VK_CONTEXT_MENU,以及 Shift-F10。
String actionName = "showPopup";
Action keyboardMenuDisplayer = new AbstractAction(actionName) {
private static final long serialVersionUID = 1;
@Override
public void actionPerformed(ActionEvent event) {
Point location;
PointerInfo info = MouseInfo.getPointerInfo();
if (info != null) {
location = info.getLocation();
SwingUtilities.convertPointFromScreen(location, tblPoints);
} else {
int focusedRow =
tblPoints.getSelectionModel().getLeadSelectionIndex();
int focusedColumn =
tblPoints.getColumnModel().getSelectionModel().getLeadSelectionIndex();
if (focusedRow >= 0 && focusedColumn >= 0) {
Rectangle cell =
tblPoints.getCellRect(focusedRow, focusedColumn, false);
location = cell.getLocation();
} else {
location = new Point();
}
}
popupMenu.show(tblPoints, location.x, location.y);
}
};
tblPoints.getActionMap().put(actionName, keyboardMenuDisplayer);
InputMap inputMap = tblPoints.getInputMap(JComponent.WHEN_FOCUSED);
inputMap.put(KeyStroke.getKeyStroke("CONTEXT_MENU"), actionName);
inputMap.put(KeyStroke.getKeyStroke("shift F10"), actionName);