Java 在JTable中禁用拖动选择

Java 在JTable中禁用拖动选择,java,swing,drag-and-drop,jtable,Java,Swing,Drag And Drop,Jtable,问题 我想单击JTable中未选中的单元格并拖动它,I。E表格应处于拖动模式。问题在于JTable有一种机制,当你点击一个未选中的单元格并拖动时,你实际上并没有处于拖动模式,而是处于选择模式。选择模式只能通过单击来实现,并且可以通过按住shift键并单击来扩展,而不能通过拖动来扩展 据我所知,罪魁祸首在BasicTableUI,但不幸的是,那里所有相关的东西都是私人的 问题 如何防止通过拖动进行选择,并在单击未选中的单元格并拖动它时立即处于拖动模式 我搜索了一下,但没有一个解决方案是令人满意的。

问题

我想单击JTable中未选中的单元格并拖动它,I。E表格应处于拖动模式。问题在于JTable有一种机制,当你点击一个未选中的单元格并拖动时,你实际上并没有处于拖动模式,而是处于选择模式。选择模式只能通过单击来实现,并且可以通过按住shift键并单击来扩展,而不能通过拖动来扩展

据我所知,罪魁祸首在BasicTableUI,但不幸的是,那里所有相关的东西都是私人的

问题

如何防止通过拖动进行选择,并在单击未选中的单元格并拖动它时立即处于拖动模式

我搜索了一下,但没有一个解决方案是令人满意的。或者,它们适用于较旧的Java版本

代码

以下是一些复制代码:

  • 单击未选中的单元格并拖动鼠标。将选择这些单元格
  • 单击选定的单元格并拖动。表格处于拖动模式
守则:

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);
    });
  }
}