Reputation: 2613
I am showing some results in a JTable that consists of 2 columns.
File - Result
I implemented a JPopupMenu which displays a copy entry, and I try to copy the value of the cell, where I right-clicked.
filelistTable.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if(SwingUtilities.isRightMouseButton(e))
{
TablePopupMenu popup = new TablePopupMenu(filelistTable, e.getPoint());
filelistTable.setComponentPopupMenu(popup);
}
}
});
--
public TablePopupMenu(JTable table, Point p) {
this.table = table;
this.p = p;
JMenuItem mntmKopieren = new JMenuItem("Kopieren");
mntmKopieren.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
copyCellToClipboard();
}
});
add(mntmKopieren);
}
public void copyCellToClipboard()
{
int r = table.rowAtPoint(p);
int c = table.columnAtPoint(p);
System.out.println(table.getValueAt(table.convertRowIndexToView(r),
table.convertRowIndexToView(c)));
StringSelection entry = new StringSelection(table.getValueAt(table.convertRowIndexToView(r),
table.convertRowIndexToView(c)).toString());
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents( entry, this );
}
Anyhow, this only works for a small number of tests. Did I do something wrong or something missing? It looks to me, as if the cell will not even get choosen correctly.
Upvotes: 4
Views: 3360
Reputation: 51524
Two thingies are slightly off:
That said: getting cell-coordinate related context is poorly supported. Often, the best bet is to (code snippet below)
Fails if (as should be done in a well-behaved application), the popup could be triggered by keyboard: if that's the case, you'll need to provide some other marker (f.i. the focused cell) to act on.
final String popupLocation = "table.popupLocation";
final JTable table = new JXTable(new AncientSwingTeam()) {
@Override
public Point getPopupLocation(MouseEvent event) {
// event may be null if triggered by keyboard, f.i.
// thanks to @Mad for the heads up!
((JComponent) event.getComponent()).putClientProperty(
popupLocation, event != null ? event.getPoint() : null);
return super.getPopupLocation(event);
}
};
JPopupMenu popup = new JPopupMenu();
Action printLocation = new AbstractAction("print cell") {
@Override
public void actionPerformed(ActionEvent e) {
Point p = (Point) table.getClientProperty(popupLocation);
if (p != null) { // popup triggered by mouse
int row = table.rowAtPoint(p);
int column = table.columnAtPoint(p);
LOG.info("" + table.getValueAt(row, column));
} else { // popup triggered otherwise
// could choose f.i. by leadRow/ColumnSelection
...
}
}
};
popup.add(printLocation);
table.setComponentPopupMenu(popup);
Edit (triggered by Mad's comment):
You should be checking MouseEvent.isPopupTrigger as the trigger point is platform dependent. This does mean you need to monitor mousePressed, mouseReleased and mouseClicked
No, that's not needed (just checked :-): the mechanism that shows the componentPopup in response to a mouseEvent - happens in BasicLookAndFeel.AWTEventHelper - only does so if it is a popupTrigger.
By reading the api doc (should have done yesterday ;-) again, it turns out that the method is called always before showing the componentPopup, that is also if triggered by other means, f.i. keyboard. In that case the event param is null - and the original code would blow. On the bright side, with that guarantee, all the logic of finding the target cell/s could be moved into that method. Didn't try though, so it might not be feasable (f.i. if then the location should be based on the leadRow/ColumnSelection that might not yet be fully handled at that time)
Upvotes: 5