JTextArea замораживает интерфейс на больших пастах

У меня есть программа, которая позволяет пользователю вводить данные в JTextArea. Затем данные анализируются и обрабатываются для дальнейшего использования.

Хотя я хорошо знаю о возможности использования неблокирующих отбрасываний файлов, и я уже предлагаю это, некоторые пользователи также могут вставлять большие куски данных. При вставке примерно 100 МБ текста весь графический интерфейс зависает примерно на 20-30 секунд.

Каков наилучший подход для принятия такого огромного куска данных без блокировки графического интерфейса? Сохранение JTextArea не является обязательным требованием.

Если нельзя избежать блокировки графического интерфейса: есть ли способ отловить и отложить событие вставки, чтобы обновить графический интерфейс с некоторым сообщением: "обработка команды вставки" и продолжить после этого?

Пример кода:

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JTextArea;
import java.awt.BorderLayout;


public class JTextAreaExample {

    private JFrame frame;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    JTextAreaExample window = new JTextAreaExample();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the application.
     */
    public JTextAreaExample() {
        initialize();
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 450, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JTextArea textArea = new JTextArea();
        frame.getContentPane().add(textArea, BorderLayout.CENTER);
    }

}

2 ответа

Решение

Я хотел бы поделиться урезанным примером моего "решения" (спасибо Эндрю Томпсону за его подсказки). Даже если это, может быть, и не делает ничего, нужно понять.

Поддержание адаптивного графического интерфейса в большинстве случаев работает как положено. Зависания GUI при фактическом обновлении текста JTextArea невозможно избежать без дальнейших мер (для этого нужно было бы использовать скользящие окна), но это выходит за рамки этого примера. Графический интерфейс не блокируется при обработке буфера копирования, и это был вопрос.

import java.awt.EventQueue;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;

import java.awt.BorderLayout;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;


public class JTextAreaExample {

    private JFrame frame;
    private static JTextArea textArea;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    JTextAreaExample window = new JTextAreaExample();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the application.
     */
    public JTextAreaExample() {
        JTextAreaExample.textArea = new JTextArea();
        initialize();
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 450, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.getContentPane().add(textArea, BorderLayout.CENTER);
        textArea.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_MASK), "ctrlvpressed");
        textArea.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0), "ctrlvpressed");
        CustomPasteAction cpa = new CustomPasteAction("Custom Paste Action", null, "A custom paste action", KeyEvent.VK_V);
        textArea.getActionMap().put("ctrlvpressed", cpa);
    }

    public static final JTextArea getTextArea() {
        return textArea;
    }

}

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.IOException;

import javax.swing.AbstractAction;
import javax.swing.ImageIcon;

public class CustomPasteAction extends AbstractAction implements ClipboardOwner {

    /** */
    private static final long serialVersionUID = 1L;

    public CustomPasteAction(String text, ImageIcon icon,
                                             String desc, Integer mnemonic) {
        super(text, icon);
        putValue(SHORT_DESCRIPTION, desc);
        putValue(MNEMONIC_KEY, mnemonic);
    }

    public CustomPasteAction() {
        super("Custom Paste Action", null);
        putValue(SHORT_DESCRIPTION, "My custom paste action");
        putValue(MNEMONIC_KEY, KeyEvent.VK_V);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        new Thread(new Runnable() {
        public void run() {

            String temp = new CustomPasteAction().getClipboardContents();
            System.out.println("Processing: " + temp);
            JTextAreaExample.getTextArea().setText(temp);

        }
    }).start();
    }

    @Override
    public void lostOwnership(Clipboard clipboard, Transferable contents) {
        // do nothing
    }

    /**
      * Get the String residing on the clipboard.
      *
      * @return any text found on the Clipboard; if none found, return an
      * empty String.
      */
      public String getClipboardContents() {
        String result = "";
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        //odd: the Object param of getContents is not currently used
        Transferable contents = null;
        try {
            contents = clipboard.getContents(null);
        } catch(IllegalStateException ise) {
            ise.printStackTrace();
        }
        boolean hasTransferableText =
          (contents != null) &&
          contents.isDataFlavorSupported(DataFlavor.stringFlavor)
        ;
        if ( hasTransferableText ) {
          try {
            result = (String)contents.getTransferData(DataFlavor.stringFlavor);
          }
          catch (UnsupportedFlavorException ex){
            //highly unlikely since we are using a standard DataFlavor
            System.out.println(ex);
            ex.printStackTrace();
          }
          catch (IOException ex) {
            System.out.println(ex);
            ex.printStackTrace();
          }
        }
        return result;
      }

      /**
       * Place a String on the clipboard, and make this class the
       * owner of the Clipboard's contents.
       */
       public void setClipboardContents( String aString ){
         StringSelection stringSelection = new StringSelection( aString );
         Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
         clipboard.setContents( stringSelection, this );
       }

}

Может быть, вы можете использовать Progress Monitor API

Другие вопросы по тегам