# Problem mit jPanel.removeAll()



## i.b.fan (31. Mai 2010)

Hallo,

schon wieder stolpere ich über ein unerwartetes Verhalten, deren Ursache ich gerne wüsste.
Ich habe in NetBeans ein JPanel erzeugt und (in der grafischen Oberfläche) auch gleich ein JLabel "myLabel" darauf platziert. Wenn ich nun im Code ein removeAll() mache, um das Panel für andere Labels frei zu machen, verschwindet es einfach nicht. 

Über Code neu hinzugefügte Labels löscht er dabei anstandslos:


```
myPanel.removeAll();
myPanel.validate();     //---> myLabel ist immernoch da!
JLabel jl = new JLabel("Hallo");
jl.setVisible(true);
jl.setOpaque(true);
jl.setBackground(Color.red);
jl.setSize(50, 70);
myPanel.add(jl);
myPanel.validate();     //---> "Hallo" ist dazu gekommen
myPanel.removeAll();
myPanel.validate();     //---> "Hallo" ist gelöscht, myLabel immernoch da!
```

Das finde ich schon recht hartnäckig... kann mir jemand erklären, warum das so ist und wie ich Abhilfe schaffen kann?

Vielen Dank im Voraus!

i.b.fan


----------



## U2nt (31. Mai 2010)

Warum willst das Panel für andere Labels frei machen? Arbeite doch lieber mit mehreren Panels und dem CardLayout.


----------



## ne0n2005 (31. Mai 2010)

Wie sieht denn sie stelle aus wo du das myLabel hinzufügst?
(Ja genau so seh ichs auch! @U2nt)


----------



## i.b.fan (1. Jun 2010)

Es können Labels hinzukommen und welche wegfallen. Anstatt jetzt hinundherzuschieben, wollte ich alle löschen und dann neu (in richtiger Reihenfolge) anordnen. Ob das nun Tasse oder Hammer ist, wollte ich zu diesem Zeitpunkt garnicht vertiefen... 

Eher zufällig bin ich dabei darauf gestossen, dass ich eine Komponente, die ich im grafischen Layout hinzugefügt habe, so nicht löschen kann. Und das erstaunt mich doch sehr!

i.b.fan


----------



## i.b.fan (1. Jun 2010)

ne0n2005 hat gesagt.:


> Wie sieht denn sie stelle aus wo du das myLabel hinzufügst?[...]



Also die Component scheint kein Pixelfehler/Darstellungsproblem zu sein, falls Du darauf hinauswillst: Sie zeigt den Tooltip-Text noch an, wenn man mit der Maus drüber fährt, auch wenn sie gescrollt wurde.


----------



## Ebenius (1. Jun 2010)

*re*validate()!

Ebenius


----------



## L-ectron-X (1. Jun 2010)

Gut Ebenius, aber du solltest noch erklären, wann revalidate() einem validate()-Aufruf vorzuziehen ist.


----------



## Ebenius (1. Jun 2010)

Kann ich auf die Schnelle schlecht erklären. Ungefähr: Revalidate macht eine *verspätetes* Validierung nach einer Invalidierung. Das ist meist dann nötig, wenn man innerhalb einer Event-Abarbeitung Änderungen sichtbar machen will. In aller Regel braucht man revalidate() als normaler Entwickler, validate/invalidate in der Regel nur als Komponentenentwickler. Wie gesagt: ungefähr.

Ebenius


----------



## i.b.fan (1. Jun 2010)

Ebenius hat gesagt.:


> *re*validate()!



Hmmm, also das Ersetzen durch revalidate() hat nichts verändert. Muss da noch mehr gemacht werden?

i.b.fan


----------



## i.b.fan (1. Jun 2010)

Ich habe versucht, das Ganze etwas weiter einzugrenzen:
Auch ein direktes Remove mit Name brachte nichts, aber die untere Ausgabe zeigt, dass myPanel nicht glaubt, dass myLabel auf ihm liegt (obwohl es ja mit gescrollt wird):


```
myPanel.remove(myLabel);  // --> keine Änderung
System.out.println(myPanel.getComponentCount()); // --> Ausgabe: 0
```
Verstecken geht übrigens: 

```
myLabel.setVisible(false);  // --> es ist tats. nicht mehr sichtbar, also durchaus ansprechbar
```

Macht das irgendeinen Sinn??

i.b.fan


----------



## i.b.fan (1. Jun 2010)

Nun war ja mein Verdacht, dass myLabel vielleicht doch in einer anderen Component liegt, aber im Inspector ist es eindeutig auf myPanel..... ???:L


----------



## U2nt (1. Jun 2010)

Vlt. mal probieren nach dem remove zu revalidaten...


----------



## Marco13 (1. Jun 2010)

... oder ein KSKB zu posten...


----------



## U2nt (1. Jun 2010)

Marco13 hat gesagt.:


> ... oder ein KSKB zu posten...



Was ist ein KSKB?


----------



## Marco13 (1. Jun 2010)

Das was erscheint wenn man mit der Maus kurz über dem Akronym " KSKB " stehenbleibt


----------



## i.b.fan (2. Jun 2010)

U2nt hat gesagt.:


> Vlt. mal probieren nach dem remove zu revalidaten...


Das hab ich doch gemacht, auch an mehreren Stellen... und zum Vergleich immer auch eine durch Code hinzugefügte Komponente removed. Ergebnis wie oben beschrieben.


----------



## hdi (2. Jun 2010)

Die Frage ist wie/wo genau Netbeans das Label addet. Das sieht man jetzt im Code leider nicht.

Sicher dass es überhaupt auf dem Panel liegt? Was sagt ein Panel#getComponentCount() am Anfang, bevor du überhaupt versucht irgendwas zu löschen? Ich glaub es ist da schon 0...

Vllt liegt das Label auf dem Frame Content Pane, über dem Panel (wenn kein LayoutManager benutzt wird geht sowas glaub ich nämlich)


----------



## i.b.fan (2. Jun 2010)

Marco13 hat gesagt.:


> ... oder ein KSKB zu posten...


Wie soll das gehen mit NetBeans? Mit all dem unter der Haube produziertem Code...

So habe ich den "Fehler" aber nochmals reproduziert:
Neues Projekt, Panel drauf und darauf ein Label (in Designansicht). 
Im Source vom View direkt nach initComponents() den oben geposteten Code einfügen.

(Wobei ich die Position des Codes natürlich auch variiert habe....)


----------



## i.b.fan (2. Jun 2010)

hdi hat gesagt.:


> Die Frage ist wie/wo genau Netbeans das Label addet. Das sieht man jetzt im Code leider nicht.
> 
> Sicher dass es überhaupt auf dem Panel liegt? Was sagt ein Panel#getComponentCount() am Anfang, bevor du überhaupt versucht irgendwas zu löschen? Ich glaub es ist da schon 0...
> 
> Vllt liegt das Label auf dem Frame Content Pane, über dem Panel (wenn kein LayoutManager benutzt wird geht sowas glaub ich nämlich)


Das hört sich plausibel an... werde ich morgen mal nachstellen (ich habe inzwischen umdesigned und auf jetzt einem nochmals neu angelegtem Projekt tritt das nicht mehr auf --> wahrscheinlich hat sich das durch Vererbung vorher auch immer auf neu angelegte Panels übertragen...)


----------



## Eldorado (2. Jun 2010)

Du weißt ja welche Komponenten du entfernen und hinzufügen willst, also deine JLabel. Adde diese doch einfach "manuell"(also direkt hinter der initComponents() von Netbenas eine eigene Methode aufrufen und dort dann die Komponenten mit einem beliebigen LayoutMager hinzufügen) und dann hast du auch keine Problem diese zu entfernen. Zudem sehe ich in deinem Code nicht, dass du die Aufgabe des Hinzufügen bzw. entfernen an den EDT übergibst...
mfg 
Eldorado


----------



## i.b.fan (4. Jun 2010)

Eldorado hat gesagt.:


> [...] Zudem sehe ich in deinem Code nicht, dass du die Aufgabe des Hinzufügen bzw. entfernen an den EDT übergibst...
> mfg
> Eldorado


Muss ich das? Also ich hab das nicht gemacht, es sei denn NetBeans macht das unter der Haube für mich. 
Ich höre das jetzt aber auch zum ersten mal. Was würde mir das denn bringen?

i.b.fan


----------



## i.b.fan (4. Jun 2010)

hdi hat gesagt.:


> Die Frage ist wie/wo genau Netbeans das Label addet. Das sieht man jetzt im Code leider nicht.
> 
> Sicher dass es überhaupt auf dem Panel liegt? Was sagt ein Panel#getComponentCount() am Anfang, bevor du überhaupt versucht irgendwas zu löschen? Ich glaub es ist da schon 0...
> 
> Vllt liegt das Label auf dem Frame Content Pane, über dem Panel (wenn kein LayoutManager benutzt wird geht sowas glaub ich nämlich)



Also ich hab es jetzt doch noch mal reproduzieren können und getComponentCount() gibt Unterschiedliches aus (siehe Comment). Im Inspector werden die beiden Labels auch unter dem Panel angezeigt. Alles ist Standard-Netbeans, bis auf den Code direkt nach "initComponents()". 
Vorgehensweise: Neues Projekt erstellt, direkt ein JPanel per D&D drauf, direkt per D&D zwei JLabels auf dieses Panel drauf. Nun habe ich gleich meinen Code eingefügt und ausgeführt.

Ob nun validate() oder revalidate() macht keinen Unterschied, das Panel rot zu machen habe ich nur eingefügt, um zu sehen, ob denn der Code überhaupt durchlaufen wird...

i.b.fan 

PS: habe bisher drei Deiner Tutorials gesehen - gefallen mir sehr gut und sind auch für Anfänger gut zu verstehen!


```
package removetest;

import java.awt.Color;
import org.jdesktop.application.Action;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.FrameView;
import org.jdesktop.application.TaskMonitor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JFrame;

/**
 * The application's main frame.
 */
public class RemoveTestView extends FrameView {

    public RemoveTestView(SingleFrameApplication app) {
        super(app);

        initComponents();

//hier mein bescheidenen Zeilen:
        System.out.println(jPanel1.getComponentCount());  //--> Ausgabe: 2
        jPanel1.setBackground(Color.red);                 //--> Panel ändert die Farbe
        jPanel1.removeAll();
        jPanel1.remove(jLabel1);
        jPanel1.revalidate();                             //--> Beide Labels noch da
        System.out.println(jPanel1.getComponentCount());  //--> Ausgabe: 0



        // status bar initialization - message timeout, idle icon and busy animation, etc
        ResourceMap resourceMap = getResourceMap();
        int messageTimeout = resourceMap.getInteger("StatusBar.messageTimeout");
        messageTimer = new Timer(messageTimeout, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                statusMessageLabel.setText("");
            }
        });
        messageTimer.setRepeats(false);
        int busyAnimationRate = resourceMap.getInteger("StatusBar.busyAnimationRate");
        for (int i = 0; i < busyIcons.length; i++) {
            busyIcons[i] = resourceMap.getIcon("StatusBar.busyIcons[" + i + "]");
        }
        busyIconTimer = new Timer(busyAnimationRate, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                busyIconIndex = (busyIconIndex + 1) % busyIcons.length;
                statusAnimationLabel.setIcon(busyIcons[busyIconIndex]);
            }
        });
        idleIcon = resourceMap.getIcon("StatusBar.idleIcon");
        statusAnimationLabel.setIcon(idleIcon);
        progressBar.setVisible(false);

        // connecting action tasks to status bar via TaskMonitor
        TaskMonitor taskMonitor = new TaskMonitor(getApplication().getContext());
        taskMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                String propertyName = evt.getPropertyName();
                if ("started".equals(propertyName)) {
                    if (!busyIconTimer.isRunning()) {
                        statusAnimationLabel.setIcon(busyIcons[0]);
                        busyIconIndex = 0;
                        busyIconTimer.start();
                    }
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(true);
                } else if ("done".equals(propertyName)) {
                    busyIconTimer.stop();
                    statusAnimationLabel.setIcon(idleIcon);
                    progressBar.setVisible(false);
                    progressBar.setValue(0);
                } else if ("message".equals(propertyName)) {
                    String text = (String)(evt.getNewValue());
                    statusMessageLabel.setText((text == null) ? "" : text);
                    messageTimer.restart();
                } else if ("progress".equals(propertyName)) {
                    int value = (Integer)(evt.getNewValue());
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(false);
                    progressBar.setValue(value);
                }
            }
        });
    }

    @Action
    public void showAboutBox() {
        if (aboutBox == null) {
            JFrame mainFrame = RemoveTestApp.getApplication().getMainFrame();
            aboutBox = new RemoveTestAboutBox(mainFrame);
            aboutBox.setLocationRelativeTo(mainFrame);
        }
        RemoveTestApp.getApplication().show(aboutBox);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        mainPanel = new javax.swing.JPanel();
        jPanel1 = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();
        menuBar = new javax.swing.JMenuBar();
        javax.swing.JMenu fileMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem exitMenuItem = new javax.swing.JMenuItem();
        javax.swing.JMenu helpMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem aboutMenuItem = new javax.swing.JMenuItem();
        statusPanel = new javax.swing.JPanel();
        javax.swing.JSeparator statusPanelSeparator = new javax.swing.JSeparator();
        statusMessageLabel = new javax.swing.JLabel();
        statusAnimationLabel = new javax.swing.JLabel();
        progressBar = new javax.swing.JProgressBar();

        mainPanel.setName("mainPanel"); // NOI18N

        jPanel1.setName("jPanel1"); // NOI18N

        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(removetest.RemoveTestApp.class).getContext().getResourceMap(RemoveTestView.class);
        jLabel1.setText(resourceMap.getString("jLabel1.text")); // NOI18N
        jLabel1.setName("jLabel1"); // NOI18N

        jLabel2.setText(resourceMap.getString("jLabel2.text")); // NOI18N
        jLabel2.setName("jLabel2"); // NOI18N

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel1)
                    .addComponent(jLabel2))
                .addContainerGap(172, Short.MAX_VALUE))
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLabel1)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel2)
                .addContainerGap(149, Short.MAX_VALUE))
        );

        javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel);
        mainPanel.setLayout(mainPanelLayout);
        mainPanelLayout.setHorizontalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, mainPanelLayout.createSequentialGroup()
                .addContainerGap(130, Short.MAX_VALUE)
                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(54, 54, 54))
        );
        mainPanelLayout.setVerticalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(mainPanelLayout.createSequentialGroup()
                .addGap(23, 23, 23)
                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(37, Short.MAX_VALUE))
        );

        menuBar.setName("menuBar"); // NOI18N

        fileMenu.setText(resourceMap.getString("fileMenu.text")); // NOI18N
        fileMenu.setName("fileMenu"); // NOI18N

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(removetest.RemoveTestApp.class).getContext().getActionMap(RemoveTestView.class, this);
        exitMenuItem.setAction(actionMap.get("quit")); // NOI18N
        exitMenuItem.setName("exitMenuItem"); // NOI18N
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        helpMenu.setText(resourceMap.getString("helpMenu.text")); // NOI18N
        helpMenu.setName("helpMenu"); // NOI18N

        aboutMenuItem.setAction(actionMap.get("showAboutBox")); // NOI18N
        aboutMenuItem.setName("aboutMenuItem"); // NOI18N
        helpMenu.add(aboutMenuItem);

        menuBar.add(helpMenu);

        statusPanel.setName("statusPanel"); // NOI18N

        statusPanelSeparator.setName("statusPanelSeparator"); // NOI18N

        statusMessageLabel.setName("statusMessageLabel"); // NOI18N

        statusAnimationLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        statusAnimationLabel.setName("statusAnimationLabel"); // NOI18N

        progressBar.setName("progressBar"); // NOI18N

        javax.swing.GroupLayout statusPanelLayout = new javax.swing.GroupLayout(statusPanel);
        statusPanel.setLayout(statusPanelLayout);
        statusPanelLayout.setHorizontalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(statusPanelSeparator, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(statusMessageLabel)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 230, Short.MAX_VALUE)
                .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(statusAnimationLabel)
                .addContainerGap())
        );
        statusPanelLayout.setVerticalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addComponent(statusPanelSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(statusMessageLabel)
                    .addComponent(statusAnimationLabel)
                    .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(3, 3, 3))
        );

        setComponent(mainPanel);
        setMenuBar(menuBar);
        setStatusBar(statusPanel);
    }// </editor-fold>

    // Variables declaration - do not modify
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel mainPanel;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JProgressBar progressBar;
    private javax.swing.JLabel statusAnimationLabel;
    private javax.swing.JLabel statusMessageLabel;
    private javax.swing.JPanel statusPanel;
    // End of variables declaration

    private final Timer messageTimer;
    private final Timer busyIconTimer;
    private final Icon idleIcon;
    private final Icon[] busyIcons = new Icon[15];
    private int busyIconIndex = 0;

    private JDialog aboutBox;
}
```


----------



## hdi (4. Jun 2010)

> PS: habe bisher drei Deiner Tutorials gesehen - gefallen mir sehr gut und sind auch für Anfänger gut zu verstehen!


Schön dass es dir etwas bringt. Schau dir mal die Videos ab #40 an, dort geht es um GUI's und auch um den EDT, was deine Frage beantworten wird was das dir bringt


----------



## Dit_ (5. Jun 2010)

i.b.fan hat gesagt.:


> Wenn ich nun im Code ein removeAll() mache, um das Panel für andere Labels frei zu machen, verschwindet es einfach nicht.




Hi versuch mal nach dem Löschen das Fenster zu minimieren und dann wieder sichtbar machen. Ist Panel dann immer noch sichtbar?


----------



## i.b.fan (5. Jun 2010)

hdi hat gesagt.:


> Schön dass es dir etwas bringt. Schau dir mal die Videos ab #40 an, dort geht es um GUI's und auch um den EDT, was deine Frage beantworten wird was das dir bringt




Jepp, 40-43 hat es wirklich hinreichend erklärt! Danke dafür! :toll:

Ich habs jetzt mit der beschriebenen inneren Klasse gelöst und siehe da: kaum macht mans richtig, funktionierts! 
Dass es zwischenzeitlich trotzdem funktioniert hatte, wird wohl einfach an zufällig günstigem Timing gelegen haben...

So gehts jetzt:

```
//hier wieder der Code direkt nach initComponents()

        Runnable removeIt = new Runnable(){

            @Override
            public void run(){

                jPanel1.setBackground(Color.red);
                jPanel1.removeAll();
                jPanel1.validate();     //--> jetzt sind wirklich alle Labels weg!!!
            }
        };
        EventQueue.invokeLater(removeIt);
```


----------



## i.b.fan (5. Jun 2010)

Eldorado hat gesagt.:


> [...] Zudem sehe ich in deinem Code nicht, dass du die Aufgabe des Hinzufügen bzw. entfernen an den EDT übergibst...
> mfg
> Eldorado




*Das mit dem EDT war der entscheidende Hinweis!*
Und mit Hilfe hdi´s Tutorials hab ichs dann auch richtig hinbekommen (s. letzten Post)

Euch allen danke für die Hilfe! *verneig*

i.b.fan


----------



## i.b.fan (6. Jun 2010)

hdi hat gesagt.:


> Schön dass es dir etwas bringt. Schau dir mal die Videos ab #40 an, dort geht es um GUI's und auch um den EDT, was deine Frage beantworten wird was das dir bringt



Hallo nochmals hdi (und die anderen natürlich auch),

bei der "Nachbereitung" dieses Threads und Deiner Tutorials haben sich noch zwei Fragen ergeben, die Du sicher mit links beantworten kannst:

a) warum übergibt NetBeans in initComponents() nichts an den EDT? (Du sagst im Tut ja, dass der EDT schon bei der bloßen Existenz eines GUI-Objekts involviert ist)

b) wenn es bei der Erzeugung durch NetBeans noch keine Raceconditions gibt, warum dann bei Änderungen (an der GUI) direkt nach initComponents()? 
Heißt das, wenn ich meine Änderungen direkt in die initComponents()-Methode mit "eingepflegt" hätte, wäre es auch nicht zu meinen Problemen gekommen?

Vielen Dank im Voraus!

i.b.fan


----------



## hdi (6. Jun 2010)

zu a)
Wenn da echt kein invokeLater oder invokeAndWait im generierten Code steht (weder in der initComponents noch in irgendwo in der main-methode), dann ist das wohl ziemlich schlecht gemacht ^^ Einen tieferen Sinn gibt es dahinter nicht. GUI Komponenten erzeugt und verändert man im EDT, punkt.

zu b)
Warum? Keine Ahnung, ich weiss nicht genau was in welchen Abständen genau passiert im EDT. Aber das muss man ja auch nicht wissen. Ich glaube kaum dass es einen Unterschied gemacht hätte wenn du den Code in die initComponents gelegt hättest, wenn die Sache mit a) stimmt...

Generell ist es so: Bevor eine Komponente angezeigt wird (setVisible(true)) kann man sie erstellen und damit arbeiten auch außerhalb des EDT. Es ist nicht empfohlen, aber in 99,9% wird es trotzdem funktionieren. (Ganz einfach weil die Chance auf eine Race Condition gegen 0 geht, da der EDT mit Komponenten die nicht angezeigt werden eig. nix macht)
_Während _eine Komponente angezeigt wird funktionieren Änderungen außerhalb des EDT's aber zu gut 70% *nicht*.


----------



## i.b.fan (6. Jun 2010)

hdi hat gesagt.:


> zu a)
> Wenn da echt kein invokeLater oder invokeAndWait im generierten Code steht (weder in der initComponents noch in irgendwo in der main-methode), dann ist das wohl ziemlich schlecht gemacht ^^ Einen tieferen Sinn gibt es dahinter nicht. GUI Komponenten erzeugt und verändert man im EDT, punkt.


Ich habe nochmals gesucht und nichts gefunden (auch in der main nicht). Verwunderlich, nach Deinen Aussagen! (vielleicht steckt es doch irgendwo tief unter der Haube und wird auch bei "generiertem Code" nur nicht angezeigt??)


> [...] Generell ist es so: Bevor eine Komponente angezeigt wird (setVisible(true)) kann man sie erstellen und damit arbeiten auch außerhalb des EDT. Es ist nicht empfohlen, aber in 99,9% wird es trotzdem funktionieren. (Ganz einfach weil die Chance auf eine Race Condition gegen 0 geht, da der EDT mit Komponenten die nicht angezeigt werden eig. nix macht)
> _Während _eine Komponente angezeigt wird funktionieren Änderungen außerhalb des EDT's aber zu gut 70% *nicht*.


Auch hier wieder erstaunlich: im generierten Code (ausser bei der ProgressBar) kommt kein setVisible(true) vor, was ja bedeutet, dass die Components von Anfang an visible sind...

Aber sei´s drum, mit der Regel *"Alles, was mit GUI zu tun hat, an den EDT übergeben!"* kann ich gut leben.  

Schönen Sonntag noch!

i.b.fan


----------



## hdi (6. Jun 2010)

Also wenn nicht mal ein setVisible(true) im Code zu finden ist, siehst du tatsächlich nicht den kompletten Code. Was komisch ist, ich meine eig. müssen die src-Dateien irgendwo liegen. 



> Aber sei´s drum, mit der Regel "Alles, was mit GUI zu tun hat, an den EDT übergeben!" kann ich gut leben.


Eben, solange man sich daran hält ist alles i.O.

GUI-Builder solltest du vermeiden. Es ist ganz okay um mal schnell das Aussehen einer GUI zu designen, nur um zu kucken wie es aussehen würde. Aber in "ernstem" Code haben solche automatisch generierten Zeilen nix zu suchen, das ist nämlich immer ein großes Chaos und sehr schlecht gemacht.

Du solltest dir von Anfang an gewöhnen alles per Hand zu schreiben. Dann gibt es auch keinen versteckten Code mehr in deinem Projekt


----------



## Eldorado (6. Jun 2010)

Netbeans übergibt in der Main-Methode initComponents() an den EDT: java.awt.EventQueue.invokeLater ist ein ähnliche Methode aus dem AWT-Lager für SwingUtilies.invokeLater und kann genauso benutzt werden.
mfg 
Eldorado


----------



## Ebenius (6. Jun 2010)

Die Initialisierung der gesamten GUI erfolgt auf dem EDT. Die einzelnen Komponenten sollten niemals Teile ihrer Initialisierung auslagern. [c]SwingUtilities.invokeLater(Runnable)[/c] ruft [c]EventQueue.invokeLater(Runnable)[/c] auf; das ist also exakt der gleiche Mechanismus.

Ebenius


----------



## i.b.fan (7. Jun 2010)

Eldorado hat gesagt.:


> Netbeans übergibt in der Main-Methode initComponents() an den EDT: java.awt.EventQueue.invokeLater ist ein ähnliche Methode aus dem AWT-Lager für SwingUtilies.invokeLater und kann genauso benutzt werden.
> mfg
> Eldorado


Also bei mir steht in der Main-Methode (welche in der ProjektnameApp.java ist) nur Folgendes:


```
/**
     * Main method launching the application.
     */
    public static void main(String[] args) {
        launch(ProjektnameApp.class, args);
    }
```

In der ProjektnameView.java ist der Aufruf der initComponents() auch unspektakulär, in der initComponents() dann wird auch nichts auf den EDT gelegt:

[Java]
    public ChanManView(SingleFrameApplication app) {
        super(app);
        initComponents();
        //... hier kommt noch StatusBarStandardGedöns
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        mainPanel = new javax.swing.JPanel();
        jPanel1 = new javax.swing.JPanel();
        availableScroller = new javax.swing.JScrollPane();

        //.... und hier folgen jetzt alle weiteren Komponenten und dann werden denen noch Werte
        // usw. aber nichts wird mit invokeLater() irgendwie auf den EDT gelegt
[/code]


----------



## i.b.fan (7. Jun 2010)

Ebenius hat gesagt.:


> Die Initialisierung der gesamten GUI erfolgt auf dem EDT. Die einzelnen Komponenten sollten niemals Teile ihrer Initialisierung auslagern. [c]SwingUtilities.invokeLater(Runnable)[/c] ruft [c]EventQueue.invokeLater(Runnable)[/c] auf; das ist also exakt der gleiche Mechanismus.
> 
> Ebenius



Also ich hab jetz auch auf das ganze Package eine Suche gemacht: Nichts mit "invoke"  oder "Runnable" gefunden... 
Zu welchem Zeitpunkt baut NetBeans das ein? Und zu welchem Zeitpunkt findet dann die Übergabe an den EDT statt?

Vor allem aber treten ja die ursprünglichen Fehler seit der (zusätzlichen zweiten???) Übergabe an den EDT nicht mehr auf:

```
//hier wieder der Code direkt nach initComponents()
 
        Runnable removeIt = new Runnable(){
 
            @Override
            public void run(){
 
                jPanel1.setBackground(Color.red);
                jPanel1.removeAll();
                jPanel1.validate();     //--> jetzt sind wirklich alle Labels weg!!!
            }
        };
        EventQueue.invokeLater(removeIt);
```

*Ich bin nun endgültig verwirrt! Wenn ich das nicht (nochmal) auf den EDT auslagern soll, warum funktioniert es dann jetzt und vorher aber nicht??? *

i.b.fan :bahnhof:


----------



## Eldorado (7. Jun 2010)

Hier der Netbeans-Code direkt nach der Erstellung eines neuen JFrame-Formulars: (vielleicht hast du den Teil ja gelöscht?) siehe Zeile 36:

```
public class NewJFrame extends javax.swing.JFrame {

    /** Creates new form NewJFrame */
    public NewJFrame() {
        initComponents();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    private void initComponents() {

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 300, Short.MAX_VALUE)
        );

        pack();
    }

    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() { //hier wird an den EDT übergeben
            public void run() {
                new NewJFrame().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify
    // End of variables declaration

}
```


----------



## Ebenius (7. Jun 2010)

Wie der launch aus Netbeans heraus genau aussieht, weiß ich nicht, da ich Netbeans nicht benutze. Ich wollte nur sagen, dass die gesamte GUI auf dem EDT initialisiert werden muss. Der Grund ist der, dass AWT nicht Thread-Save ist und ansonsten Probleme auftauchen können.

Ebenius


----------



## i.b.fan (7. Jun 2010)

Eldorado hat gesagt.:


> Hier der Netbeans-Code direkt nach der Erstellung eines neuen JFrame-Formulars: (vielleicht hast du den Teil ja gelöscht?) siehe Zeile 36: [...]



Gelöscht habe ich es nicht, da bin ich mir sicher. Auch wenn ich neue Projekte anlege werden die so wie oben beschrieben angelegt...
Bei Dir sieht das auch absolut nachvollziehbar aus mit dem EDT - allerdings hast Du ja ein JFrame angelegt in Deinem Code, ich eine DesktopApplication. Ich verwende NetBeans IDE 6.8 (Build 200912041610) . Dennoch ist dies ja eine Swing-Ausgangs-Form mit Menü etc.

*Irgendwo ist doch der Wurm drin! *verzweifel**
Ich Poste jetzt mal beide Dateien (AboutBox ist wohl nicht wichtig *g*), in der Hoffnung, dass da jemand den Haken findet. Ist das vielleicht eine Einstellungssache von NetBeans?

*Ich gehe so vor:*
New Project --> 
Step1-Auswahl: Java, Java Desktopapplication -->
Step2-Auswahl: Name=xxx, Application Shell=Basic Application -->
"finish"

und erhalte dann erstmal die drei Klassen *xxxApp.java*, *xxxView.java* und xxxAboutBox.java

*xxxApp.java:*

```
/*
 * XxxApp.java
 */

package xxx;

import org.jdesktop.application.Application;
import org.jdesktop.application.SingleFrameApplication;

/**
 * The main class of the application.
 */
public class XxxApp extends SingleFrameApplication {

    /**
     * At startup create and show the main frame of the application.
     */
    @Override protected void startup() {
        show(new XxxView(this));
    }

    /**
     * This method is to initialize the specified window by injecting resources.
     * Windows shown in our application come fully initialized from the GUI
     * builder, so this additional configuration is not needed.
     */
    @Override protected void configureWindow(java.awt.Window root) {
    }

    /**
     * A convenient static getter for the application instance.
     * @return the instance of XxxApp
     */
    public static XxxApp getApplication() {
        return Application.getInstance(XxxApp.class);
    }

    /**
     * Main method launching the application.
     */
    public static void main(String[] args) {
        launch(XxxApp.class, args);
    }
}
```

und *xxxView.java:*

```
/*
 * XxxView.java
 */

package xxx;

import org.jdesktop.application.Action;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.FrameView;
import org.jdesktop.application.TaskMonitor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JFrame;

/**
 * The application's main frame.
 */
public class XxxView extends FrameView {

    public XxxView(SingleFrameApplication app) {
        super(app);

        initComponents();

        // status bar initialization - message timeout, idle icon and busy animation, etc
        ResourceMap resourceMap = getResourceMap();
        int messageTimeout = resourceMap.getInteger("StatusBar.messageTimeout");
        messageTimer = new Timer(messageTimeout, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                statusMessageLabel.setText("");
            }
        });
        messageTimer.setRepeats(false);
        int busyAnimationRate = resourceMap.getInteger("StatusBar.busyAnimationRate");
        for (int i = 0; i < busyIcons.length; i++) {
            busyIcons[i] = resourceMap.getIcon("StatusBar.busyIcons[" + i + "]");
        }
        busyIconTimer = new Timer(busyAnimationRate, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                busyIconIndex = (busyIconIndex + 1) % busyIcons.length;
                statusAnimationLabel.setIcon(busyIcons[busyIconIndex]);
            }
        });
        idleIcon = resourceMap.getIcon("StatusBar.idleIcon");
        statusAnimationLabel.setIcon(idleIcon);
        progressBar.setVisible(false);

        // connecting action tasks to status bar via TaskMonitor
        TaskMonitor taskMonitor = new TaskMonitor(getApplication().getContext());
        taskMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                String propertyName = evt.getPropertyName();
                if ("started".equals(propertyName)) {
                    if (!busyIconTimer.isRunning()) {
                        statusAnimationLabel.setIcon(busyIcons[0]);
                        busyIconIndex = 0;
                        busyIconTimer.start();
                    }
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(true);
                } else if ("done".equals(propertyName)) {
                    busyIconTimer.stop();
                    statusAnimationLabel.setIcon(idleIcon);
                    progressBar.setVisible(false);
                    progressBar.setValue(0);
                } else if ("message".equals(propertyName)) {
                    String text = (String)(evt.getNewValue());
                    statusMessageLabel.setText((text == null) ? "" : text);
                    messageTimer.restart();
                } else if ("progress".equals(propertyName)) {
                    int value = (Integer)(evt.getNewValue());
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(false);
                    progressBar.setValue(value);
                }
            }
        });
    }

    @Action
    public void showAboutBox() {
        if (aboutBox == null) {
            JFrame mainFrame = XxxApp.getApplication().getMainFrame();
            aboutBox = new XxxAboutBox(mainFrame);
            aboutBox.setLocationRelativeTo(mainFrame);
        }
        XxxApp.getApplication().show(aboutBox);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        mainPanel = new javax.swing.JPanel();
        menuBar = new javax.swing.JMenuBar();
        javax.swing.JMenu fileMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem exitMenuItem = new javax.swing.JMenuItem();
        javax.swing.JMenu helpMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem aboutMenuItem = new javax.swing.JMenuItem();
        statusPanel = new javax.swing.JPanel();
        javax.swing.JSeparator statusPanelSeparator = new javax.swing.JSeparator();
        statusMessageLabel = new javax.swing.JLabel();
        statusAnimationLabel = new javax.swing.JLabel();
        progressBar = new javax.swing.JProgressBar();

        mainPanel.setName("mainPanel"); // NOI18N

        javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel);
        mainPanel.setLayout(mainPanelLayout);
        mainPanelLayout.setHorizontalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        mainPanelLayout.setVerticalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 252, Short.MAX_VALUE)
        );

        menuBar.setName("menuBar"); // NOI18N

        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(xxx.XxxApp.class).getContext().getResourceMap(XxxView.class);
        fileMenu.setText(resourceMap.getString("fileMenu.text")); // NOI18N
        fileMenu.setName("fileMenu"); // NOI18N

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(xxx.XxxApp.class).getContext().getActionMap(XxxView.class, this);
        exitMenuItem.setAction(actionMap.get("quit")); // NOI18N
        exitMenuItem.setName("exitMenuItem"); // NOI18N
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        helpMenu.setText(resourceMap.getString("helpMenu.text")); // NOI18N
        helpMenu.setName("helpMenu"); // NOI18N

        aboutMenuItem.setAction(actionMap.get("showAboutBox")); // NOI18N
        aboutMenuItem.setName("aboutMenuItem"); // NOI18N
        helpMenu.add(aboutMenuItem);

        menuBar.add(helpMenu);

        statusPanel.setName("statusPanel"); // NOI18N

        statusPanelSeparator.setName("statusPanelSeparator"); // NOI18N

        statusMessageLabel.setName("statusMessageLabel"); // NOI18N

        statusAnimationLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        statusAnimationLabel.setName("statusAnimationLabel"); // NOI18N

        progressBar.setName("progressBar"); // NOI18N

        javax.swing.GroupLayout statusPanelLayout = new javax.swing.GroupLayout(statusPanel);
        statusPanel.setLayout(statusPanelLayout);
        statusPanelLayout.setHorizontalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(statusPanelSeparator, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(statusMessageLabel)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 226, Short.MAX_VALUE)
                .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(statusAnimationLabel)
                .addContainerGap())
        );
        statusPanelLayout.setVerticalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addComponent(statusPanelSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(statusMessageLabel)
                    .addComponent(statusAnimationLabel)
                    .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(3, 3, 3))
        );

        setComponent(mainPanel);
        setMenuBar(menuBar);
        setStatusBar(statusPanel);
    }// </editor-fold>

    // Variables declaration - do not modify
    private javax.swing.JPanel mainPanel;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JProgressBar progressBar;
    private javax.swing.JLabel statusAnimationLabel;
    private javax.swing.JLabel statusMessageLabel;
    private javax.swing.JPanel statusPanel;
    // End of variables declaration

    private final Timer messageTimer;
    private final Timer busyIconTimer;
    private final Icon idleIcon;
    private final Icon[] busyIcons = new Icon[15];
    private int busyIconIndex = 0;

    private JDialog aboutBox;
}
```


----------



## i.b.fan (7. Jun 2010)

Ebenius hat gesagt.:


> Wie der launch aus Netbeans heraus genau aussieht, weiß ich nicht, da ich Netbeans nicht benutze. Ich wollte nur sagen, dass die gesamte GUI auf dem EDT initialisiert werden muss. Der Grund ist der, dass AWT nicht Thread-Save ist und ansonsten Probleme auftauchen können.
> 
> Ebenius


OK, dann bin ich wieder entwirrt 
Mit hdi´s Hilfe war ich (jetzt endlich *g*) genau auf diesem Stand. 
Und dann fiel mir auf, dass (bei mir) NetBeans sich scheinbar gar nicht um den EDT kümmert, was mich verunsicherte und ich zu klären suche...

i.b.fan


----------



## Ebenius (7. Jun 2010)

Gib doch mal in initComponent() aus, ob Du sie auf dem EDT ausgeführt wird. Siehe SwingUtilities.isEventDispatchThread(). Bestimmt wird das auf dem EDT ausgeführt.

Ebenius


----------



## i.b.fan (7. Jun 2010)

Ebenius hat gesagt.:


> Gib doch mal in initComponent() aus, ob Du sie auf dem EDT ausgeführt wird. Siehe SwingUtilities.isEventDispatchThread(). Bestimmt wird das auf dem EDT ausgeführt.
> 
> Ebenius



ok, das habe ich gemacht, direkt vor, nach und innerhalb der initComponents():

```
System.out.println("vor init: " + SwingUtilities.isEventDispatchThread()); //und innerhalb und nach

//Ausgabe:
//vor init: true
//innerhalb init: true
//nach init: true
```

Wie kommt das jetzt auf den EDT? Zauberei?


----------



## Ebenius (7. Jun 2010)

Na das Framework wird das schon richtig machen. [c]launch()[/c] ruft sicher eine der invoke-Methoden auf.

Ebenius


----------



## i.b.fan (7. Jun 2010)

Ebenius hat gesagt.:


> Na das Framework wird das schon richtig machen. [c]launch()[/c] ruft sicher eine der invoke-Methoden auf.
> 
> Ebenius


Das klingt plausibel und macht ja auch Sinn, nur wirft es die Schlussfolgerungen ab Post #21 völlig über den Haufen und insbesondere die Lösung in #25 

So funktioniert es endlich, aber wenn doch schon eh alles auf dem EDT ausgeführt wird, dürfte meine Übergabe an den EDT dann doch "doppelt" sein und somit genau *falsch*, oder?!


----------



## Ebenius (7. Jun 2010)

Falsch wird's dadurch noch nicht. Es wird halt in der Queue nach hinten gestellt und dem kompletten Aufbau der GUI ausgeführt, wenn das Fenster schon sichtbar ist. Dass das Verhalten dann anders ist, ist nachvollziehbar. Dass es vorher nicht funktioniert deutet auf irgendeinen anderen Fehler hin. Nichts desto trotz würde ich's so lassen und einen Kommentar hin machen, dass der entsprechende Teil verspätet ausgeführt wird, weil's ansonsten nicht funktioniert.

Ebenius


----------



## i.b.fan (7. Jun 2010)

Okay, so werd ichs vorerst machen.
Also die wahre Ursache zwar nicht gefunden, aber dabei *´ne ganze Menge gelernt!* 

Nochmals allen *vielen Dank* für die freundliche Hilfe!

i.b.fan


----------

