Swing vs Konsole

Status
Nicht offen für weitere Antworten.

zu1u

Mitglied
Hallo zusammen,
ich habe eine Anwendung mit einer Swing Gui zu der ich jetzt noch eine Konsole hinzugefuegt habe. Ich dachte nicht das es dabei grosse Komplikationen geben wuerde. Die Konsole laeuft logischerweise in einem eigenen Thread.

Problem ist jetzt folgendes:
Starte ich die GUI vor der Konsole, dann haengt sich die GUI unter dem Arbeiten mit ihr auf.
Starte ich Konsole vor GUI, dann kriege ich die GUI nicht angezeigt bevor ich einen Befehl auf der Konsole ausgefuehrt habe.

Ich habe gelesen, dass es Probleme macht wenn 2 Threads um eine Ressource (hier system.out) konkurrieren?! (die gui macht auch system.out.prints)

Kann mir jemand sagen wie ich das Problem moeglichst einfach in den Griff bekomme?

danke
 
Was bedeutet denn "eine Konsole"? Ist das ein anderes Swing-Fenster oder wie muss ich das verstehen? Hängt die Konsolae an System.out, System.err und System.in? Das lässt sich für mich nicht einfach so aus Deiner Beschreibung nehmen. Kannst Du den Code für die Konsole (ggf. vereinfacht) ins Forum posten, so dass man eine bessere Idee davon bekommt?

Ebenius
 
ja sorry, die haengt am System.out

der code sieht grob so aus



[highlight=Java]

public final class Console implements Runnable{

private MyApp myApp;

private enum Command{
COMMAND
};

public Console (MyApp myApp){
this.MyApp =myApp ;
}

public void run(){
try{
readInputs();
}
catch (Exception e){
System.out.println(e);
}
}

private void readInputs() throws Exception{

InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);

Command command = null;

while (true){
System.out.print("Console> ");

try{
command = Command.valueOf(br.readLine().);

switch (command){
case COMMAND:
System.out.println("Hallo");
default:
System.out.println("Befehl nicht gefunden");
}
}
catch (IllegalArgumentException e){
System.out.println("Befehl nicht gefunden");
}
}
}
}

[/highlight]
 
Vor allem blockiert die Konsole den System.in. Wenn jemand anderes davon lesen will, muss der warten, bis Zeile 33 einmal zurückkehrt (also wenn jemand ENTER drückt). Und selbst dann ist nicht sichergestellt, dass der andere dran kommt; könnte auch wieder der Quelltext in der Konsole sein. Ergo: Vom System.in kann gleichzeitig nur einer lesen.

// EDIT: Das Thema hat mit Swing nix zu tun. Verschoben.

Ebenius
 
Thread benutzen...

Code:
import java.io.BufferedReader;
import java.io.InputStreamReader;

import javax.swing.JFrame;
import javax.swing.JLabel;



public final class Console implements Runnable{
   
   public static void main(String[] args) {
      
      MyApp app = new MyApp();
      Console cons = new Console(app);
      
      Thread t = new Thread(cons);
      t.start();
   }
   
   private MyApp myApp;


   public Console (MyApp myApp){
       this.myApp =myApp ;
   }

   public void run(){
       try{
           readInputs();
       }
       catch (Exception e){
           System.out.println(e);
       }
   }

   private void readInputs() throws Exception{

       InputStreamReader isr = new InputStreamReader(System.in);
       BufferedReader br = new BufferedReader(isr);

       String command = null;
       
       while (true){
           System.out.print("Console> ");

           try{
               command = br.readLine();
               myApp.setInfo(command);
               
           }
           catch (IllegalArgumentException e){
               System.out.println("Befehl nicht gefunden");
           }
       }
   }
}

class MyApp extends JFrame{
   
   JLabel text;
   public MyApp() {
      this.setSize(200, 200);
      text = new JLabel();
      this.add(text);
      this.setVisible(true);
   }
   
