Runtime.getRuntime().exec Frage

DoubleM

Neues Mitglied
Hallo, ich habe eine kleine grafische Benutzeroberfläche zur Erzeugung von CAD Datein entwickelt. Diese liest die Bauteilparameter üer Textfelder ein und speichert diese anschließend in Textdateien. Mit dem Befehl
Code:
Process createfile = Runtime.getRuntime().exec("bin\\stl_CreatorV1\\OpenSCAD\\openscad.com -o "+path+"  bin\\stl_CreatorV1\\Scad-Files\\AR_Typ2.scad");
rufe ich die Datei openscad.com zur Erstellung der CAD Datei auf. Ich habe in meinem Programm eine JTextArea als Logfeld. Ich möchte nachdem ich den Speicherort für die CAD Datei ausgewählt habe und auf den Button zum Erstellen der Datei geklickt habe, die Meldung "CAD Datei wird erstellt, bitte warten!" im Logfeld ausgeben. Leider wird diese Meldung zu spät ausgegeben, erst nachdem die CAD Datei erstellt wurde. Obwohl ich diese Meldung vor dem Erstellen der CAD Datei eingefügt habe, wird diese immer danach ausgegeben. Kann mir jemand dabei helfen das Problem zu lösen? Anbei ein Ausschnitt meines Codes:
Vielen Dank,
Gruß
Markus


Java:
try {
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File("D:\\STL-Dateien\\"));
chooser.setFileFilter(new FileNameExtensionFilter("*.stl Dateien", "stl"));
chooser.setSelectedFile(new File("Bauteilname"));
int retval=  chooser.showSaveDialog(chooser);

if(retval == JFileChooser.APPROVE_OPTION)
{
 logfield.append("STL Datei wird erstellt,\ndieser Vorgang kann bis zu 2 Minuten dauern, bitte warten...\n");
 
 String path = "\""+chooser.getSelectedFile().getAbsolutePath()+".stl"+"\"";
 
Process createfile = Runtime.getRuntime().exec("bin\\stl_CreatorV1\\OpenSCAD\\openscad.com -o "+path+"  bin\\stl_CreatorV1\\Scad-Files\\AR_Typ2.scad");   
 
try {

    createfile.waitFor();


if (createfile.exitValue() == 0) //Erfolgreiche Ausführung
 {
    logfield.append("CAD Datei erfolgreich erzeugt\n");
    
 }
 else //Misslungene Ausführung
 {
    logfield.append("Fehler bei Erstellung der CAD Datei\n");
 }
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}


}
else
{
 logfield.append("Abbruch...\n");
}
 
Erst einmal zum Verständnis des Problems:
So eine GUI Applikation ist Event gesteuert. Wenn Du bei einem Controll eine Eigenschaft änderst, die das Aussehen betrifft, dann wird zum einen der interne Wert angepasst. Das ändert aber noch nichts bei der Anzeige! Daher kommt noch zum Anderen ein weiteres Event hinzu: Es wird nur ein Event erzeugt und in die Schlange der Events gestellt, das die Applikation auffordert, sich bzw. das Control neu zu malen. Das wird oft als PAINT oder WM_PAINT bezeichnet (wenn man z.B. in die Windows UI Entwicklung einsteigt in C oder C++, dann findet man diese Konstante WM_PAINT).

Daher ist das Problem, dass Dein Code eben den ertsen Schritt macht, aber da Du ja in dem EDT - dem Event Dispatch Thread - arbeitest, kann das Event zum neu Malen nicht verarbeitet werden. Erst wenn du fertig bist mit dem aktuellen Event geht die Ausführung wieder zurück und es wird nach den nächsten Events geschaut um dann das neu malen als Event zu verarbeiten: Die Anzeige kommt also erst später.

Als Lösung dazu könnte man das z.B. in einen eigenen Thread packen. Das Ausführen und die Auswertung der Rückgabe würde somit unabhängig laufen. Die Eventsteuerung geht somit sofort zurück und die Applikation kann sich selbst wieder malen. Das ist bei allen Dingen wichtig, die etwas Zeit brauchen können, denn in der Zeit, wo das derzeit läuft, reagiert die Applikation ja auf keinerlei Events!

Wenn Du in einen eigenen Thread wechselst: Controls sind nicht Thread sicher! Eine Änderung an Controls soll aber nur aus dem EDT heraus erfolgen! In Swing gibt es den SwingUtilities mit invokeLater - damit kann man dann auch so Dinge ändern.

Also vermutlich bei dir etwas wie:
SwingUtilities.invokeLater( () -> logfield.append(...) );

(Als Parameter wird ein Runable benötigt und das wird hier in Form einer Lambda Expression erzeugt.)
 

Zurück
Oben