Перетащите файлы из ОС в приложение Java (Swing) - PullRequest
7 голосов
/ 08 февраля 2012

Позвольте мне начать с того, что я читал учебник drag'n drop и похожие вопросы, задаваемые по SO, но, к сожалению, я только запутался в этом вопросе. То, чего я хочу достичь, относительно просто, поэтому я удивлен, что это уже доставило мне столько хлопот. Я пишу небольшое служебное приложение, которое объединит кучу файлов результатов (пользовательский тип xml) в большой текстовый файл, разделенный табуляцией. Большая часть функциональности уже закодирована, однако я хотел сделать для нее достойный графический интерфейс.

Я хочу иметь возможность перетаскивать файлы в компонент (например, JTextArea) приятным и приятным способом (читай: не полные пути, а вместо этого маленький значок и имя). Я хотел бы иметь возможность предоставить JFileChooser для просмотра файлов. Затем я последовательно проанализирую файлы, чтобы получить желаемую матрицу.

Что я узнал до сих пор, так это то, что фреймворк уже существует, однако любые дополнительные функции должны быть созданы на заказ. Я создал тестовый графический интерфейс в Netbeans и попытался перетащить кучу файлов на JTextArea, но они отображаются в виде путей к файлам, и по общему признанию это выглядит очень уродливо.

Буду очень признателен за любые советы и рекомендации о том, как решить (или уточнить) эту проблему аккуратно. Обратите внимание, что я намерен использовать программное обеспечение на нескольких разных ОС (Mac, Win и Linux).

РЕДАКТИРОВАТЬ: код, который я имею до сих пор, основан на одном из примеров из учебных пособий Sun и выглядит следующим образом

import java.awt.datatransfer.*;
import java.awt.event.*;
import java.awt.*;
import java.io.*;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.border.TitledBorder;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.text.*;

public class ConsolidatorDemo extends JPanel implements ActionListener {
    private static final long serialVersionUID = -4487732343062917781L;
    JFileChooser fc;
    JButton clear;
    JTextArea dropZone, console;
    JSplitPane childSplitPane, parentSplitPane;
    PrintStream ps;

  public ConsolidatorDemo() {
    super(new BorderLayout());

    fc = new JFileChooser();;
    fc.setMultiSelectionEnabled(true);
    fc.setDragEnabled(true);
    fc.setControlButtonsAreShown(false);
    fc.setFileSelectionMode(JFileChooser.FILES_ONLY);               


    JPanel fcPanel = new JPanel(new BorderLayout());
    fcPanel.add(fc, BorderLayout.CENTER);

    clear = new JButton("Clear All");
    clear.addActionListener(this);
    JPanel buttonPanel = new JPanel(new BorderLayout());
    buttonPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    buttonPanel.add(clear, BorderLayout.LINE_END);

    JPanel leftUpperPanel = new JPanel(new BorderLayout());
    leftUpperPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    leftUpperPanel.add(fcPanel, BorderLayout.CENTER);
    leftUpperPanel.add(buttonPanel, BorderLayout.PAGE_END);


    JScrollPane leftLowerPanel = new javax.swing.JScrollPane();
    leftLowerPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    dropZone = new JTextArea();
    dropZone.setColumns(20);
    dropZone.setLineWrap(true);
    dropZone.setRows(5);
    dropZone.setDragEnabled(true);
    dropZone.setDropMode(javax.swing.DropMode.INSERT);
    dropZone.setBorder(new TitledBorder("Selected files/folders"));
    leftLowerPanel.setViewportView(dropZone);

    childSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
            leftUpperPanel, leftLowerPanel);
    childSplitPane.setDividerLocation(400);
    childSplitPane.setPreferredSize(new Dimension(480, 650));

    console = new JTextArea();
    console.setColumns(40);
    console.setLineWrap(true);
    console.setBorder(new TitledBorder("Console"));

    parentSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
                    childSplitPane, console);
    parentSplitPane.setDividerLocation(480);
    parentSplitPane.setPreferredSize(new Dimension(800, 650));

    add(parentSplitPane, BorderLayout.CENTER);

}

