我正在尝试右键单击JPopupMenu
时显示JTable
。
我已经以不同的方式实现了这一点,但是没有一个允许我做这个问题:在我右键单击表后执行一些代码,但是弹出菜单在屏幕上。
当显示弹出菜单并在其外部右键单击时,它会在另一个位置再次打开。所以必须有一个内部的听众告诉它这样做,但我无法找到它。理想情况下,我会@Override
它并执行我在右键单击JTable时执行的相同代码。
因此,总结一下这个问题,当菜单仍然具有焦点(或正在显示)时,如果我在菜单外部(或者在表格单元格上)右键单击,如何触发某些代码?
编辑:仔细观察后,我发现了问题,但没有找到解决方案。 JPopupMenu
不是问题,而是UIManager
。以下是我的测试表单的代码,它显示了我描述的问题:
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import javax.swing.UnsupportedLookAndFeelException;
public class PopupTesting extends javax.swing.JFrame {
public PopupTesting() {
initComponents();
}
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
jTable1 = new javax.swing.JTable();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jTable1.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
{null, null, null, null},
{null, null, null, null},
{null, null, null, null},
{null, null, null, null}
},
new String [] {
"Title 1", "Title 2", "Title 3", "Title 4"
}
));
jTable1.addMouseListener(new java.awt.event.MouseAdapter() {
@Override
public void mousePressed(java.awt.event.MouseEvent evt) {
jTable1MousePressed(evt);
}
});
jScrollPane1.setViewportView(jTable1);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(61, 61, 61)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(83, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(69, 69, 69)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 267, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(121, Short.MAX_VALUE))
);
pack();
}
private void jTable1MousePressed(java.awt.event.MouseEvent evt) {
if (SwingUtilities.isRightMouseButton(evt)) {
jTable1.setRowSelectionInterval(jTable1.rowAtPoint(evt.getPoint()), jTable1.rowAtPoint(evt.getPoint()));
getPopup().show(jTable1, evt.getX(), evt.getY());
}
}
public static void main(String args[]) {
try {
javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
Logger.getLogger(PopupTesting.class.getName()).log(Level.SEVERE, null, ex);
}
java.awt.EventQueue.invokeLater(() -> {
new PopupTesting().setVisible(true);
});
}
private JPopupMenu getPopup() {
if (jTable1.getSelectedRow() > -1) {
JPopupMenu popup = new JPopupMenu();
MouseListener listener = (new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
System.out.println("I'm a menu Item.");
}
});
JMenuItem m = new JMenuItem("Regular Menu Item");
m.addMouseListener(listener);
popup.add(m);
return popup;
} return null;
}
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTable jTable1;
}
如果删除该行:
javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());
以及周围的try
和catch
,它完美无缺。
答案 0 :(得分:1)
或在表格之上
表头不是表的一部分,因此它不会响应鼠标事件。您需要向表头添加一个单独的侦听器。
当您点击其他地方并且菜单在屏幕上时,它会关闭并触发您尝试点击的点击事件
如果单击表格的单元格,则在Windows 7上使用JDK8可以正常工作。
如果您仍然遇到问题,请发布一个显示问题的SSCCE。
编辑:
正如MadProgrammer在评论中所建议的那样,应该使用setComponentPoupMenu(...)
方法。这是一个较新的API。我不知道这两种方法之间有什么区别,但使用这种方法对我来说都适用于我测试过的LAF。
EDIT2:
它再一次对我来说仍然很好。请注意,您不应将MouseListener添加到菜单项。您使用ActionListener来处理菜单项的单击:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TableRightClick extends JFrame implements ActionListener
{
JPopupMenu popup;
public TableRightClick()
{
popup = new JPopupMenu();
popup.add( new JMenuItem("Do Something1") );
JMenuItem menuItem = new JMenuItem("ActionPerformed");
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, ActionEvent.ALT_MASK));
menuItem.addActionListener( this );
popup.add( menuItem );
JTable table = new JTable(10, 5);
table.addMouseListener( new MouseAdapter()
{
public void mousePressed(MouseEvent e)
{
JTable source = (JTable)e.getSource();
int row = source.rowAtPoint( e.getPoint() );
int column = source.columnAtPoint( e.getPoint() );
if (! source.isRowSelected(row))
source.changeSelection(row, column, false, false);
}
});
table.setComponentPopupMenu( popup );
table.setPreferredScrollableViewportSize(table.getPreferredSize());
getContentPane().add( new JScrollPane(table) );
JMenuBar menuBar = new JMenuBar();
setJMenuBar( menuBar );
menuBar.add( popup );
}
public void actionPerformed(ActionEvent e)
{
Component c = (Component)e.getSource();
JPopupMenu popup = (JPopupMenu)c.getParent();
JTable table = (JTable)popup.getInvoker();
System.out.println(table.getSelectedRow() + " : " + table.getSelectedColumn());
}
public static void main(String[] args)
{
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (Exception ex) { System.out.println(ex); }
TableRightClick frame = new TableRightClick();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
}
答案 1 :(得分:1)
好吧,经过几个小时的尝试解决问题,我最终做了一个狡猾的修复。执行我要求的代码在这里:
import java.awt.AWTException;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
public class PopupTesting extends javax.swing.JFrame {
public PopupTesting() {
initComponents();
jTable.setComponentPopupMenu(getPopup());
}
volatile int lastMouse = 1;
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
jTable = new javax.swing.JTable();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jTable.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
{null, null, null, null},
{null, null, null, null},
{null, null, null, null},
{null, null, null, null}
},
new String [] {
"Title 1", "Title 2", "Title 3", "Title 4"
}
));
jTable.addMouseListener(new java.awt.event.MouseAdapter() {
@Override
public void mousePressed(java.awt.event.MouseEvent evt) {
jTableMousePressed(evt);
}
});
jScrollPane1.setViewportView(jTable);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(61, 61, 61)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(83, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(69, 69, 69)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 267, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(121, Short.MAX_VALUE))
);
pack();
}
private void jTableMousePressed(java.awt.event.MouseEvent evt) {
lastMouse = evt.getButton();
if (lastMouse == 3) lastMouse--;
lastMouse = InputEvent.getMaskForButton(lastMouse);
}
public static void main(String args[]) {
try {
javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
Logger.getLogger(PopupTesting.class.getName()).log(Level.SEVERE, null, ex);
}
java.awt.EventQueue.invokeLater(() -> {
new PopupTesting().setVisible(true);
});
}
private JPopupMenu getPopup() {
JPopupMenu popup = new JPopupMenu();
JMenuItem m = new JMenuItem("Regular Menu Item");
m.addActionListener((ActionEvent e) -> {
System.out.println("I'm a menu Item.");
});
popup.add(m);
PopupTesting frame = this;
popup.addAncestorListener( new AncestorListener() {
@Override
public void ancestorAdded(AncestorEvent event) {
Point mousePoint = MouseInfo.getPointerInfo().getLocation();
mousePoint = SwingUtilities.convertPoint(frame, parseInt(mousePoint.getX() - getX()), parseInt(mousePoint.getY() - getY()), jTable);
jTable.setRowSelectionInterval(jTable.rowAtPoint(mousePoint), jTable.rowAtPoint(mousePoint));
}
@Override public void ancestorRemoved(AncestorEvent event) {
try {
Robot bot = new Robot();
bot.mousePress(lastMouse);
bot.mouseRelease(lastMouse);
} catch (AWTException ex) {
Logger.getLogger(PopupTesting.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override public void ancestorMoved(AncestorEvent event) {}
});
return popup;
}
private int parseInt(Double val) {
return val.intValue();
}
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTable jTable;
}
尽管setComponentPopupMenu()
在仍然可见时再次显示弹出窗口,但它仍然不会触发MouseListener
。
我“修复”它的方式是使用AncestorListener
,在显示弹出菜单时触发ancestorAdded
,并在退出屏幕时触发ancestorRemoved
。
使用ancestorAdded
,我只是这样做,以便每当菜单显示时,它也会选择它背后的单元格(花了很多时间来弄清楚如何从{{1}获得相同的位置我可以从MouseInfo
得到,但我到了那里。
MouseEvent
,我不得不“欺骗”。基本上,每次我在桌面上点击(ancestorRemoved
)时,我都会存储用于执行此操作的按钮。
然后,一旦MousePressed
被触发,它就会创建一个ancestorRemoved
,重复最后一次鼠标点击(如果是鼠标1则触发鼠标1,鼠标2触发鼠标2等)。
此解决方案有效,但在退出Robot
时不允许我按住鼠标按钮。如果有人相信知道解决方案,请告诉我,但现在问题已经解决了。