Swing-Application mehrere JPanels

Hi,

ich schreibe gerade eine größere Applikation, wo ich mehrere JPanel in das JFrame einbinde.

Einige Elemente auf verschiedenen Panels müssen untereinander mittels der Listener interagieren.

Hat jemand schon Erfahrungen damit, wie ich eine eher unübersichtliche große Java-Datei vermeiden kann?
Wenn ich jedem JPanel eine eigene Datei spendiere muß ich irgendwie die Elemente miteinander verknüpfen.

Besten Dank für Anregungen

Winni

Hi Winni,

stellt sich mir erstmal die Frage, was unter den einzelnen Elementen zu verstehen ist und warum du diese über viele JPanels einbindest?!

Kann es sein, dass du damit die Layout-Gebung erreichen willst?

Ich persönlich bevorzuge bei solch einem Fall, in dem wahrscheinlich keine allzu große Wiederverwendbarkeit herrschen wird, meistens anonyme innere Klassen als Listener.

Sprich. Mein einziges JPanel, welches dann in dem JFrame sitzt besitzt alle Elemente und ein registrierter anonymer Listener kennt dann beispielsweise ein anderes Element anhand der umliegenden Panel-Klasse.

Dies mag bei vielen Elementen irgendwann unübersichtlich werden. Du musst eigentlich folgende Dinge betrachten:

  • Wiederverwendung der anonymen Klassen
  • vermutlicher zukünftiger Pfelgeaufwand
  • gesamter Umfang

Je größer die eine Panel-Klasse werden wird, desto mehr würde ich zu ausgelagerter Struktur raten.

Da kann man dann aber auch schnell den Überblick verlieren, denn vor lauter Referenzübergaben und getter-Methoden kann man die Übersichtlichkeit auch ziemlich verschlechtern.

Es ist also mehr oder weniger eine Erfahrungs- und Gefühlssache.

Wenn du etwas konkreter wirst, dann könnte ich evtl. genauer analysieren.

Ciao, Bill

Hi Bill,

also ich habe ein Borderlayout wo ich neben dem Center (da soll ne Tabbed Pane mit 2 JPanels (vielleicht werden es ja auch mal mehr) eine North-Komponente (Lauter Dateien (4 oder später mehr), die zu laden sind [JLabel JTextField(Name/Path) und JButton browse] ) und eine West-Komponente (2 JList, welche Elemente aus den Dateien in der North-Komponente zur Auswahl haben) habe.
Südlich hätte ich gerne noch JCheckBox-en, welche einige Dateien und auch eine JList inaktivieren, sowie eine Ladung Buttons, welche im Prinzip auf die Dateien, die Listboxen sowie die Ausgaben Zugriff haben müssen.
Im Center soll es eine Textausgabe und eine Tabelle geben (eben durch Auswahl der JTabbedPane)

Ich wollte es vermeiden, Alle Komponenten in ein GridBagLayout zu friemeln, da ich ja dann jede einzelne Zelle verfriemeln müßte. Außerdem sollten die Panels einen Rahmen mit Titel haben (das habe ich gelöst).

Ich denke, daß ich davon wenig wiederverwerten will.

Kommst Du dann weiter?

Gruß

Winni
Vielleicht hilft Dir das weiter.

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hi Winni,

wenn du layouttechnisch so etwas „Großes“ vorhast, dann empfehle ich dir auf jeden Fall das TableLayout (https://tablelayout.dev.java.net/). Das ist einfach zu verwenden und wesentlich besser „lesbar“, als das GridBagLayout. Beim BorderLayout allein wirst du bestimmt mit dem Verschachteln von Panels nicht fertig. Vielleicht findest du ja Gefallen dran? Ich arbeite sehr viel mit dem TableLayout und kann es daher nur wärmstens empfehlen.

Da du einiges an Komponenten verwenden wirst, ist eine Aufteilung in einzelne Klassen sicherlich nicht verkehrt.

Das können ja durchaus Panels sein, die du dann letztendlich im Frame richtig anordnest. Die Panels könnten entsprechend als Listener auf den „Action“-Panels fungieren. Kannst ja dafür eigene Listener schreiben.

Beispiel:
Im Norden hast du ja deine 4 Dateikomponenten. Diese können mittels „Browse“ verändert werden, also hat das umliegende Panel entsprechende fireFile1Changed(File newFile) bis fireFile4Changed(File newFile)-Methoden, die dann vom jeweiligen „Browse“-Button angestoßen werden und in denen dann die registrierten FileListener informiert werden. Diese FileListener implementieren entsprechend die Methoden file1Changed(File newFile) bis file2Changed(File newFile) und können eben bei diesem nördlichen Panel registriert werden. Einer dieser Listener kann z.B. eine deiner JLists sein?!

Somit erreichst du, dass du im Prinzip in der konkreten Nord-Panel-Klasse gar nicht wissen musst, wer um dich rum existiert. Du weiß eben nur, dass all deine registrierten Listener die Info haben wollen und leitest diese weiter.

Hilft dir das weiter?

Ciao, Bill

Hi Bill,

Hi Winni,

wenn du layouttechnisch so etwas „Großes“ vorhast, dann
empfehle ich dir auf jeden Fall das TableLayout
(https://tablelayout.dev.java.net/). Das ist einfach zu
verwenden und wesentlich besser „lesbar“, als das
GridBagLayout. Beim BorderLayout allein wirst du bestimmt mit
dem Verschachteln von Panels nicht fertig. Vielleicht findest
du ja Gefallen dran? Ich arbeite sehr viel mit dem TableLayout
und kann es daher nur wärmstens empfehlen.

Da ich das ganze in einer Firma schreibe, wird es wohl schwierig, noch das TableLayout einzuführen.
(Das Ding muß auf jedem handelsüblichen JRE laufen)

Da du einiges an Komponenten verwenden wirst, ist eine
Aufteilung in einzelne Klassen sicherlich nicht verkehrt.

Das denke ich auch…

Das können ja durchaus Panels sein, die du dann letztendlich
im Frame richtig anordnest. Die Panels könnten entsprechend
als Listener auf den „Action“-Panels fungieren. Kannst ja
dafür eigene Listener schreiben.

Beispiel:
Im Norden hast du ja deine 4 Dateikomponenten. Diese können
mittels „Browse“ verändert werden, also hat das umliegende
Panel entsprechende fireFile1Changed(File newFile) bis
fireFile4Changed(File newFile)-Methoden, die dann vom
jeweiligen „Browse“-Button angestoßen werden und in denen dann
die registrierten FileListener informiert werden. Diese
FileListener implementieren entsprechend die Methoden
file1Changed(File newFile) bis file2Changed(File newFile) und
können eben bei diesem nördlichen Panel registriert werden.
Einer dieser Listener kann z.B. eine deiner JLists sein?!

Somit erreichst du, dass du im Prinzip in der konkreten
Nord-Panel-Klasse gar nicht wissen musst, wer um dich rum
existiert. Du weiß eben nur, dass all deine registrierten
Listener die Info haben wollen und leitest diese weiter.

Hilft dir das weiter?

Also ich verstehe davon nur Bahnhof…

Kannst Du das etwas einfacher erklären?

Ciao, Bill

Besten Dank…

Winni

Hi Winni,

Beispiel:
Im Norden hast du ja deine 4 Dateikomponenten. Diese können
mittels „Browse“ verändert werden, also hat das umliegende
Panel entsprechende fireFile1Changed(File newFile) bis
fireFile4Changed(File newFile)-Methoden, die dann vom
jeweiligen „Browse“-Button angestoßen werden und in denen dann
die registrierten FileListener informiert werden. Diese
FileListener implementieren entsprechend die Methoden
file1Changed(File newFile) bis file2Changed(File newFile) und
können eben bei diesem nördlichen Panel registriert werden.
Einer dieser Listener kann z.B. eine deiner JLists sein?!

Also ich verstehe davon nur Bahnhof…

Kannst Du das etwas einfacher erklären?

Mmh.
Wie erkläre ich das am Besten?!
Angenommen, du verwendest oben ein Panel (sagen wir A), welches einen Button hat. Das Betätigen dieses Buttons (Btn1) bewirkt ja ein ActionEvent, also kannst du rein theoretisch ein weiteres Panel (sagen wir B), welches die JList enthält und z.B. auch noch eine Status-Zeile (sagen wir C) registrieren, die dann anhand dem ActionEvent erkennen, dass der Button gedrückt wurde und entsprechende Aktionen ausführen. In diesem einfachen Fall implementieren also B und C das Interface ActionListener.

Wenn du nun in A auch noch einen zweiten Button (Btn2) einfügst, auf den wiederum B und C reagieren sollen, dann musst du in B und C praktisch eine Möglichkeit haben, um das zu behandelnde ActionEvent eindeutig dem Btn1 oder Btn2 aus A zuordnen zu können. Hierzu könntest du vom ActionEvent die Quelle abfragen und diese dann mit Btn1 bzw. Btn2 vergleichen. Dazu musst du jedoch in A zwei Methoden schaffen, die dir A und B zur Verfügung stellen (also getBtn1() etc.). Diese sind dann public und somit kann man auch von außen diese Buttons manipulieren => schlecht!

Feiner ist es, wenn du in A eine Liste hältst, in der sich Listener für Btn1 und Btn2 registrieren können. Also erhält A die Methode addBtnListener(BtnListener lis), die dann den übergebenen Listener in die Liste einträgt.

Der BtnListener ist lediglich ein Interface und besitzt die Methoden btn1Pressed(Object einParameter) und btn2Pressed(Object einParameter).
B und C implementieren dieses Interface, wodurch sie explizit auf das Drücken von Btn1 und Btn2 reagieren können, und registrieren sich bei A als BtnListener.

A registriert wiederum bei Btn1 und Btn2 anonyme ActionListener.
Da ich grad merke, dass das ganze sicherlich einfacher ist, wenn du bissel Code siehst, höre ich an dieser Stelle lieber auf und geb dir ein Code-Schnipsel. Mit dem kannst du dir alles noch bissel besser herleiten.

/\*\*
 \* Ein Listener 
 \*/
public interface BtnListener
{
 public void btn1Pressed(Object parameter);
 public void btn2Pressed(Object parameter);
}

/\*\*
 \* Dein Panel A
 \*/
public class A
{
 private List m\_Listeners = Collections.synchronizedList(new ArrayList());
 private JButton m\_Btn1;
 private JButton m\_Btn2;

 private void init()
 {
 // ...

 m\_Btn1.addActionListener(new ActionListener(){
 public void actionPerformed(ActionEvent arg0)
 {
 fireBtn1Pressed("something");
 }});

 m\_Btn2.addActionListener(new ActionListener(){
 public void actionPerformed(ActionEvent arg0)
 {
 fireBtn2Pressed("something");
 }});

 // ...
 }

 private void fireBtn1Pressed(Object something)
 {
 Iterator it = m\_Listeners.iterator();
 BtnListener lis;
 while(it.hasNext())
 {
 lis = (BtnListener)it.next();
 lis.btn1Pressed(something);
 }
 }

 private void fireBtn2Pressed(Object something)
 {
 Iterator it = m\_Listeners.iterator();
 BtnListener lis;
 while(it.hasNext())
 {
 lis = (BtnListener)it.next();
 lis.btn2Pressed(something);
 }
 }

 public void addBtnListener(BtnListener lis)
 {
 m\_Listeners.add(lis);
 }
}

/\*\*
 \* Dein Panel B
 \*/
public class B implements BtnListener
{
 public void btn1Pressed(Object parameter)
 {
 // irgendwas tun
 }

 public void btn2Pressed(Object parameter)
 {
 // irgendwas tun
 }

}

/\*\*
 \* Dein Panel C
 \*/
public class C implements BtnListener
{
 public void btn1Pressed(Object parameter)
 {
 // irgendwas anderes tun
 }

 public void btn2Pressed(Object parameter)
 {
 // irgendwas anderes tun
 }

}

Hoffe, dass hilft dir weiter!
Ciao, Bill

Hi Bill,

ok, ich wurschtle mir das irgendwie zusammen…

Die Panels implementieren das Interface BtnListener, und diese muß ich also dann in das Panel einfügen…

Da müßte ich die Buttons dann aber besser in meiner JFrame-Klasse halten, da ich ja sonst nicht die listenerList füttern kann, oder?

Wie wäre es, wenn ich die Models alle in der JFrame-Klasse instanziiere und dem JPanel-Konstruktor übergebe?
Ok, für JTextArea, JList und JTable gibts welche, kann man darüber auch das Enable steuern?

Wie mache ich das für meine Datei-Kombination aus JLabel, JTextField und JButton?

Ich werde mal ne Nacht drüber schlafen…

Grüßle und vielen Dank für die Tipps

Winni

Hi Bill,

vielen Dank für die Tipps mit dem Aufbau eines Models und Listeners.

Habe inzwischen weitergebaut…

Die Models (teilweise selbstgemixte) liegen in meinem JFrame und werden an die jeweiligen Konstruktoren übergeben.

Und die entsprechenden Komponenten implementieren meine Listener-Inderfaces.
(habe auch eigne Events von EventObject abgeleitet)

Langsam wird es was…

Gruß

Winni