public void setDefaultButton() {
    getRootPane().setDefaultButton(clear);
}

public void actionPerformed(ActionEvent e) {
    if (e.getSource() == clear) {
        dropZone.setText("");

    }
}

/**
 * Create the GUI and show it. For thread safety,
 * this method should be invoked from the
 * event-dispatching thread.
 */
private static void createAndShowGUI() {
    //Make sure we have nice window decorations.
    JFrame.setDefaultLookAndFeelDecorated(true);
    try {
      //UIManager.setLookAndFeel("de.javasoft.plaf.synthetica.SyntheticaBlackStarLookAndFeel");
        for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                UIManager.setLookAndFeel(info.getClassName());
                break;
            }
        }
    }catch (Exception e){
      e.printStackTrace();
    }

    //Create and set up the window.
    JFrame frame = new JFrame("Consolidator!");
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    //Create and set up the menu bar and content pane.
    ConsolidatorDemo demo = new ConsolidatorDemo();
    demo.setOpaque(true); //content panes must be opaque
    frame.setContentPane(demo);

    //Display the window.
    frame.pack();
    frame.setVisible(true);
    demo.setDefaultButton();
}

public static void main(String[] args) {
    //Schedule a job for the event-dispatching thread:
    //creating and showing this application's GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            createAndShowGUI();
        }
    });
}

Ответы [ 3 ]

9 голосов
/ 09 февраля 2012

Вот быстрый фрагмент для импорта фактических файлов в JList (в отличие от импорта его представления String в текстовый компонент) и использования настраиваемого средства визуализации, чтобы красиво его представить. Это адаптировано из BasicDnD (в учебнике):

    fileDropper = new JList(new DefaultListModel());
    fileDropper.setDragEnabled(true);
    leftLowerPanel.setViewportView(fileDropper);

    TransferHandler handler =   new TransferHandler() {

        @Override
        public boolean canImport(TransferHandler.TransferSupport info) {
            // we only import FileList
            if (!info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
                return false;
            }
            return true;
        }

        @Override
        public boolean importData(TransferHandler.TransferSupport info) {
            if (!info.isDrop()) {
                return false;
            }

            // Check for FileList flavor
            if (!info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
                displayDropLocation("List doesn't accept a drop of this type.");
                return false;
            }

            // Get the fileList that is being dropped.
            Transferable t = info.getTransferable();
            List<File> data;
            try {
                data = (List<File>)t.getTransferData(DataFlavor.javaFileListFlavor);
            } 
            catch (Exception e) { return false; }
            DefaultListModel model = (DefaultListModel) fileDropper.getModel();
            for (File file : data) {
                model.addElement(file);
            }
            return true;
        }

        private void displayDropLocation(String string) {
            System.out.println(string);
        }
    };
    fileDropper.setTransferHandler(handler);
    fileDropper.setCellRenderer(new DefaultListRenderer(
          StringValues.FILE_NAME, IconValues.FILE_ICON));

