Swing Dialog zeigt keinen Inhalt in Verbindung mit JFrame

patrick_e

Aktives Mitglied
Hallo,
ich habe ein JFrame welches bei Klick des OK Buttons ein JDialog öffnen soll, jedoch wird nur der Leere JDialog angezeigt ohne die beeinhaltenden JLabels .
Das ist das JFrame
Java:
public class Eingabe extends JFrame {

    JTextField vonField = new JTextField();
    JTextField bisField = new JTextField();
    JLabel vonLabel = new JLabel("VON");
    JLabel bisLabel = new JLabel("BIS");
    JButton ok = new JButton("OK");
    JButton fromPickerButton = new JButton(new ImageIcon(getClass().getResource("/resources/calendar-month.png")));
    JButton toPickerButton = new JButton(new ImageIcon(getClass().getResource("/resources/calendar-month.png")));

    public Eingabe() {
//Hier wird der Eingabe Dialog erstellt
        JPanel content = new JPanel();
        //Panel wird erstellt und dem Dialog hinzugefügt
        this.add(content);
        //Panel werden Elemente hinzugefügt
        content.setLayout(new TableLayout(new double[][]{{0.4, 0.4, 0.2}, {0.25, 0.25, 0.25,}}));
        content.add(vonLabel, "0,0");
        content.add(bisLabel, "0,1");
        content.add(vonField, "1,0");
        content.add(bisField, "1,1");
        content.add(fromPickerButton, "2,0");
        content.add(toPickerButton, "2,1");
        //Bei Klick auf den von Kalender wird folgendes ausgeführt
        fromPickerButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                try {
                    pickerJDialog pjd = new pickerJDialog(vonField, Eingabe.this.fromPickerButton, null, null);
                    pjd.setVisible(true);
                } catch (RemoteException ex) {
                    Logger.getLogger(Eingabe.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
        //Bei Klick auf den bis Kalender wird folgendes ausgeführt
        toPickerButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                try {
                    pickerJDialog pjd = new pickerJDialog(bisField, Eingabe.this.toPickerButton, null, null);
                    pjd.setVisible(true);
                } catch (RemoteException ex) {
                    Logger.getLogger(Eingabe.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
        //Eigenschaften des Dialogs werden gesetzt
        this.setSize(300, 150);
        this.setResizable(false);
        centerDialog();
        content.add(ok, "1,2");
        content.setVisible(true);

        this.setTitle("Eingabe");
        //Wenn das Fenster geschlossen wird schließt auch das Programm
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getRootPane().setDefaultButton(ok);
    }
    //Funktionen
    //Gibt den von Datum zurück
    public String returnvon() {
        return vonField.getText();
    }
    //gibt das bis Datum zurück
    public String returnbis() {
        return bisField.getText();
    }
    //zentrier den Dialog auf dem Bildschirm
    private void centerDialog() {
        Dimension dim = getToolkit().getScreenSize();
        Rectangle abounds = getBounds();
        setLocation((dim.width - abounds.width) / 2,
                (dim.height - abounds.height) / 2);
    }
}
Der JDialog
Java:
public class bitteWarten extends JDialog {

    public bitteWarten() throws InterruptedException {
        JPanel panel = new JPanel();
        this.add(panel);
        JLabel label = new JLabel("Bitte warten...");
        panel.setLayout(new TableLayout(new double[][]{{TableLayout.FILL}, {TableLayout.FILL}}));
        panel.add(label,"0,0");
        this.pack();
        centerDialog();
        setVisible(true);
        Thread.sleep(5000);
    }

    private void centerDialog() {
        Dimension dim = getToolkit().getScreenSize();
        Rectangle abounds = getBounds();
        setLocation((dim.width - abounds.width) / 2,
                (dim.height - abounds.height) / 2);
    }
}

und der ActionListener in der Main Klasse
Java:
final Eingabe ei = new Eingabe();
            
            ei.setVisible(true);
//Folgender Code wird ausgeführt wenn der OK Button gedrückt wird
            ei.ok.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent ae) {
                    try {
                        SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");
                        ex.ExcelExp(2, con, sdf.parse(ei.returnvon()), sdf.parse(ei.returnbis()));
                        ex.ExcelExp(3, con, sdf.parse(ei.returnvon()), sdf.parse(ei.returnbis()));
                        con.close();
                        mail mail= new mail();
                        //mail.sendMail(to, to2, to3, to4, from, host, filename, filename2, msgText1, subject);
                       bitteWarten bwa = new bitteWarten();
                        //openDat("Montage");
                        //openDat("Produktion");
                        ei.setVisible(false);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });

Vielen Dank schon mal im Vorraus!
 
du rufst in deinen ActionListener die klasse pickerJDialog auf und nicht die klasse bitteWarten. Achso Klassen Name werden immer Groß geschrieben und ich würde immer Englische Namen nehmen:
Code:
PickerJDialog
BitteWarten
 
In der Main Klasse wird bitteWarten im ActionListener aufgerufen!!!!
Ist aber auch ganz schön merkwürdiger Code.

Warum das
Code:
Thread.sleep(5000);
im Konstruktor? Das ist da mit Sicherheit völlig falsch. Was soll das werden? Ein "Bitte warten" Dialog, der nach fünf Sekunden wieder verschwinden soll?

Fenster kann man ganz einfach mit
Code:
setLocationRelativeTo(null)
in der Mitte des Bildschirms anzeigen lassen.
 
Oh Sorry, habe ich nicht gesehen. Ich denke mal es liegt an deinem Thread.sleep. Ich denke mal du weißt das du Swing für die Anzeige deiner Elemente nutzt und Swing ein Single Threaded UI Framework ist. Der Thread der bei swing das neu zeichnen oder Abarbeitung von ActionListeners übernimmt ist der EventDispatcherThread. Da du diesen Thread für fünf Sekunden schlafen last, friert die Komplete GUI ein und kein Element kann mit dem setVisible deines Dialogs angezeigt werden. bei setVisible wird eine Reprint Event in die Queue des EventDispatcherThread eingefügt, doch dein Aktuelles Event im ActionListeners blockiert ja die Queue 5 Sekunden lang und nach dem sleep versteckst du den Dialog wieder, deswegen siehst du keine Elemente.

Versuchmal:
Java:
final bitteWarten bwa = new bitteWarten();
bwa.setVisible(true);
new Thread(){
   public void run() {
      Thread.sleep(5000);
      bwa.setVisible(false);
   }
}.start();

Und lösche den Thread.sleep und bwa.setVisible aus deinem bitteWarten. Das ist jetzt nur eine Lösung für den schnellen Test ob es am sleep liegt, aber eigentlich muss hier wieder ein Invoke in den EventDispatcherThread gemacht werden um den Dialog visible = false zusetzen.
 
Zuletzt bearbeitet:
Habe das sleep entfernt. Aber jetzt ist mir aufgefallen das das Fenster erst dann gefüllt wird wenn ein Excel Export mit der Apache POI durchgeführt wurde! Kann mir das aber nicht erklären???:L
 
Ah, Also deine actionPerformed vom ActionListener wird vom EventDispatcherThread Aufgerufen. Das heißt wenn in der actionPerformed Zeitkritische Aufgaben durchgeführt werden, wie zum beispiel das schrieben oder lesen ins Dateisystem, friert die GUI in der Zeit ein. Um das zu lösen sollte man diese Aufgaben in eine Extra Thread Auslagern der Unabhängig von der GUI die Daten Läde/schriebt und dann der GUI bescheid gibt, das die IO-Operation abgeschlossen ist. @See SwingWorkers

Das heißt für dein Problem würde ich folgenden Ablauf vorschlagen, in der actionPerformed zeigst du dein Warte Dialog an und erzeugt dann einen neuen Thread. In diesem Thread werden dann deine Exports gemacht! Sind die Exports Abgeschlossen so benachrichtigst du die GUI das der BitteWarten Dialog nicht mehr benötigt wird und zeigt Vielleicht eine weiteren Dialog an. Der Thread läuft dann zu ende und wird vom garbage collector entsorgt. Der Vorteil ist, das in der zeit wo die Exports gemacht werden deine GUI frei ist und weiter Events oder neuzeichnungen vorgenommen werden kann.
 
Hey, also ich hoffe du verstehst das ich dir jetzt hier keine Definition von Threads und wie man die in Java einsetzt schreibe, aber ich habe hier mal ein paar links. Ich würde mir zu erst mal diesen hier dürchlesen:
Galileo Computing :: Java ist auch eine Insel – 14 Threads und nebenläufige Programmierung

Gibt eine Guten Überblick was eine Thread und Prozesse sind!

Und dann würde ich mir hier das mal Durchlesen:
Threads in Java

Dort steht wie du eine Thread in java erzeugst und wieder stoppst.

Wenn du das gemacht hast, können wir gerne zusammen eine Saubere Lösung für das Problem finden
 
Zuletzt bearbeitet:
Ich habe jetzt den Bitte Warten Dialog in einen Thread gepackt aber der Inhalt dieses Dialogs wird immer noch am ende der Datenbankabfrage angezeigt.
Hier der Code wo ich den Thread erstelle...

Java:
                        Thread thread1 = new Thread() {
                            public void run() {
                                bitteWarten bw;
                                try {
                                    bw = new bitteWarten();
                                    bw.showDialog();
                                } catch (InterruptedException ex) {
                                    Logger.getLogger(Betriebsdatenerfassung.class.getName()).log(Level.SEVERE, null, ex);
                                }
                            }
                        };

                        thread1.start();
                        
                        ex.ExcelExp(2, con, sdf.parse(ei.returnvon()), sdf.parse(ei.returnbis()));
                        ex.ExcelExp(3, con, sdf.parse(ei.returnvon()), sdf.parse(ei.returnbis()));
                        con.close();
 
Ich habe jetzt den Bitte Warten Dialog in einen Thread gepackt
vs
Das heißt für dein Problem würde ich folgenden Ablauf vorschlagen, in der actionPerformed zeigst du dein Warte Dialog an und erzeugt dann einen neuen Thread. In diesem Thread werden dann deine Exports gemacht!
Die langwierige Datenbankabfrage muss aus dem EDT raus und in einem separaten Thread ausgeführt werden.

Hilfreich wäre ein kurzes und kompilierbares Beispiel Deines Problems bzw. Deines Lösungsansatzes, die Datenbankabfrage kann man ja mit einem Thread.sleep(...) simulieren.
 
Mmh ich muss leider Michael recht geben, du hast es immer noch falsch herum. Erst Dialog Anzeigen, dann Thread mit der Datenbank und Export Logik erzeuge, dann Thread starten.
 
Habe es jetzt zum Laufen gebracht, mit zwei Threads. Nur wie beende ich jetzt eine Thread im zweiten Thread, so das es am saubersten ist?
 
Äh wie hast du den zwei Threads? Also der erste Thread zeiget den Dialog an und der zweite macht dann den Export bz Datenbank?

[WR]Oh das ist gefährlich, da eigentlich keiner außer der EventDispatcherThread auf UI Elemente zugreifen darf.[/WR]
 
Zuletzt bearbeitet:
Ja genau...

Java:
                        thread1 = new Thread() {
                            public void run() {
                                bitteWarten bw;
                                try {
                                    bw = new bitteWarten();
                                    bw.showDialog();
                                } catch (InterruptedException ex) {
                                    Logger.getLogger(Betriebsdatenerfassung.class.getName()).log(Level.SEVERE, null, ex);
                                }

                            }
                        };
                        Thread threadDBAbfr = new Thread() {
                            public void run() {
                                try {
                                    ExcelExp ex = new ExcelExp();
                                    SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");
                                    ex.ExcelExp(2, con, sdf.parse(ei.returnvon()), sdf.parse(ei.returnbis()));
                                    ex.ExcelExp(3, con, sdf.parse(ei.returnvon()), sdf.parse(ei.returnbis()));
                                    con.close();

                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        };

                        thread1.start();
                        threadDBAbfr.start();
 
Schaumal, ich hätte es so gemacht:
Java:
public void actionPerformed(ActionEvent e) {
   final BitteWarten bw = new BitteWarten();
   bw.showDialog();
   Thread t = new Thread(){
      public void run() {
         ex.ExcelExp(2, con, sdf.parse(ei.returnvon()), sdf.parse(ei.returnbis()));
         ex.ExcelExp(3, con, sdf.parse(ei.returnvon()), sdf.parse(ei.returnbis()));
         con.close();
         Thread.sleep(5000);
         SwingUtilities.invokeLater(new Runnable(){
            public void run() {
               bw.closeDialog();
            }
         }); 
      }
   };
   t.start();
}
 
Wo ist da jetzt der Unterschied zwischen deiner Version und meiner hier?

Java:
public void actionPerformed(ActionEvent ae) {
                    try {
                        //erfVersand erf = new erfVersand();
                        bw = new bitteWarten();
                        bw.showDialog();

                        Thread threadDBAbfr = new Thread() {
                            public void run() {
                                try {
                                    ExcelExp ex = new ExcelExp();
                                    SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");
                                    ex.ExcelExp(2, con, sdf.parse(ei.returnvon()), sdf.parse(ei.returnbis()));
                                    ex.ExcelExp(3, con, sdf.parse(ei.returnvon()), sdf.parse(ei.returnbis()));
                                    con.close();
                                    bw.closeDialog();
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        };
Was macht das...
Java:
SwingUtilities.invokeLater(new Runnable(){
            public void run() {
               bw.closeDialog();
            }
         });
 
Na ja, mit deiner Version nutzt du jetzt auch nur ein Thread, mit deiner vorher waren es zwei.

Java:
SwingUtilities.invokeLater(new Runnable(){
  public void run() {
     // ...
  }
});

Also mit SwingUtilities.invokeLater fügst du eine Aufgabe zum EventDispatcherThread (EDT) hinzu. Du kannst dir den EDT vorstellen wie ein Arbeiter, der eine Warteschlange (Queue) besitzt. In die Queue werden Dominosteine eingefügt. Jeder Dominosteine beinhaltet eine Aufgabe die Abgearbeitet werden muss, dabei kommen das Click-Events auf Buttons oder neu-zeichnen wenn das Frame oder die Komponente verschoben bzw. verändert wurde. Der EDT ist ein einzelner Thread. Mit SwingUtilities.invokeLater fügst du dein eigenen Dominostein am Ende der Queue ein. Das heißt diese Aufgabe wird dann vom EDT verarbeitet.

Ich denke mal du hast schon gehört das wenn zwei Threads auf die selbe Resource zugreifen es Probleme geben kann. Du kannst dir die Thread wie zwei Köche vorstellen, was passiert wohl wenn zwei Köche im selben Topf zwei unterschiedliche Suppen kochen? Um dieses Problem zu umgehen, ist der EDT Single Threaded und wenn man etwas an der GUi ändern will, sollte man das mit Hilfe von SwingUtilities.invokeLater, damit stellt man sicher das nur ein Koch auf der GUI kocht.
 

Zurück
Oben