Swing Thread für CMD auslesen

sandaime

Mitglied
Hallo liebe community,

ich habe eine Methode erstellt, was eine exe startet, welches in der Konsole läuft. Im weiteren wird in die Konsole ein Pfad eingegeben, womit dann das Programm eine Berechnung startet. Die Werte für die Berechnung entnimmt die Exe einer txt Datei. Naja das Problem hierbei ist, dass ich die Konsolenausgabe mir in die eine TextArea ausgeben will und das natürlich in Echtzeit.
Mit meiner Methode funktioniert die Ausgabe in der Konsole von Eclipse, aber nicht in meiner TextArea und ich habe zurzeit überhaupt keine Idee wieso. Nun habe ich nur noch wenig Zeit für meine Bachelorarbeit und stehe unter Druck. Ich hoffe ihr könnte mir aktiv helfen.

Danke an alle dir mir helfen und an die die sich wenigstens das Problem durchlesen 🙂



Code:
private void KonsoleEingabe(boolean neustart) {

        String austalPfad = cf.pathToAustalExe;
        String austalDirectory = curProjektPfad.split("austal2000.txt")[0];


        if (curProjektPfad == null) {
            JOptionPane.showMessageDialog(this, "Es ist kein Projekt ausgewählt oder erstellt worden!");
        } else {
            // TODO Thread einbauen
            // ProcessBuilder auf thread umstellen und asynchron in das TextFeld ergebnisAusgabe schrieben mittels .append
            // Siehe JavaCommandLineWrapperExample Zeile 80ff.
            ProcessBuilder builder = null;
            if( neustart ){
                builder = new ProcessBuilder(austalPfad,"-D", austalDirectory);
            } else {
                builder = new ProcessBuilder(austalPfad, austalDirectory);
            }
           
            builder.redirectErrorStream(true);
            Process p = null;
            try {
                p = builder.start();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String line = null;
            while (true) {
                try {
                    line = r.readLine();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                if (line == null) {
                    break;
                }
                //ergebnisAusgabe.append(line);
                ergebnisAusgabe.setText(line);
                System.out.println(line);
            }
        }
    }
 
Mhh, das einzige, das mir gerade einfällt ist nur die Zeile " ergebnisAusgabe.setText(line);"
Versuch mal ergebnisAusgabe.setText(ergebnisAusgabe.getText()+"\n"+line); oder ergebnisAusgabe.append("\n"+line);
(Wenn das eine Bachelorabeit ist, möchtest du vielleicht die Java-Coding-Conventions einhalten und Methoden klein schreiben...)
 
Hallo,
danke für die Antwort. Das mit den Methodennamen stimmt. Sonst sind das nur Gründe für eine schlechtere Note. Leider funktioniert dein Vorschlag nicht.
 
Zeig mal bitte, wie #KonsoleEingabe aufgerufen wird

(Wenn ich raten müsste, würde ich drauf sagen, dein TODO fixt es...)
 
Zuletzt bearbeitet:
Wieder einmal danke für die Antworten. Hier ist der Code zum Aufrufen der Methode.
--> JCODA dein Vorschlag hat leider nicht funktioniert.
Ich etwas im Internet gefunden ich glaube das ist die Lösung für mein Problem jedoch schaffe ich es nicht ganz in mein Code einzubinden. Davon den Code poste ich auch mal

Code:
case ("Starte Austal2000"):
           
            String[] values = {"Normal Starten", "Lösche vorherige Daten und starte neu"};

            Object selected = JOptionPane.showInputDialog(null, "Wie möchten sie das Projekt starten?", "Startauswahl", JOptionPane.DEFAULT_OPTION, null, values, "0");
            if ( selected != null ){//null if the user cancels.
                String selectedString = selected.toString();
                if(selectedString.equals("Normal Starten")){
                    this.konsoleEingabe(false);
                }else{
                    this.konsoleEingabe(true);
                }
                //do something
            }else{
                System.out.println("User cancelled");
            }

            break;

Code:
import java.util.concurrent.Executors;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class JavaCommandLineWrapperExample extends JFrame {
    
      JTextArea txtConsole;
      JTextField txtCommand;
    
      public JavaCommandLineWrapperExample() {
        super("JavaCommandLineWrapperExample");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    
        txtConsole = new JTextArea(20, 80);
        txtCommand = new JTextField(80);
    
        txtConsole.setEditable(false);
    
        JScrollPane scrollPane = new JScrollPane(txtConsole);
    
        add(scrollPane);
        add(txtCommand, BorderLayout.SOUTH);
    
        pack();
        setVisible(true);
    
        startShell();
      }
    
    
      void startShell() {
        ProcessBuilder processBuilder = new ProcessBuilder("cmd.exe").redirectErrorStream(true);
    
        try {
          final Process process = processBuilder.start();
          final PrintWriter processInput = new PrintWriter(process.getOutputStream());
          captureProcessOutput(process);
          txtCommand.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
              processInput.println(txtCommand.getText());
              processInput.flush();
              txtCommand.setText("");
            }
          });
    
          int exitCode = process.waitFor();
          System.exit(exitCode);
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    
    
      void captureProcessOutput(final Process process) {
        Executors.newSingleThreadExecutor().execute(new Runnable() {
          @Override
          public void run() {
            try {
              char c = (char)-1;
              InputStream processOutput = process.getInputStream();
              while ((c = (char) processOutput.read()) != -1) {
                txtConsole.append(String.valueOf(c));
                txtConsole.setCaretPosition(txtConsole.getText().length());
              } 
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
        });
      }
 
Du startest deine Methode innerhalb des AWT-Thread (also aus #actionPerformed oä)?
Dann blockiert die gesamte GUI (und damit auch das aktualisieren des Textes), bis die Methode zurückkehrt.

Wenn du dein TODO umsetzt (was man bei einer BA durchaus können sollte), dürfte es laufen 😉
Was verstehst du denn an dem gefundenem Code nicht?
 
Naja, meine Frage war keine "Lösung" sondern, falls dort nichts ausgegeben wird, muss man an anderer Stelle suchen als bei dem TextField...
Vielleicht braucht das Programm ein bisschen Zeit, bis die Ausgabe erscheint, deshalb würde ich mal versuchen zu warten.
Versuch mal:

Java:
private void KonsoleEingabe(boolean neustart) {

        String austalPfad = cf.pathToAustalExe;
        String austalDirectory = curProjektPfad.split("austal2000.txt")[0];


        if (curProjektPfad == null) {
            JOptionPane.showMessageDialog(this, "Es ist kein Projekt ausgewählt oder erstellt worden!");
        } else {
            // TODO Thread einbauen
            // ProcessBuilder auf thread umstellen und asynchron in das TextFeld ergebnisAusgabe schrieben mittels .append
            // Siehe JavaCommandLineWrapperExample Zeile 80ff.
            ProcessBuilder builder = null;
            if( neustart ){
                builder = new ProcessBuilder(austalPfad,"-D", austalDirectory);
            } else {
                builder = new ProcessBuilder(austalPfad, austalDirectory);
            }
         
            builder.redirectErrorStream(true);
            Process p = null;
            try {
                p = builder.start();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String line = null;
            int k=0;
            while (true) {
                try{
                    Thread.sleep(1000);
                }catch(Exception e){
                     e.printStackTrace();
                }
                try {
                    line = r.readLine();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                if (line == null) {
                    k++;
                    if(k==5){
                        break;
                    }
                }else{               
                   ergebnisAusgabe.append(line);
                   System.out.println(line);
                 }
            }
        }
    }
 
Hi,
mrBrown du hast Recht. Diesen schuh ziehe ich mir selber an. Was ich an dem Code nicht verstehe ist warum er das auslesen mit dem Thread in einer anderen Methode macht. Aber ich glaube dass ich mit der Vorlage mein Problem lösen sollte.

JCODA das programm arbeitet jetzt zwar langsamer, aber die Ausgabe findet nur in der Eclipse Konsole statt.

Danke für eure antworte 🙂
 
Was ich an dem Code nicht verstehe ist warum er das auslesen mit dem Thread in einer anderen Methode macht. Aber ich glaube dass ich mit der Vorlage mein Problem lösen sollte.
Da es sonst im AWT-Thread läuft, und diesen blockiert, sodass nichts mehr an der GUI aktualisiert werden kann.
Läuft das in einem eigenen Thread, passiert das nicht, weil beide gleichzeitig laufen und der AWT-T. kann seine GUI aktualisieren (was dann aber mit #invokeLater passieren sollte)
 
Ich habe hier die Lösung. An dieser Stelle noch ein besonderer Dank an MrBrown. Dein Tipp was in der Methode von dem anderen Code passiert war der Auslöser dafür, dass ich wusste wie ich das für mein Problem nutze.
Wie zu sehen ist rufe ich die methode auslese() in der methode konsoleEingabe(), das muss so sein weil Swing probleme bei solchen sachen hat. Für genaueres siehe --> http://openbook.rheinwerk-verlag.de...19_026.htm#mjff97f42688ce8483476fd5597042a972.

Code:
public void konsoleEingabe(boolean neustart) {

        String austalPfad = cf.pathToAustalExe;
        String austalDirectory = curProjektPfad.split("austal2000.txt")[0];


        if (curProjektPfad == null) {
            JOptionPane.showMessageDialog(this, "Es ist kein Projekt ausgewählt oder erstellt worden!");
        } else {
            ProcessBuilder builder = null;
            if( neustart ){
                builder = new ProcessBuilder(austalPfad,"-D", austalDirectory);
            } else {
                builder = new ProcessBuilder(austalPfad, austalDirectory);
            }
          
            builder.redirectErrorStream(true);
            Process p = null;
            try {
                p = builder.start();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
          auslesen(p); 
        }
    }
   
    
    // Ein Thread ist noetig in Swing nutzung weil sonst die GUI blockiert wird
    // deswegen laeuft die Methode seperat
     void auslesen(final Process p) {
    Executors.newSingleThreadExecutor().execute(new Runnable() {
    public void run(){
         BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
         String line = null;
         while (true) {
             try {
                 line = r.readLine();
                
             } catch (IOException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
             if (line == null) {
                 break;
             }
             ergebnisAusgabe.append(line+"\r\n");
         }
     }
});
}
 
Kleine Anmerkung noch, ergebnisAusgabe.append(line+"\r\n"); sollte mit SwingUtilities.invokeLater ausgeführt werden, GUI-Änderungen müssen immer im passenden Thread ausgeführt werden 😉
 

Neue Themen


Zurück
Oben