Не смог удержаться от показа конфигурации рендерера SwingX :-) В ядре Java вы бы делали это вручную, что-то вроде

   class MyRenderer extends DefaultListCellRenderer {

        @Override
        public Component getListCellRendererComponent(...) {
            super.getList...
            if (value instanceof File) {
                setText(FileSystemView.getFileSystemView().getDisplayName(value);
                setIcon(FileSystemView.getFileSystemView().getSystemIcon(value);
            } 
            return this;
        }

   }
7 голосов
/ 09 февраля 2012

Это, по сути, ответ Клеопатры 1 (с небольшими изменениями, не обязательно в лучшую сторону), .. со скриншотом!

ConsolidatorDemo

import java.awt.datatransfer.*;
import java.awt.event.*;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.io.*;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.border.TitledBorder;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.filechooser.FileSystemView;
import javax.swing.text.*;
import java.util.List;

public class ConsolidatorDemo extends JPanel implements ActionListener {
    private static final long serialVersionUID = -4487732343062917781L;
    JFileChooser fc;
    JButton clear;
    JTextArea console;

    JList dropZone;
    DefaultListModel listModel;
    JSplitPane childSplitPane, parentSplitPane;
    PrintStream ps;

  public ConsolidatorDemo() {
    super(new BorderLayout());

    fc = new JFileChooser();;
    fc.setMultiSelectionEnabled(true);
    fc.setDragEnabled(true);
    fc.setControlButtonsAreShown(false);
    fc.setFileSelectionMode(JFileChooser.FILES_ONLY);


    JPanel fcPanel = new JPanel(new BorderLayout());
    fcPanel.add(fc, BorderLayout.CENTER);

    clear = new JButton("Clear All");
    clear.addActionListener(this);
    JPanel buttonPanel = new JPanel(new BorderLayout());
    buttonPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    buttonPanel.add(clear, BorderLayout.LINE_END);

    JPanel leftUpperPanel = new JPanel(new BorderLayout());
    leftUpperPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    leftUpperPanel.add(fcPanel, BorderLayout.CENTER);
    leftUpperPanel.add(buttonPanel, BorderLayout.PAGE_END);

    JScrollPane leftLowerPanel = new javax.swing.JScrollPane();
    leftLowerPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));

    listModel = new DefaultListModel();
    dropZone = new JList(listModel);
    dropZone.setCellRenderer(new FileCellRenderer());
    dropZone.setTransferHandler(new ListTransferHandler(dropZone));
    dropZone.setDragEnabled(true);
    dropZone.setDropMode(javax.swing.DropMode.INSERT);
    dropZone.setBorder(new TitledBorder("Selected files/folders"));
    leftLowerPanel.setViewportView(new JScrollPane(dropZone));

    childSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
            leftUpperPanel, leftLowerPanel);
    childSplitPane.setDividerLocation(400);
    childSplitPane.setPreferredSize(new Dimension(480, 650));

    console = new JTextArea();
    console.setColumns(40);
    console.setLineWrap(true);
    console.setBorder(new TitledBorder("Console"));

    parentSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
                    childSplitPane, console);
    parentSplitPane.setDividerLocation(480);
    parentSplitPane.setPreferredSize(new Dimension(800, 650));

    add(parentSplitPane, BorderLayout.CENTER);

}

public void setDefaultButton() {
    getRootPane().setDefaultButton(clear);
}

public void actionPerformed(ActionEvent e) {
    if (e.getSource() == clear) {
        listModel.clear();
    }
}

/**
 * Create the GUI and show it. For thread safety,
 * this method should be invoked from the
 * event-dispatching thread.
 */
private static void createAndShowGUI() {
    //Make sure we have nice window decorations.
    JFrame.setDefaultLookAndFeelDecorated(true);
    try {
      //UIManager.setLookAndFeel("de.javasoft.plaf.synthetica.SyntheticaBlackStarLookAndFeel");
        for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                UIManager.setLookAndFeel(info.getClassName());
                break;
            }
        }
    }catch (Exception e){
      e.printStackTrace();
    }

    //Create and set up the window.
    JFrame frame = new JFrame("Consolidator!");
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    //Create and set up the menu bar and content pane.
    ConsolidatorDemo demo = new ConsolidatorDemo();
    demo.setOpaque(true); //content panes must be opaque
    frame.setContentPane(demo);

    //Display the window.
    frame.pack();
    frame.setVisible(true);
    demo.setDefaultButton();
}

public static void main(String[] args) {
    //Schedule a job for the event-dispatching thread:
    //creating and showing this application's GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            createAndShowGUI();
        }
    });
}
}

class FileCellRenderer extends DefaultListCellRenderer {

    public Component getListCellRendererComponent(JList list,
        Object value,
        int index,
        boolean isSelected,
        boolean cellHasFocus) {

        Component c = super.getListCellRendererComponent(
            list,value,index,isSelected,cellHasFocus);

        if (c instanceof JLabel && value instanceof File) {
            JLabel l = (JLabel)c;
            File f = (File)value;
            l.setIcon(FileSystemView.getFileSystemView().getSystemIcon(f));
            l.setText(f.getName());
            l.setToolTipText(f.getAbsolutePath());
        }

        return c;
    }
}

class ListTransferHandler extends TransferHandler {

    private JList list;

    ListTransferHandler(JList list) {
        this.list = list;
    }

    @Override
    public boolean canImport(TransferHandler.TransferSupport info) {
        // we only import FileList
        if (!info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
            return false;
        }
        return true;
    }

    @Override
    public boolean importData(TransferHandler.TransferSupport info) {
        if (!info.isDrop()) {
            return false;
        }

        // Check for FileList flavor
        if (!info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
            displayDropLocation("List doesn't accept a drop of this type.");
            return false;
        }

        // Get the fileList that is being dropped.
        Transferable t = info.getTransferable();
        List<File> data;
        try {
            data = (List<File>)t.getTransferData(DataFlavor.javaFileListFlavor);
        }
        catch (Exception e) { return false; }
        DefaultListModel model = (DefaultListModel) list.getModel();
        for (Object file : data) {
            model.addElement((File)file);
        }
        return true;
    }

