【问题标题】:Disable drag selection in JTable在 JTable 中禁用拖动选择
【发布时间】:2016-06-28 15:05:38
【问题描述】:

问题

我想单击 JTable 中未选择的单元格并将其拖动,即。 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);

  }
}

截图:

非常感谢您的帮助!

【问题讨论】:

  • when you click on an empty cell and drag it? 你的意思是空的,没有内容的单元格(例如区分空字符串和其他),或者只是拖动任何单元格?发布的代码不包含“空”单元格。
  • 哦,你说得对,我修好了。这是一个未选中的单元格。我想点击一个未选中的单元格并拖动它。
  • 如果您也更新了问题的第二句,那将会很有用。
  • @VGR:什么意思?
  • 您的问题中至少有两个地方使用了“空单元格”一词。如果您的意思是未选中的单元格,那么如果您将措辞更改为“未选中的单元格”,读者的困惑就会大大减少。

标签: java swing drag-and-drop jtable


【解决方案1】:

你或许可以直接调用MouseMotionListener#mouseDragged(...)中的TransferHandler#exportAsDrag(...)方法:

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

【讨论】:

    【解决方案2】:

    选择模式应该只能通过点击实现,并且应该可以通过 shift + click 扩展,而不是通过拖动

    您可以通过使用一些额外的逻辑覆盖 JTable 的 processMouseEvent 方法来改变行为。当按钮按下事件发生时 - 并且 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);
            }
    };
    

    【讨论】:

    • 谢谢,但这并不适用于所有情况。如果你是 e,它就不起作用。 G。在单细胞选择模式下。我用单细胞选择模式更新了这个例子。我已经看到了覆盖 processMouseEvent 的解决方案。我还没有找到一个令人满意的工作。
    • @Roland,可能没有比仅在选择模式的基础上实现它更简单的答案了……也就是说 Control 启动拖动 - Shift 应该具有优先权。因此,您可以根据需要更改选择,然后传递带有控制掩码的 MouseEvent(请参阅编辑 - 请注意,我尚未针对所有选择模式进行测试)。
    • 非常感谢您的努力。但是现在单个单元格的选择消失了。当我单击一个单元格时,它只会获得焦点边框。我会玩弄你的解决方案。但正如我所说,我以前见过这种解决方案。我不喜欢它是隐式调用一些听众的选择的改变。我正在寻找更多没有副作用的正确方法。
    猜你喜欢
    • 2013-07-12
    • 2011-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-13
    • 1970-01-01
    • 2018-08-09
    • 2013-02-13
    相关资源
    最近更新 更多