Pull to refresh

Copy/paste функциональность между Swing's JTables и Excel

Reading time9 min
Views3.6K
Original author: Ashok Banerjee, Jignesh Mehta
От переводчика: данный перевод просто проба пера. Буду очень благодарен за все замечания. Надеюсь на вашу помощь в приведении этой статьи к литературному виду. Вот только небольшой список того, чтобы я хотел исправить в данной статье:
  • сделать статью более «русской», а не просто набором переведённых слов.


Многие бизнес приложения разрабатываются с использованием Java. Большинство из них отображают данные в виде таблиц используя Swing JTable. Было бы очень удобно иметь возможность копировать и вставлять данные из данного приложения в Microsoft Excel и обратно. Таким образом пользователи смогли бы воспользоваться всей мощью этой вездесущей программы.

Данный Java совет поможет понять принцип формируемой Excel строки, помещаемой в системный буфера обмена, позволит добиться copy/paste функциональности при взаимодействии JTable и Excel. Как вы увидите далее, этот совет законченный и позволяет добиться желаемого результата буквально дописав одну строчку кода.

Всё, что вам нужно для достижения данной цели, это скопировать файл ExcelAdapter.java, описанный ниже, скомпилировать его и позаботиться о доступности полученного класса для вашего приложения. Как только вы это сделаете, ваш JTable готов к «разговору» с Excel. Мы покажем какую строчку необходимо дописать, чтобы обеспечить Copy/Paste функциональность с Excel. Конечно, будет приведен и пример простого приложения, обеспеченного данной функциональностью.

Класс адаптер


Ниже представлен код класса-адаптера, называемого ExcelAdapter.java, который и призван решить данную задачу:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.datatransfer.*;
import java.util.*;

/**
* ExcelAdapter enables Copy-Paste Clipboard functionality on JTables. The
* clipboard data format used by the adapter is compatible with the clipboard
* format used by Excel. This provides for clipboard interoperability between
* enabled JTables and Excel.
*/
public class ExcelAdapter implements ActionListener {
   private String rowstring, value;
   private Clipboard system;
   private StringSelection stsel;
   private JTable jTable1;

   /**
    * The Excel Adapter is constructed with a JTable on which it enables
    * Copy-Paste and acts as a Clipboard listener.
    */
   public ExcelAdapter(JTable myJTable) {
      jTable1 = myJTable;
      KeyStroke copy = KeyStroke.getKeyStroke(KeyEvent.VK_C,
            ActionEvent.CTRL_MASK, false);
      // Identifying the copy KeyStroke user can modify this
      // to copy on some other Key combination.
      KeyStroke paste = KeyStroke.getKeyStroke(KeyEvent.VK_V,
            ActionEvent.CTRL_MASK, false);
      // Identifying the Paste KeyStroke user can modify this
      // to copy on some other Key combination.
      jTable1.registerKeyboardAction(this, "Copy", copy,
            JComponent.WHEN_FOCUSED);
      jTable1.registerKeyboardAction(this, "Paste", paste,
            JComponent.WHEN_FOCUSED);
      system = Toolkit.getDefaultToolkit().getSystemClipboard();
   }

   /**
    * Public Accessor methods for the Table on which this adapter acts.
    */
   public JTable getJTable() {
      return jTable1;
   }

   public void setJTable(JTable jTable1) {
      this.jTable1 = jTable1;
   }