    private void displayDropLocation(String string) {
        System.out.println(string);
    }
}
  1. Я был занят написанием ответа, когда заметил, что она уже опубликовала ответ. Так как мой TransferHandler был очень сломан, я использовал ее. Хотя я использовал свою версию рендерера ячеек списка, которая, кажется, не отражает тонкости того, что она предлагала. Я также получал ошибки компиляции при упоминании List (учитывая, что компилятор предполагал, что я имел в виду список AWT. Я понял, что происходит, только после того, как я изменил несколько операторов типа List<File>, чтобы они не были универсальными - Я думаю, что большинство из них теперь вернулись обратно.
0 голосов
/ 02 апреля 2017

Вот код без консоли и дополнительной кнопки

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.PrintStream;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.border.TitledBorder;
import javax.swing.filechooser.FileSystemView;

public class ConsolidatorDemo extends JPanel implements ActionListener {
    private static final long serialVersionUID = -4487732343062917781L;
    // JFileChooser fc;
    JButton clear,compare;
    JTextArea fc;

    JList dropZone;
    DefaultListModel listModel;
    JSplitPane childSplitPane, parentSplitPane;
    PrintStream ps;

    public ConsolidatorDemo() {
        super(new BorderLayout());

        /* fc = new JFileChooser();;
    fc.setMultiSelectionEnabled(true);
    fc.setDragEnabled(true);
    fc.setControlButtonsAreShown(false);
    fc.setFileSelectionMode(JFileChooser.FILES_ONLY);*/
        fc= new JTextArea();
        fc.setText("Rules:\n1. drop old html first.\n2. drop new html.\n3. drop output folder.\n4. click compare button.\n5. Check output in the output.txt file.\nEnd");

        fc.setEditable(false);
        JPanel fcPanel = new JPanel(new BorderLayout());

        fcPanel.add(fc, BorderLayout.CENTER);


        compare = new JButton("Compare");
        compare.addActionListener(this);
        JPanel buttonPanel1 = new JPanel(new BorderLayout());
        buttonPanel1.setBorder(BorderFactory.createEmptyBorder(1,1,1,1));
        buttonPanel1.add(compare, BorderLayout.LINE_END);


        clear = new JButton("Clear All");
        clear.addActionListener(this);
        JPanel buttonPanel = new JPanel(new BorderLayout());
        buttonPanel.setBorder(BorderFactory.createEmptyBorder(1,1,1,1));
        buttonPanel.add(clear, BorderLayout.LINE_END);

        JPanel leftUpperPanel = new JPanel(new BorderLayout());
        leftUpperPanel.setBorder(BorderFactory.createEmptyBorder(3,3,3,3));
        leftUpperPanel.add(fcPanel, BorderLayout.CENTER);
        leftUpperPanel.add(buttonPanel1, BorderLayout.LINE_END);
        leftUpperPanel.add(buttonPanel, BorderLayout.PAGE_END);

        JScrollPane leftLowerPanel = new javax.swing.JScrollPane();
        leftLowerPanel.setBorder(BorderFactory.createEmptyBorder(3,3,3,3));

        listModel = new DefaultListModel();
        dropZone = new JList(listModel);
        dropZone.setCellRenderer(new FileCellRenderer());
        dropZone.setTransferHandler(new ListTransferHandler(dropZone));
        dropZone.setDragEnabled(true);
        dropZone.setDropMode(javax.swing.DropMode.INSERT);
        dropZone.setBorder(new TitledBorder("Drag and drop files here"));
        leftLowerPanel.setViewportView(new JScrollPane(dropZone));

        childSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, leftLowerPanel,leftUpperPanel);
        childSplitPane.setDividerLocation(200);//400
        childSplitPane.setPreferredSize(new Dimension(300, 400));//480, 650

        /*console = new JTextArea();
    console.setColumns(40);
    console.setLineWrap(true);
    console.setBorder(new TitledBorder("Console"));

    parentSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
                    childSplitPane, console);
    parentSplitPane.setDividerLocation(480);
    parentSplitPane.setPreferredSize(new Dimension(800, 650));*/

        add(childSplitPane, BorderLayout.CENTER);

    }

    public void setDefaultButton() {
        getRootPane().setDefaultButton(clear);
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == clear) {
            listModel.clear();
        }else if (e.getSource() == compare) {
            //our function
        }
    }

    /**
     * Create the GUI and show it. For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Make sure we have nice window decorations.
        JFrame.setDefaultLookAndFeelDecorated(true);
        try {
            //UIManager.setLookAndFeel("de.javasoft.plaf.synthetica.SyntheticaBlackStarLookAndFeel");
            for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }

        //Create and set up the window.
        JFrame frame = new JFrame("Bill of materials Comparer");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        //Create and set up the menu bar and content pane.
        ConsolidatorDemo demo = new ConsolidatorDemo();
        demo.setOpaque(true); //content panes must be opaque
        frame.setContentPane(demo);

        //Display the window.
        frame.pack();
        frame.setVisible(true);
        demo.setDefaultButton();
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

class FileCellRenderer extends DefaultListCellRenderer {

    public Component getListCellRendererComponent(JList list,Object value,int index,boolean isSelected,boolean cellHasFocus) {

        Component c = super.getListCellRendererComponent(list,value,index,isSelected,cellHasFocus);

        if (c instanceof JLabel && value instanceof File) {
            JLabel l = (JLabel)c;
            File f = (File)value;
            l.setIcon(FileSystemView.getFileSystemView().getSystemIcon(f));
            l.setText(f.getName());
            //l.setText(f.getAbsolutePath());
            l.setToolTipText(f.getAbsolutePath());
        }

        return c;
    }
}

class ListTransferHandler extends TransferHandler {

    private JList list;

    ListTransferHandler(JList list) {
        this.list = list;
    }

    @Override
    public boolean canImport(TransferHandler.TransferSupport info) {
        // we only import FileList
        if (!info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
            return false;
        }
        return true;
    }

    @Override
    public boolean importData(TransferHandler.TransferSupport info) {
        if (!info.isDrop()) {
            return false;
        }

        // Check for FileList flavor
        if (!info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
            displayDropLocation("List doesn't accept a drop of this type.");
            return false;
        }

        // Get the fileList that is being dropped.
        Transferable t = info.getTransferable();
        List<File> data;
        try {
            data = (List<File>)t.getTransferData(DataFlavor.javaFileListFlavor);
        }
        catch (Exception e) { return false; }
        DefaultListModel model = (DefaultListModel) list.getModel();
        for (Object file : data) {
            model.addElement((File)file);
        }
        return true;
    }

    private void displayDropLocation(String string) {
        System.out.println(string);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...