JTable - перетаскивание - PullRequest
       30

JTable - перетаскивание

11 голосов
/ 03 апреля 2009

ОК, эта проблема выходит за рамки моей лиги. Я пытаюсь реализовать GUI-виджет на качелях, который позволяет перетаскивать файлы на JTable и позволяет перетаскивать строки JTable для повторной сортировки. Вспомните плейлисты VLC или плейлисты в iTunes.

У меня сбрасываются файлы из ОС (Explorer, Finder и т. Д.), Которые работают просто отлично, но у меня нет времени с перекомпоновкой строк таблицы, когда файлы в ней. Проблема в том, что когда я добавляю пользовательский TransferHandler в таблицу, перетаскивая из , таблица мгновенно уничтожается. Вот пример кода:

import javax.swing.*;

public class TableTest
{
    public static void main (String [] argv)
    {
        // setup table data
        String [] columns = new String [] {"Foo", "Bar", "Baz", "Quux"};
        String [][] data = new String [][] {{"A", "B", "C", "D"},
                        {"1", "2", "3", "4"},
                        {"i", "ii", "iii", "iv"}};
        // create table
        JTable table = new JTable(data, columns);

        // set up drag and drop
        table.setDragEnabled(true);
        table.setDropMode(DropMode.INSERT_ROWS);
        table.setFillsViewportHeight(true);
        TransferHandler dnd = new TransferHandler() {
            // here be code to handle drops, and one would
            // presume drag exporting, too
        };
        table.setTransferHandler(dnd);
        JScrollPane scroll = new JScrollPane(table);

        // create and show window
        JFrame window = new JFrame();
        window.getContentPane().add(scroll);
        window.pack();
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setVisible(true);
    }
}

Запустите этот код как есть, и вы увидите, что не можете инициировать перетаскивание таблицы. Если вы закомментируете вызов setTransferHandler () для таблицы, перетаскивание работает (т. Е. Когда я начинаю перетаскивать строку таблицы) , Я получаю X круговой курсор, говорящий, что я не могу бросить там). Но как только для таблицы установлен TransferHandler, я не могу перетаскивать строки. Проблема должна быть в TransferHandler, но я тщательно устраню ее и отлаживаю, и определил, что перетаскивание никогда не начинается, когда на столе есть TransferHandler. Что я делаю не так?

Ответы [ 4 ]

5 голосов
/ 04 марта 2010

У меня была такая же проблема, она не имеет ничего общего с вашей пользовательской реализацией TransferHandler. Когда вы заменяете TransferHandler, вам также нужно взять DragSource по умолчанию и сказать ему распознавать жест перетаскивания. Вам также может понадобиться реализовать свой собственный Transferable, потому что вам нужно будет передать его в метод DragGestureEvent.startDrag ().

    table.setTransferHandler(new MyTransferHandler());
    table.setDragEnabled(true);
    DragSource source = DragSource.getDefaultDragSource();
    source.createDefaultDragGestureRecognizer(table, DnDConstants.ACTION_COPY, new DragGestureListener() {

        @Override
        public void dragGestureRecognized(DragGestureEvent dge) {
            //grab the selected files from the table model
            ArrayList<File> files = new ArrayList<File>();
            for (int row : table.getSelectedRows()) {
                files.add((File) dm.getValueAt(row, 1));
            }

            //FileTransferable is a custom Transferable implementation
            Transferable transferable = new FileTransferable(files); 

            //and this is the magic right here
            dge.startDrag(null,transferable);
        }
    });
3 голосов
/ 07 апреля 2009

Мне кажется, проблема в том, что пустой TransferHandler фактически предотвращает возникновение событий DnD. Здесь есть образец, который может быть уместным.

http://www.java2s.com/Code/Java/Swing-JFC/ExtendedDnDDragandDropDemo.htm

3 голосов
/ 07 апреля 2009

Не похоже, что вы используете TransferHandler должным образом. Попробуйте прочитать урок здесь .

См. Документ TransferHandler здесь . Пустой конструктор не выглядит так, как будто он предназначен для использования вне подкласса TransferHandler.

И вы не реализуете ни одну из функций, предусмотренных в стандартном TransferHandler, предоставляемом для компонентов Swing. Смотрите отрывок из учебника DnD здесь (мой жирный):

Примечание. При установке пользовательского TransferHandler на компонент Swing поддержка по умолчанию заменяется. Например, если вы замените TransferHandler в JTextField на тот, который обрабатывает только цвета, вы отключите его способность поддерживать импорт и экспорт текста. Если вам нужно заменить TransferHandler по умолчанию - например, тот, который обрабатывает текст - вам нужно будет повторно реализовать возможность импорта и экспорта текста. Это не обязательно должно быть настолько обширно, как то, что предоставляет Swing - это может быть так же просто, как поддержка разновидности данных StringFlavor, в зависимости от потребностей вашего приложения.

1 голос
/ 22 декабря 2010

Я не хотел разбираться в том, что происходит, поэтому я просто делегировал методы, которые мне не были интересны, старому TransferHandler.

tree.setDragEnabled(true);
tree.setDropMode(DropMode.XXXX);
tree.setTransferHandler(new MyTransferHandler(tree.getTransferHandler());

Начните со стандартной настройки, но передайте старый TransferHandler в свой собственный TransferHandler.

private class MyTransferHandler extends TransferHandler {
  private TransferHandler delegate;

  public MyTransferHandler(TransferHandler delegate) {
    this.delegate = delegate;
  }

  public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
    return delegate.canImport(comp, transferFlavors);
  }

  public boolean canImport(TransferSupport support) {
    return true;
  }

  protected Transferable createTransferable(JComponent c) {
    try {
      Method method = delegate.getClass().getDeclaredMethod("createTransferable", JComponent.class);
      method.setAccessible(true);
      return (Transferable) method.invoke(delegate, c);
    } catch (Exception e) {
      return super.createTransferable(c);
    }
  }

  public void exportAsDrag(JComponent comp, InputEvent event, int action) {
    delegate.exportAsDrag(comp, event, action);
  }

  protected void exportDone(JComponent source, Transferable data, int action) {
    try {
      Method method = delegate.getClass().getDeclaredMethod("exportDone", JComponent.class, Transferable.class,
          int.class);
      method.setAccessible(true);
      method.invoke(delegate, source, data, action);
    } catch (Exception e) {
      super.exportDone(source, data, action);
    }
  }

  public int getSourceActions(JComponent c) {
    return delegate.getSourceActions(c);
  }

  public Icon getVisualRepresentation(Transferable t) {
    return delegate.getVisualRepresentation(t);
  }

  public boolean importData(JComponent comp, Transferable t) {
    return delegate.importData(comp, t);
  }

  public boolean importData(TransferHandler.TransferSupport support) {
    return delegate.importData(support);
  }
}

Одна хитрость заключается в том, что методы createTransferable (JComponent) и exportDone (JComponent, Transferable, int) защищены, поэтому вам необходимо выполнить рефлексию для делегирования этим методам. Когда я не делал эту рефлексию, стратегия не работала. После того, как я это делегировал, перетаскивание работало, как и ожидалось, без изменения DragSource или необходимости писать новый Transferable.

...