   /**
    * This method is activated on the Keystrokes we are listening to in this
    * implementation. Here it listens for Copy and Paste ActionCommands.
    * Selections comprising non-adjacent cells result in invalid selection and
    * then copy action cannot be performed. Paste is done by aligning the upper
    * left corner of the selection with the 1st element in the current
    * selection of the JTable.
    */
   public void actionPerformed(ActionEvent e) {
      if (e.getActionCommand().compareTo("Copy") == 0) {
         StringBuffer sbf = new StringBuffer();
         // Check to ensure we have selected only a contiguous block of
         // cells
         int numcols = jTable1.getSelectedColumnCount();
         int numrows = jTable1.getSelectedRowCount();
         int[] rowsselected = jTable1.getSelectedRows();
         int[] colsselected = jTable1.getSelectedColumns();
         if (!((numrows - 1 == rowsselected[rowsselected.length - 1]
               - rowsselected[0] && numrows == rowsselected.length) && (numcols - 1 == colsselected[colsselected.length - 1]
               - colsselected[0] && numcols == colsselected.length))) {
            JOptionPane.showMessageDialog(null, "Invalid Copy Selection",
                  "Invalid Copy Selection", JOptionPane.ERROR_MESSAGE);
            return;
         }
         for (int i = 0; i < numrows; i++) {
            for (int j = 0; j < numcols; j++) {
               sbf.append(jTable1.getValueAt(rowsselected[i],
                     colsselected[j]));
               if (j < numcols - 1)
                  sbf.append("\t");
            }
            sbf.append("\n");
         }
         stsel = new StringSelection(sbf.toString());
         system = Toolkit.getDefaultToolkit().getSystemClipboard();
         system.setContents(stsel, stsel);
      }
      if (e.getActionCommand().compareTo("Paste") == 0) {
         System.out.println("Trying to Paste");
         int startRow = (jTable1.getSelectedRows())[0];
         int startCol = (jTable1.getSelectedColumns())[0];
         try {
            String trstring = (String) (system.getContents(this)
                  .getTransferData(DataFlavor.stringFlavor));
            System.out.println("String is:" + trstring);
            StringTokenizer st1 = new StringTokenizer(trstring, "\n");
            for (int i = 0; st1.hasMoreTokens(); i++) {
               rowstring = st1.nextToken();
               StringTokenizer st2 = new StringTokenizer(rowstring, "\t");
               for (int j = 0; st2.hasMoreTokens(); j++) {
                  value = (String) st2.nextToken();
                  if (startRow + i < jTable1.getRowCount()
                        && startCol + j < jTable1.getColumnCount())
                     jTable1.setValueAt(value, startRow + i, startCol
                           + j);
                  System.out.println("Putting " + value + "at row="
                        + startRow + i + "column=" + startCol + j);
               }
            }
         } catch (Exception ex) {
            ex.printStackTrace();
         }
      }
   }
}
* This source code was highlighted with Source Code Highlighter.


Простое приложение


Ниже приведён код простого приложения Frame1.java, который, используя ExcelAdapter, делает JTable Excel-совместимым.

import java.awt.*;
import javax.swing.*;

public class Frame1 extends Frame {
   
   BorderLayout borderLayout1 = new BorderLayout();
   JTable jTable1;
   Object[][] data = new Object[4][4];
   Object header[] = { "Jan", "Feb", "Mar", "Apr" };

   public static void main(String args[]) {
      Frame1 myframe = new Frame1();
      myframe.setSize(new Dimension(250, 250));
      myframe.setVisible(true);
   }

   public Frame1() {
      super();
      try {
         jbInit();
      } catch (Exception e) {
         e.printStackTrace();
      }
   }

   private void jbInit() throws Exception {
      for (int i = 0; i < 4; i++)
         for (int j = 0; j < 4; j++)
            data[i][j] = new Integer(i * 10 + j);
      System.out.println("Header length=" + header[1]);
      jTable1 = new JTable(data, header);
      jTable1.setCellSelectionEnabled(true);
      this.setTitle("Excel Lent JTABLE");
      jTable1.setBackground(Color.pink);
      this.setLayout(borderLayout1);
      this.setSize(new Dimension(400, 300));
      this.setBackground(Color.white);
      this.add(jTable1, BorderLayout.CENTER);
      // This is the line that does all the magic!
      ExcelAdapter myAd = new ExcelAdapter(jTable1);
   }
}
* This source code was highlighted with Source Code Highlighter.



Формат данных, помещаемых Excel в буфер обмена


Формат данных, помещаемых Excel в буфер обмена очень простой. Excel разделяет данные, которые находятся в одной строке, с помощью табов, а данные, которые находятся в разных строках — символами новой строки (обычно это символ "\n"). Таким образом, когда вы копируете набор ячеек, Excel помещаете в буфер обмена строку, сформированную по вышеописанным правилам. Используя данную информацию, можно реализовать Copy/Paste функциональность в лубом приложении, написанном на любом языке, который позволяет работать с буфером обмена.

Авторы


Ashok Banerjee и Jignesh Mehta работают в Oracle Corporation.
Tags:
Hubs:
+3
Comments2

Articles