Java 在JTable中禁用拖动选择
问题 我想单击JTable中未选中的单元格并拖动它,I。E表格应处于拖动模式。问题在于JTable有一种机制,当你点击一个未选中的单元格并拖动时,你实际上并没有处于拖动模式,而是处于选择模式。选择模式只能通过单击来实现,并且可以通过按住shift键并单击来扩展,而不能通过拖动来扩展 据我所知,罪魁祸首在BasicTableUI,但不幸的是,那里所有相关的东西都是私人的 问题 如何防止通过拖动进行选择,并在单击未选中的单元格并拖动它时立即处于拖动模式 我搜索了一下,但没有一个解决方案是令人满意的。或者,它们适用于较旧的Java版本 代码 以下是一些复制代码:Java 在JTable中禁用拖动选择,java,swing,drag-and-drop,jtable,Java,Swing,Drag And Drop,Jtable,问题 我想单击JTable中未选中的单元格并拖动它,I。E表格应处于拖动模式。问题在于JTable有一种机制,当你点击一个未选中的单元格并拖动时,你实际上并没有处于拖动模式,而是处于选择模式。选择模式只能通过单击来实现,并且可以通过按住shift键并单击来扩展,而不能通过拖动来扩展 据我所知,罪魁祸首在BasicTableUI,但不幸的是,那里所有相关的东西都是私人的 问题 如何防止通过拖动进行选择,并在单击未选中的单元格并拖动它时立即处于拖动模式 我搜索了一下,但没有一个解决方案是令人满意的。
- 单击未选中的单元格并拖动鼠标。将选择这些单元格
- 单击选定的单元格并拖动。表格处于拖动模式
import java.awt.BorderLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.DropMode;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class Main {
public static void main(String args[]) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE);
Object rowData[][] = {
{ "a", "a", "a" },
{ "a", "a", "a" },
{ "a", "a", "a" },
{ "a", "a", "a" },
{ "a", "a", "a" },
};
Object columnNames[] = { "Column 1", "Column 2", "Column 3" };
final JTable table = new JTable( rowData, columnNames);
table.setDragEnabled( true);
table.setDropMode( DropMode.INSERT_ROWS);
table.addMouseMotionListener( new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
boolean selectionIsAdjusting = table.getSelectionModel().getValueIsAdjusting();
if( selectionIsAdjusting) {
System.out.println("selecting");
} else {
System.out.println("dragging");
}
}
});
table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
table.setColumnSelectionAllowed(true);
table.setRowSelectionAllowed(true);
JScrollPane scrollPane = new JScrollPane( table);
frame.add( scrollPane, BorderLayout.CENTER);
frame.setSize( 300, 150);
frame.setVisible( true);
}
}
截图:
非常感谢你的帮助
选择模式只能通过单击来实现,并且可以通过按住shift键并单击来扩展,而不能通过拖动来扩展
您可以通过使用一些附加逻辑重写JTable的processMouseeEvent
方法来改变行为。当按钮按下事件发生时-且shift未按下-在调用父方法之前,将JTable的选择更改为当前单击的行
JTable table = new JTable( rowData, columnNames){
@Override
public void processMouseEvent(MouseEvent e){
Component c = (Component)e.getSource();
if (e.getModifiersEx() == MouseEvent.BUTTON1_DOWN_MASK && ( e.getModifiers() & MouseEvent.SHIFT_DOWN_MASK) == 0 ){
int row = rowAtPoint(e.getPoint());
int col = columnAtPoint(e.getPoint());
if ( !isCellSelected(row, col) ){
clearSelection();
changeSelection(row, col, false, false);
}
}
MouseEvent e1 = new MouseEvent(c, e.getID(), e.getWhen(),
e.getModifiers() | InputEvent.CTRL_MASK,
e.getX(), e.getY(),
e.getClickCount(),
e.isPopupTrigger() ,
e.getButton());
super.processMouseEvent(e1);
}
};
您可以直接调用
MouseMotionListener#mouseDragged(…)
中的方法:
当你点击一个空单元格并拖动它时?
你的意思是空的,没有内容单元格(例如区分空字符串和其他),还是只拖动任何单元格?发布的代码不包含“空”单元格。哦,你说得对,我已经修复了它。这是一个未选中的单元格。我想单击一个未选中的单元格并将其拖动。如果您还更新了问题的第二句话,这将非常有用。@VGR:您的意思是什么?您的问题中至少有两个地方使用了“空单元格”一词。如果您指的是未选中的单元格,如果您将措辞更改为“未选择的单元格。”谢谢,但这并不是在所有情况下都有效。例如,如果您处于单单元格选择模式,则不起作用。我使用单单元格选择模式更新了示例。我看到了覆盖ProcessMouseeEvent的解决方案。我还没有找到一个能令人满意的解决方案。@Roland,可能没有一个比在选择模式基础…所说的控件启动拖动移动应该具有优先权。因此,您可以根据需要更改选择,然后传递带有控件掩码的MouseEvent(请参阅编辑-注意,我没有对所有选择模式进行测试)。非常感谢您的努力。但现在单个单元格的选择已不存在。当我单击单元格时,它只会获得焦点边框。我将玩弄您的解决方案。但正如我所说,我以前见过该解决方案。我不喜欢的是隐式调用某些侦听器的选择的更改。我正在搜索更多内容没有副作用的正确方法。
import java.awt.*;
import java.awt.event.*;
import java.util.Optional;
import javax.swing.*;
import javax.swing.table.*;
public class Main2 {
public JComponent makeUI() {
Object columnNames[] = {"Column 1", "Column 2", "Column 3"};
Object data[][] = {
{ "a", "a", "a" },
{ "a", "a", "a" },
{ "a", "a", "a" },
{ "a", "a", "a" },
{ "a", "a", "a" },
};
JTable table = new JTable(new DefaultTableModel(data, columnNames));
table.setDragEnabled(true);
table.setDropMode(DropMode.INSERT_ROWS);
table.addMouseMotionListener(new MouseAdapter() {
@Override public void mouseDragged(MouseEvent e) {
JComponent c = (JComponent) e.getComponent();
Optional.ofNullable(c.getTransferHandler())
.ifPresent(th -> th.exportAsDrag(c, e, TransferHandler.COPY));
}
});
table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
table.setColumnSelectionAllowed(true);
table.setRowSelectionAllowed(true);
JPanel p = new JPanel(new BorderLayout());
p.add(new JScrollPane(table));
p.add(new JTextField(), BorderLayout.SOUTH);
return p;
}
public static void main(String... args) {
EventQueue.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new Main2().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}