   public void setInfo(String info) {
      this.text.setText(info);
      System.out.println("text gesetzt "+info);
   }
   
   
   
}

das soll mal die grundlegende funktionsweise zeigen...
 
ARadauer, ich glaub das geht am Thema vorbei. Die Konsole wird schon über einen anderen Thread gestartet. Das Problem ist, dass hier zwei Stränge sich um den Lock auf System.in kloppen.

Ebenius
 
@ARadauer: so aehnlich schaut es bei mir auch aus.. die Konsole ist bereits ein Thread

@Ebenius: Es liest aber eigentlich nur die Konsole von System.in , daher sollte das doch ok sein oder? Nur System.out nutzen sie eigentlich beide
 
@Ebenius: Es liest aber eigentlich nur die Konsole von System.in , daher sollte das doch ok sein oder? Nur System.out nutzen sie eigentlich beide
Das würde ich an Deiner Stelle nochmal prüfen, weil die Erklärung erstklassisch zu Deiner Fehlerbeschreibung passt. 🙂 An System.out kann ich nichts kritisches erkennen. Schreib doch mal um die readline-Zeile ...[HIGHLIGHT="Java"]synchronized (System.in) {
...
}[/HIGHLIGHT]
... Starte dann mal im Debugger (Eclipse leistet), mach Dir einen Breakpoint in die readline-Zeile, und schau, auf welchen Lock der andere Thread wartet.

Ebenius
 
Zuletzt bearbeitet:
sorry ich hab den debugger bisher nicht wirklich benutzt,
wo seh ich denn auf welchen lock ein thread wartet?!

Fuer den Console.readInputs() Eintrag im 'Debug' Fenster bekomme ich bei den Variables einen Eintrag 'lock InputStreamReader' .. fuer die anderen Threads im Debug fenster bekomm ich gar keine Variables angezeigt... wie gesagt ich kenn mich da nicht so aus 😳

allerdings denke ich jetzt das du recht hast. Ich habe z.b. ein Textfeld auf der gui, dass ja moeglicherweise auf System.in noch zugreifen will....

also davon ausgehend, wie komm ich aus der misere?!? ???:L
 
Die GUI-Komponenten bekommen Ihre Eingaben nicht vom stdin. An einem normalen Textfeld sollte es also nicht hängen.

sorry ich hab den debugger bisher nicht wirklich benutzt, [...]
Dann wird's aber Zeit. 🙂

Wie man einen Breakpoint setzt weißt Du sicher oder findest es einfach heraus. Starte Deine Anwendung nicht mit "Run", sondern mit "Debug". Lass die Anwendung laufen, bis sie am Breakpoint anhält. In der Debug-Perspektive im Eclipse hast Du oben links eine View "Debug" die einen Baum aller Threads Deiner Anwendung beinhaltet. Den angehaltenen Thread kannst Du anhand optisch von den anderen unterscheiden. Nun such Dir aus dem Baum den zweiten Thread heraus; wir vermuten erstmal, dass Du den Event Dispatch Thread lahm gelegt hast. Den hältsts Du an, mit Rechtsklick "Suspend".

[...] wo seh ich denn auf welchen lock ein thread wartet?!

In den Einstellungen der Debug-View (ungefähr rechte obere Ecke, weißes Dreieck nach unten) kannst Du "Java" » "Show Monitors" auswählen. Alle Monitors (das sind die Objekte die mit dem synchronized-Schlüsselwort synchronisiert werden) werden an den angehaltenen Thread angezeigt; entweder mit "owns: ObjectBlablabla (id=0815)" (der Thread hat den Lock auf den Monitor erhalten) oder mit "waiting for: ObjectBlablabla (id=0815)" (der Thread wartet, dass ein anderer den Lock auf den Monitor freigibt).

Probier's mal aus. 🙂

Ebenius
 
ah danke!

