Java Terminal gui

Sp4rky

Cadet 4th Year
Registriert
März 2019
Beiträge
77
hallöchen
ich bin gerade dabei ein kleines gui zu basteln was sich optional in eine meiner anwendungen als terminal einpassen soll (wenn grad keins da ist). dafür würde ich gern als ausgabe system.out und system.err darstellen (ggf auch noch eine kopie von system.in) und über eine eingabe dinge an system.In füttern.
ich bin soweit bereits gekommen, dass ich die ausgaben von out und err angezeigt bekomme, leider habe ich keine ahnung wie ich text an in übergebe. (wird ja sicherlich so ähnlich funktionieren, nur gibt es da ein get(bytes) oder so etwas?)
Der Code sieht aktuell so aus:
Java:
public class Terminal extends JFrame{

    private JTextArea outtextArea;

    public Terminal(){
        try{
            JFrame frame = new JFrame();

            //Output
            outtextArea = new JTextArea();
            outtextArea.setFont(new Font("monospaced", Font.ITALIC, 12));
            outtextArea.setEnabled(false);
            outtextArea.setBackground(Color.BLACK);
            outtextArea.setForeground(Color.WHITE);
            outtextArea.setBorder(BorderFactory.createEmptyBorder());
            //
            PrintStream printStream1 = new PrintStream(new CustomOutputStream(outtextArea)); //Stream
            System.setOut(printStream1);
            System.setErr(printStream1);
            JScrollPane jsp = new JScrollPane(outtextArea);
            frame.add(jsp);
           
            //Input
            JTextField input = new JTextField();
            input.setBackground(Color.BLACK);
            input.setForeground(Color.WHITE);
            input.setBorder(BorderFactory.createEmptyBorder());
            frame.add(input, BorderLayout.SOUTH);


            frame.pack();
            frame.setSize(1900,1050);
            frame.setExtendedState(frame.getExtendedState() | JFrame.MAXIMIZED_BOTH);
            frame.getContentPane().setBackground(Color.BLACK);
            frame.setVisible( true );


            input.addActionListener(new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e){
                    String in = input.getText();

                     input.setText(null);

                }
            });

        }catch (Exception e){
            System.err.println(e);
        }
    }

    public void clear(){
        outtextArea.setText(null);
    }
}
CustomOutputStream
Java:
public class CustomOutputStream extends OutputStream {
    private JTextArea textArea;

    public CustomOutputStream(JTextArea textArea) {
        this.textArea = textArea;
    }

    @Override
    public void write(int b) throws IOException {
        textArea.append(String.valueOf((char)b));
        textArea.setCaretPosition(textArea.getDocument().getLength());
    }
}
 
Zuletzt bearbeitet:
New Scanner(System.in)
 
danke für die antwort,
allerdings bin ich mir nicht ganz sicher wie mir das weiter helfen soll.
scanner wird doch benutzt um aus einem inputstream daten auszulesen und nicht daten in einen inputstream zu schreiben?
ich würde ja gern mit dem jtextfield das gleiche verhalten erzeugen wie bei einem scanner im terminal, nur das der scanner irgendwo im code sitzt und unabhängig davon ist ob nun mein gui läuft oder doch irgend ein terminal.
 
Du kannst in einem INput stream keine Daten AUSgeben. Du musst dir analog zum CustomOutputStream einen CustomInputStream erstellen.
 
irgendwie bekomme ich nicht das gleiche verhalten hin welches ich erwarten würde von system.in.
wenn ich das ganze mit einem scanner teste
Java:
public static void main(String[]args){
    try{
        new Terminal();
        Scanner scanner = new Scanner(System.in);
        System.out.println(scanner.nextLine());
    }catch (Exception e){
        e.printStackTrace();
    }
}
bekomme ich eine nosuchelement exception anstelle das auf eine eingabe gewartet wird.
meine inputstream erstelle ich in terminal() und setze ihn dann als system.in
Java:
public class CustomInputStream extends InputStream {

    private List<Integer> integerList = new ArrayList<Integer>();

    CustomInputStream(JTextField textField) {
        textField.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                if(e.getKeyChar()=='\n'){
                    for(char a : textField.getText().toCharArray()){
                        integerList.add((int)a);
                    }
                    textField.setText("");
                }
                super.keyReleased(e);
            }
        });
    }

    @Override
    public int read() throws IOException {
        if(!integerList.isEmpty()){
            return integerList.remove(0);
        }
        return -1;
    }
irgendwo muss also noch ein fehler sein den ich nicht sehe
 
Du musst vermutlich vorher mit hasNextLine() testen, ob es Eingaben gibt.
 
das lässt den fehler zwar verschwinden, allerdings scheint die bedingung nie erfüllt zu sein, da aus system.in nichts raus zu bekommen ist. zudem verhält sich das ganze ja dann auch anders als würde ich es mit nem terminal starten anstelle meines guis
evtl erstelle ich den stream nicht richtig oder gebe ihn falsch weiter?
Java:
InputStream is = new CustomInputStream(input);
System.setIn(is);
 
Zuletzt bearbeitet:
Sp4rky schrieb:
da aus system.in nichts raus zu bekommen ist.
Hast du denn auch was in des Textfeld eingegeben? Musst du evtl. noch '\n' zusätzlich in deine ArrayList packen, damit der Scanner das als Zeile erkennt?
 
Die read Methode muss blockieren, wenn keine Eingabe vorhanden ist. Das erreicht man am einfachsten mit einer BlockingQueue.
Java:
BlockingQueue<Integer> queue = new LinkedBlockingQueue<>();

...
    
// die read Methode sieht dann so aus
public int read() throws IOException {
    try {
        return queue.take();
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
    return -1;
}
 
ah danke, dass bringt mich doch ein ganzes stück näher an eine lösung :)
so gibt system.in.read schon mal etwas zurück, allerdings mag der scanner noch nicht so ganz. zwar bekomme ich keinen fehler mehr angezeigt, aber leider auch keine ausgabe. also es hängt bei scanner.next-line-() fest, unabhänig davon das ich etwas eingebe
 
Ok, der Scanner verwendet einen InputStreamReader mit internem Puffer. Dann muss man zusätzlich noch die andere read Methode implementieren, damit nicht erst gelesen werden muss bis der Puffer voll ist.
Code:
@Override
public int read(byte[] b, int off, int len) throws IOException {
    return super.read(b, off, 1);
}
Ergänzung ()

Die eleganteste Lösung bekommt man aber vermutlich bei Verwendung von Piped Streams.
Hier ist das komplette Beispiel:
Java:
public class Piped {
    public static void main(String[] args) throws Exception {
        JFrame f = new JFrame("Piped");
        JTextField tf = new JTextField(40);
        f.getContentPane().add(BorderLayout.CENTER, tf);
        f.pack();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
        PipedInputStream pis = new PipedInputStream();
        PipedOutputStream pos = new PipedOutputStream(pis);
        System.setIn(pis);
        tf.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    pos.write(tf.getText().getBytes());
                    pos.write(10);
                    pos.flush();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                tf.setText("");
            }
        });
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()){
            System.out.println(scanner.nextLine());
        }
    }
}
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Sp4rky
vielen dank
wie einfach lösungen doch sein können wenn man weiß was man benötigt überrascht mich doch immer wieder
 

Ähnliche Themen

Antworten
10
Aufrufe
1.088
Antworten
5
Aufrufe
4.240
Zurück
Oben