Создать консоль Java внутри панели графического интерфейса - PullRequest
42 голосов
/ 05 декабря 2008

Как создать экземпляр консоли Java внутри панели графического интерфейса?

Ответы [ 5 ]

68 голосов
/ 05 декабря 2008

Вот функциональный класс. Вы можете установить экземпляр этого в систему и ошибиться, используя:

PrintStream con=new PrintStream(new TextAreaOutputStream(...));
System.setOut(con);
System.setErr(con);

Обновлено 2014-02-19 : чтобы использовать EventQueue.invokeLater (), чтобы избежать проблем с многопоточностью GUI, которые могут очень редко встречаться с оригиналом.

Обновлено 2014-02-27 : улучшена реализация

Обновлено 2014-03-25 : Корректная запись и удаление строк в текстовой области должны соответствовать методу run(), чтобы избежать состояния гонки между добавлением и удалением, которое может произойти, если консоль затоплена с выходом. Конечный результат мне тоже кажется чище.

import java.awt.*;
import java.io.*;
import java.util.*;
import java.util.List;
import javax.swing.*;

public class TextAreaOutputStream
extends OutputStream
{

// *************************************************************************************************
// INSTANCE MEMBERS
// *************************************************************************************************

private byte[]                          oneByte;                                                    // array for write(int val);
private Appender                        appender;                                                   // most recent action

public TextAreaOutputStream(JTextArea txtara) {
    this(txtara,1000);
    }

public TextAreaOutputStream(JTextArea txtara, int maxlin) {
    if(maxlin<1) { throw new IllegalArgumentException("TextAreaOutputStream maximum lines must be positive (value="+maxlin+")"); }
    oneByte=new byte[1];
    appender=new Appender(txtara,maxlin);
    }

/** Clear the current console text area. */
public synchronized void clear() {
    if(appender!=null) { appender.clear(); }
    }

public synchronized void close() {
    appender=null;
    }

public synchronized void flush() {
    }

public synchronized void write(int val) {
    oneByte[0]=(byte)val;
    write(oneByte,0,1);
    }

public synchronized void write(byte[] ba) {
    write(ba,0,ba.length);
    }

public synchronized void write(byte[] ba,int str,int len) {
    if(appender!=null) { appender.append(bytesToString(ba,str,len)); }
    }

@edu.umd.cs.findbugs.annotations.SuppressWarnings("DM_DEFAULT_ENCODING")
static private String bytesToString(byte[] ba, int str, int len) {
    try { return new String(ba,str,len,"UTF-8"); } catch(UnsupportedEncodingException thr) { return new String(ba,str,len); } // all JVMs are required to support UTF-8
    }

// *************************************************************************************************
// STATIC MEMBERS
// *************************************************************************************************

    static class Appender
    implements Runnable
    {
    private final JTextArea             textArea;
    private final int                   maxLines;                                                   // maximum lines allowed in text area
    private final LinkedList<Integer>   lengths;                                                    // length of lines within text area
    private final List<String>          values;                                                     // values waiting to be appended

    private int                         curLength;                                                  // length of current line
    private boolean                     clear;
    private boolean                     queue;

    Appender(JTextArea txtara, int maxlin) {
        textArea =txtara;
        maxLines =maxlin;
        lengths  =new LinkedList<Integer>();
        values   =new ArrayList<String>();

        curLength=0;
        clear    =false;
        queue    =true;
        }

    synchronized void append(String val) {
        values.add(val);
        if(queue) { queue=false; EventQueue.invokeLater(this); }
        }

    synchronized void clear() {
        clear=true;
        curLength=0;
        lengths.clear();
        values.clear();
        if(queue) { queue=false; EventQueue.invokeLater(this); }
        }

    // MUST BE THE ONLY METHOD THAT TOUCHES textArea!
    public synchronized void run() {
        if(clear) { textArea.setText(""); }
        for(String val: values) {
            curLength+=val.length();
            if(val.endsWith(EOL1) || val.endsWith(EOL2)) {
                if(lengths.size()>=maxLines) { textArea.replaceRange("",0,lengths.removeFirst()); }
                lengths.addLast(curLength);
                curLength=0;
                }
            textArea.append(val);
            }
        values.clear();
        clear =false;
        queue =true;
        }

    static private final String         EOL1="\n";
    static private final String         EOL2=System.getProperty("line.separator",EOL1);
    }

} /* END PUBLIC CLASS */

А вот его скриншот в действии:

enter image description here

24 голосов
/ 05 декабря 2008

@ Софт Обезьяна:

Это работает! :)

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

public class Main{
    public static void main( String [] args ) throws InterruptedException  {
        JFrame frame = new JFrame();
        frame.add( new JLabel(" Outout" ), BorderLayout.NORTH );

        JTextArea ta = new JTextArea();
        TextAreaOutputStream taos = new TextAreaOutputStream( ta, 60 );
        PrintStream ps = new PrintStream( taos );
        System.setOut( ps );
        System.setErr( ps );


        frame.add( new JScrollPane( ta )  );

        frame.pack();
        frame.setVisible( true );
        frame.setSize(800,600);

        for( int i = 0 ; i < 100 ; i++ ) {
            System.out.println( i );
            Thread.sleep( 500 );
        }
    }
}
4 голосов
/ 17 октября 2012

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

Вот (возможно) более чистый способ сделать то, что опубликовала программная обезьяна:

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;

import javax.swing.JTextArea;

/**
 * Represents a console viewable through a <code>JTextArea</code>.
 * 
 * <p>
 *  Implementation:
 *  <code>
 *      System.setOut(new PrintStream(new Console( ... )));
 *  </code>
 *  </p>
 * 
 * @author Derive McNeill
 *
 */
public class Console extends OutputStream {

    /**
     * Represents the data written to the stream.
     */
    ArrayList <Byte> data = new ArrayList <Byte> ();

    /**
     * Represents the text area that will be showing the written data.
     */
    private JTextArea output;

    /**
     * Creates a console context.
     * @param output
     *      The text area to output the consoles text.
     */
    public Console(JTextArea output) {
        this.output = output;
    }

    /**
     * Called when data has been written to the console.
     */
    private void fireDataWritten() {

        // First we loop through our written data counting the lines.
        int lines = 0;
        for (int i = 0; i < data.size(); i++) {
            byte b = data.get(i);

            // Specifically we look for 10 which represents "\n".
            if (b == 10) {
                lines++;
            }

            // If the line count exceeds 250 we remove older lines.
            if (lines >= 250) {
                data = (ArrayList<Byte>) data.subList(i, data.size());
            }
        }

        // We then create a string builder to append our text data.
        StringBuilder bldr = new StringBuilder();

        // We loop through the text data appending it to the string builder.
        for (byte b : data) {
            bldr.append((char) b);
        }

        // Finally we set the outputs text to our built string.
        output.setText(bldr.toString());
    }

    @Override
    public void write(int i) throws IOException {

        // Append the piece of data to our array of data.
        data.add((byte) i);

        // Indicate that data has just been written.
        fireDataWritten();
    }

}
2 голосов
/ 10 ноября 2012

ByteArrayOutputStream можно использовать для исключения буферизации.

private void redirectConsoleTo(final JTextArea textarea) {
    PrintStream out = new PrintStream(new ByteArrayOutputStream() {
        public synchronized void flush() throws IOException {
            textarea.setText(toString());
        }
    }, true);

    System.setErr(out);
    System.setOut(out);
}

Вместо ограничения номера строки вы можете связать ByteArrayOutputStream # reset () с какой-либо кнопкой.

private void redirectConsoleWithClearButton(final JTextArea textarea, JButton clearButton) {
    final ByteArrayOutputStream bytes = new ByteArrayOutputStream() {
        public synchronized void flush() throws IOException {
            textarea.setText(toString());
        }
    };

    clearButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            bytes.reset();
        }
    });

    PrintStream out = new PrintStream(bytes, true);

    System.setErr(out);
    System.setOut(out);
}
1 голос
/ 02 января 2015

Я недавно использовал отличный код , предоставленный Лоуренсом Долом в одном из моих проектов.

Однако в моем случае код занимал слишком много памяти. Мне удалось резко сократить потребление памяти, заменив JTextarea на JLabel.

Мои поиски экономии памяти показали, что внутренний код JTextarea имеет тенденцию удерживать фактический текст, отправленный слишком много времени. Следовательно, весь этот текст нельзя было собрать мусором.

Вот гибкая версия исходного кода (с синхронизацией потоков, замененной блокировками).

JComponentOutputStream.java

import java.awt.EventQueue;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import javax.swing.JComponent;

public class JComponentOutputStream extends OutputStream {

    // *************************************************************************************************
    // INSTANCE MEMBERS
    // *************************************************************************************************

    private byte[] oneByte; // array for write(int val);
    private Appender appender; // most recent action

    private Lock jcosLock = new ReentrantLock();

    public JComponentOutputStream(JComponent txtara, JComponentHandler handler) {
        this(txtara, 1000, handler);
    }

    public JComponentOutputStream(JComponent txtara, int maxlin, JComponentHandler handler) {
        if (maxlin < 1) {
            throw new IllegalArgumentException("JComponentOutputStream maximum lines must be positive (value=" + maxlin + ")");
        }
        oneByte = new byte[1];
        appender = new Appender(txtara, maxlin, handler);
    }

    /** Clear the current console text area. */
    public void clear() {
        jcosLock.lock();
        try {
            if (appender != null) {
                appender.clear();
            }
        } finally {
            jcosLock.unlock();
        }
    }

    public void close() {
        jcosLock.lock();
        try {
            appender = null;
        } finally {
            jcosLock.unlock();
        }
    }

    public void flush() {
        // sstosLock.lock();
        // try {
        // // TODO: Add necessary code here...
        // } finally {
        // sstosLock.unlock();
        // }
    }

    public void write(int val) {
        jcosLock.lock();
        try {
            oneByte[0] = (byte) val;
            write(oneByte, 0, 1);
        } finally {
            jcosLock.unlock();
        }
    }

    public void write(byte[] ba) {
        jcosLock.lock();
        try {
            write(ba, 0, ba.length);
        } finally {
            jcosLock.unlock();
        }
    }

    public void write(byte[] ba, int str, int len) {
        jcosLock.lock();
        try {
            if (appender != null) {
                appender.append(bytesToString(ba, str, len));
            }
        } finally {
            jcosLock.unlock();
        }
    }

    static private String bytesToString(byte[] ba, int str, int len) {
        try {
            return new String(ba, str, len, "UTF-8");
        } catch (UnsupportedEncodingException thr) {
            return new String(ba, str, len);
        } // all JVMs are required to support UTF-8
    }

    // *************************************************************************************************
    // STATIC MEMBERS
    // *************************************************************************************************

    static class Appender implements Runnable {
        private final JComponent swingComponent;
        private final int maxLines; // maximum lines allowed in text area
        private final LinkedList<Integer> lengths; // length of lines within
                                                    // text area
        private final List<String> values; // values waiting to be appended

        private int curLength; // length of current line
        private boolean clear;
        private boolean queue;

        private Lock appenderLock;

        private JComponentHandler handler;

        Appender(JComponent cpt, int maxlin, JComponentHandler hndlr) {
            appenderLock = new ReentrantLock();

            swingComponent = cpt;
            maxLines = maxlin;
            lengths = new LinkedList<Integer>();
            values = new ArrayList<String>();

            curLength = 0;
            clear = false;
            queue = true;

            handler = hndlr;
        }

        void append(String val) {
            appenderLock.lock();
            try {
                values.add(val);
                if (queue) {
                    queue = false;
                    EventQueue.invokeLater(this);
                }
            } finally {
                appenderLock.unlock();
            }
        }

        void clear() {
            appenderLock.lock();
            try {

                clear = true;
                curLength = 0;
                lengths.clear();
                values.clear();
                if (queue) {
                    queue = false;
                    EventQueue.invokeLater(this);
                }
            } finally {
                appenderLock.unlock();
            }
        }

        // MUST BE THE ONLY METHOD THAT TOUCHES the JComponent!
        public void run() {
            appenderLock.lock();
            try {
                if (clear) {
                    handler.setText(swingComponent, "");
                }
                for (String val : values) {
                    curLength += val.length();
                    if (val.endsWith(EOL1) || val.endsWith(EOL2)) {
                        if (lengths.size() >= maxLines) {
                            handler.replaceRange(swingComponent, "", 0, lengths.removeFirst());
                        }
                        lengths.addLast(curLength);
                        curLength = 0;
                    }
                    handler.append(swingComponent, val);
                }

                values.clear();
                clear = false;
                queue = true;
            } finally {
                appenderLock.unlock();
            }
        }

        static private final String EOL1 = "\n";
        static private final String EOL2 = System.getProperty("line.separator", EOL1);
    }

    public interface JComponentHandler {
        void setText(JComponent swingComponent, String text);

        void replaceRange(JComponent swingComponent, String text, int start, int end);

        void append(JComponent swingComponent, String text);
    }

} /* END PUBLIC CLASS */

Пример использования

<code>JLabel console = new JLabel();
JComponentOutputStream consoleOutputStream = new JComponentOutputStream(console, new JComponentHandler() {
    private StringBuilder sb = new StringBuilder();

    @Override
    public void setText(JComponent swingComponent, String text) {
        sb.delete(0, sb.length());
        append(swingComponent, text);
    }

    @Override
    public void replaceRange(JComponent swingComponent, String text, int start, int end) {
        sb.replace(start, end, text);
        redrawTextOf(swingComponent);
    }

    @Override
    public void append(JComponent swingComponent, String text) {
        sb.append(text);
        redrawTextOf(swingComponent);
    }

    private void redrawTextOf(JComponent swingComponent) {
        ((JLabel)swingComponent).setText("<html><pre>" + sb.toString() + "
"); } }); PrintStream con = new PrintStream (consoleOutputStream); System.setOut (CON); System.setErr (CON); // Необязательно: добавьте панель прокрутки вокруг консоли, чтобы иметь полосы прокрутки JScrollPane sp = new JScrollPane (// приставка, // ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, // ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED // ); myPanel.add (SP);
...