also ich krieg jetzt angezeigt dass der Konsole Thread: owns: BufferedInputStream (id=22)
der Thread [AWT-Shutdown]: waiting for Object (id=42)
der Thread [AWT-EventQueue-0]: waiting for: EventQueue (id = 52)

sonst habe ich keine owns/wait for gefunden

kannst du mir mit der info nochmal weiterhelfen?
 
Zuletzt bearbeitet:
Eigenartig. Wenn Du alles richtig überprüft hast, dann ist die Vermutung mit dem Lock auf System.in falsch. Woher könnte denn sonst das Verhalten kommen, dass die restliche GUI sich erst aufbaut, wenn Du in der Konsole ENTER drückst?

Mach Dir mal einen BreakPoint auf das setVisible(true) Deines GUI-Fensters. Dann starte die Anwendung, und warte ein bisschen. Wenn Du den Breakpoint schon jetzt erreichst, verstehe ich gar nix mehr...

Und dann drück ENTER und warte, bis das setVisible(true) erreicht wird. Dann kannst Du Dir den Stack in der DebugView ansehen. Überprüf halt alle Methoden im Stack, ob sie auf irgendetwas gewartet haben.

Ebenius
 
also wenn ich nur einen breakpoint beim setVisible habe, dann komme ich da auch direkt im debugen hin... ohne dass ich zuvor enter druecken muss. Am Stack kann ich an der Stelle nix auffaelliges entdecken.. nur paar 'gui starten' aufrufe..

resume ich dann an der stelle, krieg ich die gui halt noch nicht angezeigt und muss erst was in die konsole eingeben :shock:

also falls nochmal jemand hilfestellung geben kann:toll:
 
Ich verstehe's nicht. Wenn Du mal den gesamten Quellcode hast (keine Ahnung ob Du das weggeben willst / kannst / darfst), kann ich mich ja mal reinlesen. Mehr weiß ich jetzt auch nicht.

Ebenius
 
den orginal quellcode kann ich leider nicht geben.

aber probier doch mal den geposteten code von ARadauer und ersetze das JLabel durch ein JTextField

also wenn ich das bei mir hier grade mache kann ich glaube ich das reproduzieren. :lol:

Also bei mir kann ich in das Textfeld nichts reinschreiben, bis ich einmal was auf der Konsole mache

aender ich den code so dass zuerst die Konsole und dann die GUI gestartet wird dann entspricht das ziemlich genau meinem problem 😳
[highlight=Java]

import java.io.BufferedReader;
import java.io.InputStreamReader;

public final class Console implements Runnable{

public static void main(String[] args) {

MyApp app = new MyApp();

Console cons = new Console(app);

Thread t = new Thread(cons);
t.start();

app.start();


}

private MyApp myApp;


public Console (MyApp myApp){
this.myApp =myApp ;
}

public void run(){
try{
readInputs();
}
catch (Exception e){
System.out.println(e);
}
}

private void readInputs() throws Exception{

InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);

String command = null;

while (true){
System.out.print("Console> ");

try{
command = br.readLine();
myApp.setInfo(command);

}
catch (IllegalArgumentException e){
System.out.println("Befehl nicht gefunden");
}
}
}
}



import javax.swing.JFrame;
import javax.swing.JTextField;

class MyApp extends JFrame{

JTextField text;
public MyApp() {
this.setSize(200, 200);
text = new JTextField();
this.add(text);

}

public void start() {
this.setVisible(true);
}

public void setInfo(String info) {
this.text.setText(info);
System.out.println("text gesetzt "+info);
}
}
[/highlight]
 
Bei mir funktioniert der Code fehlerfrei, sowohl aus dem Eclipse als auch aus der Shell gestartet: Sun Java 6 Update 12 auf Linux.

In welcher Umgebung geht's bei Dir denn nicht?

Ebenius
 
XP Java 6 Update12 ... aus Eclipse das beschr. Problem... als runnable jar nicht mehr :applaus:
das soll mir reichen, dank dir fuer die hilfe!
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben