# Komponente zur Laufzeit erstellen



## Kiloui (6. März 2009)

Hi,
wie erreiche ich es Komponenten (Buttons, CheckBoxes etc) zur Laufzeit zu erstellen ?

Ganz simpel...angenommen der Benutzer wir nach einer Anzahl gefragt und anschließend werden entsprechend viele CheckBoxes erstellt ?
Ich weiß nicht wie das mit den namen der CheckBoxes objekte funktioniert.
Werden den Komponenten dann zufällige namen zugeteilt ?
Wie kann ich dann die Namen herausfinden um mit den Komponenten arbeiten zu können ?


Was ich vorhabe ist es ein Verzeichnis zu durchsuchen und dann für jede Datei die gefunden wird ein Bild + CheckBox zu erstellen.


----------



## takidoso (7. März 2009)

Hallo Kiloui
Aus meiner Sciht ist das eigetnlich nicht so schwer.
Alles was Du machen musst ist die Komponenten z.B. Buttons zur Laufzeit in Deinen Kontainer z.B. JPanel einzufügen. Nehmen wiri mal an, Du weit den Buttons die Du so dynamisch erzeugst und in Deinen Kontainer hinzufügst (add-Methode) den selben Listener zu, so kannst Du problemlos mit Abfragen der Source (s. EventObject) im Listener auf den entsprechendne Button schließen. Du kannst natürlich Deinen Komponenten auch Namen geben, wenn Du der Meinung bist Du müsstest das. Diese könnte man dann einfach machschinell mit einem Statischen String und einer laufenden Nummer versehen. Ich bin jetzt mal davon ausgegangen, dass Du Swing verwendest, jedoch nehme ich an dass dies im SWT sicher ähnlich gehandhabt wird, auch wenn ich SWT nicht kenne.
viele Grüß e

Takidoso


----------



## Kiloui (7. März 2009)

Danke für deine Antwort.

Habe grad mal versucht ein Objekt zu erstellen dessen Name durch einen vorher definierten String repräsentiert wird....und das funktioniert echt 
War mir eigentlich sicher dass würde nicht gehen...aber so ist es ja echt easy 

Danke
kiloui


----------



## Kai008 (7. März 2009)

Wozu der Name?
Wäre es nicht sinnvoller ein Array von der Länge der Eingabe zu erstellen und da der Reihe nach die JComponents reinschreiben? Und eben dann im Listener übern Source per Schleife das Objekt herausfinden?

Namen sind afaik nur dafür gut, in einer Debug-Ansicht Threads auseinanderhalten zu können. Sonst habe ich in ihnen keine Verwendung erkannt.


----------



## Kiloui (7. März 2009)

> Wäre es nicht sinnvoller ein Array von der Länge der Eingabe zu erstellen und da der Reihe nach die JComponents reinschreiben? Und eben dann im Listener übern Source per Schleife das Objekt herausfinden?



Was genau meinst du mit den Listenern ? Hab grad erst angefangen mit Java und damit noch nie gearbeitet....

Den Namen brauche ich aber um mit dem Obkekt arbeiten zu können....also um  über "name.eigenschaft"  die eigenschaften der Komponente zu bestimmen


----------



## Kai008 (7. März 2009)

Hier ein kleines Beispiel.
Habs auf 3 Klassen aufgeteilt, damit du dich besser auskennst.
Natürlich ginge es besser (da man keine Schleife braucht) über eine anonymoume Klasse, aber ich denke für einem Anfänger ist das noch zu schwer.
Wenn du irgendetwas nicht verstehst dann frag.


```
package app;

import javax.swing.JButton;
import javax.swing.JFrame;

public final class Kiloui extends JFrame
{
	private static final long serialVersionUID = 1L;
	private final int numbersOfButtons = 5;
	
	public Kiloui()
	{
		super();
		
		this.setSize(800, 600);
		this.setTitle("Ne menge Buttons");
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setResizable(false);
		this.setLayout(null);
		
		JButton[] buttonArray = new JButton[this.numbersOfButtons];
		BuildForm.run(this.numbersOfButtons, buttonArray, this);
		
		this.setVisible(true);
	}
	public final static void main(String[] args)
	{
		new Kiloui();
	}
}
//////////////////////////////
package app;

import javax.swing.JButton;

public final class BuildForm extends Object
{
	public BuildForm()
	{
		super();
	}
	public final static void run(int i, JButton[] buttonArray, Kiloui kiloui)
	{
		Listener l = new Listener(buttonArray);
		
		for(int j = 0; j < i; j++)
		{
			buttonArray[j] = new JButton();
			buttonArray[j].setText("Button ".concat(String.valueOf(j)));
			buttonArray[j].setLocation(20, 30 * j + 10);
			buttonArray[j].setSize(100, 20);
			buttonArray[j].addActionListener(l);
			
			kiloui.add(buttonArray[j]);			
		}
	}
}
//////////////////////////////
package app;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;

public final class Listener implements ActionListener
{
	private JButton[] buttonArray;
	
	public Listener(JButton[] buttonArray)
	{
		super();
		this.buttonArray = buttonArray;
	}
	public final void actionPerformed(ActionEvent arg0)
	{
		JButton source = (JButton)arg0.getSource();
		
		for(JButton button:this.buttonArray)
			if(button.equals(source))
				System.out.println(button.getText().concat(" gedrückt"));
	}
}
```


----------



## Kiloui (7. März 2009)

Ok danke, das funktioniert soweit alles und macht auch alles sinn.

Aber 3 Fragen hab ich doch noch 

1) Hat zwar nicht direkt was mit dem Thema zu tun aber was erreichst du durch das "this.".
Z.b.  in der Klasse "Kiloui" schreibst du:



> this.setSize(800, 600);
> this.setTitle("Ne menge Buttons");
> this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
> this.setResizable(false);
> this.setLayout(null);



oder



> BuildForm.run(*this.*numbersOfButtons, buttonArray, this);



Hätte vorallem beim zweiten nich einfach "numersOfButtons" gereicht anstatt "this.NumbersOfButtons" ?

2)
Kann man auch einfach direkt einen ActionListener erstellen und den Namen herausbekommen können ohne selbst eine Klasse "Listener" zu schreiben und die Klasse "ActionListener" zu extenden/implementieren ?

3)
Die Methode "actionPerformed(ActionEvent arg0)" rufst du nirgends auf, oder ?
Sprich "actionPerformed" kann man beliebig mit Code füllen und wird ohne dass man sie nochmal speziell aufruft ausgeführt sobald dass Programm merkt dass mit der jeweiligen Komponente etwas gemacht wird ?


----------



## Kai008 (7. März 2009)

1)
Hätte es. "this." ist ein Pointer, der direkt auf die Klasse verweißt. Im ersten Zitat verweißt es immer auf Methoden der Klasse. Kiloui erbt von JFrame (extends JFrame), d. H. es bekommt alle public und protected (event. auch die ohne Modifizierer, solche hatte ich aber noch nie) Methoden und Variablen der jeweiligen Klasse.
Ich verwende es grundsätzlich immer, ist aber nur nötig wenn es eine Klassen- und eine Methodenvariable gibt, da sonst die Methodenvariable bevorzugt wird. z. B.:

```
String aString;
public void setAString(String aString)
{
	this.aString = aString;
}
```
Hier ist es notwendig, da er sonst die Methodenvariable, die im Konstruktor steht in sich selbst schreiben würde.
Aber ich verwende es nur um schnell zwischen Klassen- und Methoden-Variablen zu unterscheiden. Zudem öffnet sich bei "this" automatisch in Eclipse das Autoverfollständigkeitsfenster, sonst müsste ich Controll + Space drücken.

2)
Ja. Das meine ich mit Anonyme Klasse. 

```
for(int j = 0; j < i; j++)
{
	buttonArray[j] = new JButton();
	buttonArray[j].setText("Button ".concat(String.valueOf(j)));
	buttonArray[j].setLocation(20, 30 * j + 10);
	buttonArray[j].setSize(100, 20);
	buttonArray[j].addActionListener(new ActionListener() {
		public void actionPerformed(ActionEvent e)
		{
			JButton source = (JButton)e.getSource();
			System.out.println(source.getText());
		}				
	});
	
	kiloui.add(buttonArray[j]);			
}
```

In diesen Fall bekommt jeder Button seinen eigenen ActionListener. Hier brauchst du keine Schleife, da der Source immer der gleich ist, da der Listener ja nur an einen Button hängt. Wichtig ist nur dass anonyme Klassen keinen Konstruktor haben, d. H. du kannst ihnen auch keine Objekte übergeben.

3)
Nein, das machen die Buttons selbst. Einfach mit addActionListener() eine Klasse die ActionListener implementiert (könntest  z. B. auch in der "BuildForm" den ActionListener implementieren und ihm per "this" übergeben), oder eben eine anonyme Klasse schreiben. Ich glaube zumindest dass es auch "Klasse" heißt, obwohl es in Wirklichkein ein Interface ist.


----------



## Kiloui (7. März 2009)

Ok, danke für die Mühe. Wieder was dazu gelernt.


----------



## Kiloui (7. März 2009)

Ach noch eine Sache...damit ich keinen neuen Thread aufmachen muss 

Wenn ich jetzt mehrere Komponenten erstelle und diese nicht in das fenster paßen sind sie nicht mehr sichtbar....wie bekomme ich sobald nötig eine Scrollleiste an meinem Fenster hin ?


----------



## Kai008 (8. März 2009)

Durch ein JScrollPane.
Hier mal schnell aus einen meiner Projekte:


```
public static void run(List<Cmd> list, OptionsWindow optionsWindow)
{
	JPanel panel = new JPanel();
	panel.setLayout(null);
	panel.setPreferredSize(new Dimension(900, list.size() * 30 + 20));

	int listlenght = list.size();
	JLabel[] cmdLabels = new JLabel[listlenght];
	JLabel[] pathLabels = new JLabel[listlenght];
	JLabel[] parmLabels = new JLabel[listlenght];

	JTextField[] cmdFields = new JTextField[listlenght];
	JTextField[] pathFields = new JTextField[listlenght];
	JTextField[] parmFields = new JTextField[listlenght];
	
	EditButton[] editButtons = new EditButton[listlenght];
	DelButton[] delButtons = new DelButton[listlenght];

	BrowseButton[] browseButtons = new BrowseButton[listlenght];
	OKButton[] okButtons = new OKButton[listlenght];
	
	for(int i = 0; i < list.size(); i++)
	{
		cmdLabels[i] = new JLabel();
		cmdLabels[i].setText(list.get(i).getCommand());
		cmdLabels[i].setSize(100, 9);
		cmdLabels[i].setLocation(20, i * 30 + 20);
		panel.add(cmdLabels[i]);
		
		pathLabels[i] = new JLabel();
		pathLabels[i].setText(list.get(i).getPath());
		pathLabels[i].setSize(300, 9);
		pathLabels[i].setLocation(150, i * 30 + 20);
		panel.add(pathLabels[i]);
		
		parmLabels[i] = new JLabel();
		parmLabels[i].setText(list.get(i).getParm());
		parmLabels[i].setSize(100, 9);
		parmLabels[i].setLocation(470, i * 30 + 20);
		panel.add(parmLabels[i]);
		///////
		cmdFields[i] = new JTextField();
		cmdFields[i].setSize(100, 19);
		cmdFields[i].setLocation(20, i * 30 + 20 - 5);
		cmdFields[i].setVisible(false);
		panel.add(cmdFields[i]);
		
		pathFields[i] = new JTextField();
		pathFields[i].setSize(300, 19);
		pathFields[i].setLocation(150, i * 30 + 20 - 5);
		pathFields[i].setVisible(false);
		panel.add(pathFields[i]);
		
		parmFields[i] = new JTextField();
		parmFields[i].setSize(100, 19);
		parmFields[i].setLocation(470, i * 30 + 20 - 5);
		parmFields[i].setVisible(false);
		panel.add(parmFields[i]);
		///////
		editButtons[i] = new EditButton(i, optionsWindow);
		editButtons[i].setSize(100, 15);
		editButtons[i].setLocation(600, i * 30 + 20 - 3);
		panel.add(editButtons[i]);
		
		delButtons[i] = new DelButton(i, optionsWindow);
		delButtons[i].setSize(100, 15);
		delButtons[i].setLocation(730, i * 30 + 20 - 3);
		panel.add(delButtons[i]);
		///////
		browseButtons[i] = new BrowseButton(i, optionsWindow);
		browseButtons[i].setText("Browse");
		browseButtons[i].setSize(100, 15);
		browseButtons[i].setLocation(600, i * 30 + 20 - 3);
		browseButtons[i].setVisible(false);
		panel.add(browseButtons[i]);
		
		okButtons[i] = new OKButton(i, optionsWindow);
		okButtons[i].setText("OK");
		okButtons[i].setSize(100, 15);
		okButtons[i].setLocation(730, i * 30 + 20 - 3);
		okButtons[i].setVisible(false);
		panel.add(okButtons[i]);
	}
	
	JScrollPane scrollPane = new JScrollPane(
			JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
			JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
	scrollPane.setViewportView(panel);
	scrollPane.setBackground(Color.blue);
	scrollPane.setLocation(20, 20);
	scrollPane.setSize(900, 8 * 30 + 50);
	
	optionsWindow.setCmdLabels(cmdLabels);
	optionsWindow.setPathLabels(pathLabels);
	optionsWindow.setParmLabels(parmLabels);
	
	optionsWindow.setCmdFields(cmdFields);
	optionsWindow.setPathFields(pathFields);
	optionsWindow.setParmFields(parmFields);
	
	optionsWindow.setEditButtons(editButtons);
	optionsWindow.setDelButtons(delButtons);
	optionsWindow.setBrowseButtons(browseButtons);
	optionsWindow.setOkButtons(okButtons);
	
	JScrollPane oldPane = optionsWindow.getScrollPane();
	if(oldPane != null)
		optionsWindow.remove(oldPane);		
	optionsWindow.add(scrollPane); 
	optionsWindow.setScrollPane(scrollPane);
}
```

Ist zum editieren Strings aus einen Objekt.

Zuerst wird ein JPanel angelegt, wichtig ist "setPreferredSize()" und nicht "setSize()" zu verwenden sonst funktioniert es nicht. Keine Ahnung warum, war das erste und einzige mal dass ich eines verwendet habe. Als Größe gibtst du das an, was es tatsächlich haben soll, also inkl. des nicht sichtbaren Bereiches.

Dann werden die Arrays wie bei dem was ich vorhin geschrieben habe angelegt. Dann halt Schleife, die alle Objekte erstellt.

Dann wird die JScrollPane angelegt. Die Parameter sagen, dass immer eine vertikale (nach oben/unten) ScrollBar angezeigt werden soll, auch wenn sie nicht gebraucht wird, und niemals eine horenziontale. Danach sagt man, dass das Panel darin angezeigt werden soll. Danach die Hintergrundsfarbe, warum weiß ich auch nicht mehr, und dann halt Größe und Positionen.
Dann werden die Arrays im OptionsWindow in Klassenvariablen geschrieben, geprüft ob schon eine JScrollBar existiert, tut sie es wird sie entfernt, danach wird die neue hinzugefügt.


----------



## Kiloui (8. März 2009)

Das klappt noch nicht so ganz. Ich habe jetzt versucht in die Klasse "BuildForm" ein ScrollPanel einzufügen und die Buttons dann zum Panel zu "adden":



```
import java.awt.Color;
import java.awt.Dimension;

import javax.swing.JButton;
import javax.swing.JScrollPane;
 
public final class BuildForm extends Object
{
    public BuildForm()
    {
        super();
    }
    public final static void run(int i, JButton[] buttonArray, Kiloui kiloui)
    {
        Listener l = new Listener(buttonArray);
        
        JScrollPane scrollPane = new JScrollPane(
                JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane.setBackground(Color.blue);
        scrollPane.setLocation(20, 20);
        scrollPane.setSize(500,500);
                
        kiloui.add(scrollPane);
        
        
        for(int j = 0; j < i; j++)
        {
            buttonArray[j] = new JButton();
            buttonArray[j].setText("Button ".concat(String.valueOf(j)));
            buttonArray[j].setLocation(20, 30 * j + 10);
            buttonArray[j].setSize(100, 20);
            buttonArray[j].addActionListener(l);
            
            scrollPane.add(buttonArray[j]);
        }
        
    }
}
```


Problem1: Die Scrollleiste bleibt "deaktiviert". Ich kann also nicht runterscrollen obwohl insgesamt 100 Buttons erstellt wurden, Wenn ich die Größe des Panals mittels "setsize()" hochsetze dann verschwindet das Panel aus dem unteren Rand des Fensters und die Scrollleiste bleibt an sich immer noch deaktiviert.
Wenn ich ".setPreferedSize()" nutze tut sich garnichts.

Problem2: Nur der erste und letzte Button auf dem Panel sind sichtbar. Die anderen sieht man erst wenn man mit der Maus kurz drüber fährt. (s. Anhang)


----------



## Kai008 (8. März 2009)

Morgen.


```
public final static void run(int i, JButton[] buttonArray, Kiloui kiloui)
{
    Listener l = new Listener(buttonArray);
    
    JPanel panel = new JPanel();
    panel.setLayout(null);
    panel.setPreferredSize(new Dimension(500, 30 * i + 20));        
    
    for(int j = 0; j < i; j++)
    {
        buttonArray[j] = new JButton();
        buttonArray[j].setText("Button ".concat(String.valueOf(j)));
        buttonArray[j].setLocation(20, 30 * j + 10);
        buttonArray[j].setSize(100, 20);
        buttonArray[j].addActionListener(l);
        
        panel.add(buttonArray[j]);
    }
    
    JScrollPane scrollPane = new JScrollPane(
            JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
            JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
    scrollPane.getViewport().setView(panel);
    scrollPane.setBackground(Color.blue);
    scrollPane.setLocation(20, 20);
    scrollPane.setSize(500,500);
    kiloui.add(scrollPane);
}
```


----------



## Kiloui (8. März 2009)

achso...man muss ein Panel und ein ScrollPane erstellen.
Ok dann klappts jez, danke.


----------



## takidoso (8. März 2009)

Kai008 hat gesagt.:


> 1)
> Hätte es. "this." ist ein Pointer, der direkt auf die Klasse verweißt.


Verweist nicht wirklich auf die Klasse, aber auf "das Objekt" der Klasse.
Wenn mich nicht alles täuscht dürfte "this." innerhalb statischer Methoden nicht möglich sein.


----------



## Kai008 (8. März 2009)

Stimmt, man bekommt auch eine Warnung wenn man mit this auf eine statische Methode innerhalb einer nicht-statischen zugreift. Aber das ist ja (insbesonderst für einen Anfänger) nicht so wichtig, bzw. eher verwirrend.


----------

