Best Practice Listerner

kaoZ

Top Contributor
Aloha, folgendes Problem tut sich auf, ich habe ein ein kleines realisierungsproblem / bzw. suche ich quasi eine best Practice um dies umzusetzen , es geht um folgendes :

Gegeben ist ein Array aus JPanel , welches "Karten" für ein Cardlayout hält :

Java:
private JPanel[] cards;

...

cards[0] = new WelcomeCard();
cards[1] = new UserCard();
cards[2] = new RootCard();
cards[3] = new DisclaimerCard();

die einzelnen Cards sind z.B so realisiert :

Java:
public class DisclaimerCard extends Card {
	private static final long serialVersionUID = 1L;

	private JScrollPane scrollPane;
	private JTextArea area;
	private JPanel btnPane;
	private JCheckBox box;
	
	public DisclaimerCard() {
		initComponents();
		setProperties();
		addComponents();
	}
	
	@Override
	void initComponents() {
		setContent(new JPanel(new BorderLayout()));
		
		this.area		 = new JTextArea();
		this.scrollPane	 = new JScrollPane(area);
		this.box = new JCheckBox("AGB Akzeptieren");
		
		this.btnPane = createButtonPane();
	}

	@Override
	void setProperties() {
		getCard().setLayout(new BorderLayout());
		
		FileUtil.addTextToArea(getTextArea(), FileUtil.readFile("text/agb.txt"));
		
		getTextArea().setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
		
	}

	@Override
	void addComponents() {
		getContent().add(BorderLayout.CENTER, getScrollPane());
		getContent().add(BorderLayout.PAGE_END, getButtonPane());
		
		getCard().add(getContent());
		
	}
	
	private JPanel createButtonPane(){
		JPanel panel = new JPanel();
		final Dimension panelSize = new Dimension(0,80);
		GridBagConstraints g = new GridBagConstraints();

		panel.setPreferredSize(panelSize);
		panel.setLayout(new GridBagLayout());
		
		
		g.gridx = 0;
		g.gridy = 0;
		g.weightx = 1;
		g.anchor = GridBagConstraints.LINE_START;
		panel.add(getCheckBox(), g);
		
		
		return panel;
	}
	
	public void addListener(ActionListener l){
		getCheckBox().addActionListener(l);
	}
	
	public JCheckBox getCheckBox() 				{return this.box;}
	public JPanel getButtonPane() 				{return this.btnPane;}
	public JTextArea getTextArea() 				{return this.area;}
	public JScrollPane getScrollPane()			{return this.scrollPane;}

}

grade im Bezug auf dieses JPanel (Card) geht es nun darum Listener zu setzen, hierzu habe ich eine Methode erstellt die einen Beliebigen Listener der Checkbox hinzufügt.

Das ganze sieht dann so aus zzt. :



Der Listener Selber wird in einem Teil der Gui, die später diese Karten darstellt als innere Klasse realisiert, meine Frage ist einfach, macht man das im Professionellen Bereich über Innere Klassen oder sollte man hier die Listener für die jeweiligen Komponenten dann doch in Separaten Klassen realisieren?

Es scheint sich nun nämlich zu häufen zzt. sind es nun schon ein Listener für die Buttons , und einer für die CheckBox welche nachher bei Aktivierung einen Dialog öffnen soll , welcher den Installations-Assistenten abschließt, und die gesammelten Informationen an das Model des Installers übergibt.

Um den Buttons, welche in einer Methode einem extra JPanel hinzugefügt werden, Listener hinzuzufügen zu können , habe ich eine Methode geschrieben welche dies möglich macht, hier mal die Installer Klasse komplett :

Java:
import static de.kaoz.constants.Constants.INSTALLER_TITLE;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import de.kaoz.installer.cards.DisclaimerCard;
import de.kaoz.installer.cards.RootCard;
import de.kaoz.installer.cards.UserCard;
import de.kaoz.installer.cards.WelcomeCard;

public class Installer extends JFrame{
	private static final long serialVersionUID = 1L;
	
	private JPanel contentPane;
	private JPanel btnPane;
	private JPanel[] cards;
	
	private JButton[] btns;
	
	private InstallerModel model;

	final Dimension btnSize		 = new Dimension(125,25);
	final Dimension frameSize	 = new Dimension(600,450);
	
	public Installer() {
		initComponents();
		setProperties();
		addComponents();
	}
	
	private void initComponents(){
		this.model			 = new InstallerModel();
		this.contentPane	 = new JPanel(new CardLayout());
		this.btnPane		 = createBtnPane();
		this.cards			 = new JPanel[4];
		
		cards[0] = new WelcomeCard();
		cards[1] = new UserCard();
		cards[2] = new RootCard();
		cards[3] = new DisclaimerCard();

	}
	
	private void setProperties(){
		getFrame().setTitle(INSTALLER_TITLE);
		getFrame().setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		getFrame().setSize(frameSize);
		getFrame().setLocationRelativeTo(null);
		getFrame().setResizable(false);
		
		getContent().setBorder(BorderFactory.createEmptyBorder(30,30,10,30));
	}
	
	private void addComponents(){
		addCards(cards);
		getFrame().add(BorderLayout.CENTER, contentPane);
		getFrame().add(BorderLayout.PAGE_END, btnPane);
	}
	
	private void addCards(JPanel...cards){
		for (JPanel card : cards) {
			contentPane.add(card);
		}
	}
	
	private JPanel createBtnPane(){
		JPanel panel = new JPanel();
		panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
		panel.setBorder(BorderFactory.createEmptyBorder(0, 0, 20, 0));
		
		final String[] btnTxt = {"Zurück","Weiter"};
		final Dimension btnDim = new Dimension(125,25);
		final Dimension btnGap = new Dimension(20,0);
		
		btns = new JButton[2];
		
		for (int i = 0; i < btns.length; i++) {
			btns[i] = new JButton(btnTxt[i]);
			btns[i].setPreferredSize(btnDim);
		}
		
		panel.add(Box.createHorizontalGlue());
		panel.add(btns[0]);
		panel.add(Box.createRigidArea(btnGap));
		panel.add(btns[1]);
		panel.add(Box.createRigidArea(new Dimension(30,0)));
		
		addListener(new ButtonListener(getContent()), btns);
		
		btns[0].setEnabled(false);

		return panel;
	}
	
	public void addListener(ActionListener l, JButton...btns){
		for (JButton btn : btns) {
	        btn.addActionListener(l);
        }
	}
	
	public void setVisible(){
		getFrame().setVisible(true);
	}

	public JButton[] getBtns() 						{return this.btns;}
	public JPanel[] getCards() 						{return this.cards;}
	public JFrame getFrame() 						{return this;}
	public JPanel getContent() 						{return this.contentPane;}
	public InstallerModel getModel() 				{return this.model;}	
	
	/** Inner class Listener */
	
	class ButtonListener implements ActionListener {

		private JPanel container;
		private int index;
		
		public ButtonListener(JPanel container) {
			this.container = container;
			this.index = 0;
		}
		
		@Override
		public void actionPerformed(ActionEvent e) {
			
			CardLayout layout = (CardLayout) getContainer().getLayout();
			
			switch (e.getActionCommand()) {
			case "Weiter":
				if (getIndex() < getContainer().getComponentCount() - 1) {
					incrementIndex();
					layout.next(getContainer());
				}
				
				if (getIndex() > 0) {
					btns[0].setEnabled(true);
				}
				
				if (getIndex() == getContainer().getComponentCount() - 1) {
					btns[1].setEnabled(false);
				}
				
				break;
			case "Zurück":
				if (getIndex() != 0) {
					decrementIndex();
					layout.previous(getContainer());
				}
				
				if (getIndex() < 1) {
					btns[0].setEnabled(false);
				}
				
				if (getIndex() < getContainer().getComponentCount() - 1) {
					btns[1].setEnabled(true);
				}
			
				break;
			}
		}
		
		class CheckBoxListener implements ActionListener{

			@Override
            public void actionPerformed(ActionEvent e) {
	            // TODO Auto-generated method stub
	            
            }
			
		}
		
		public void incrementIndex(){
			this.index++;
		}
		
		public void decrementIndex(){
			this.index--;
		}
		
		public JPanel getContainer() 			{return this.container;}
		public int getIndex() 					{return this.index;}
	}
}

Hier noch das dazu gehörende Model welches die Daten am Ende des Setups beinhalten soll und diese dann bei Abschluss dementsprechend händelt ( noch nicht implementiert )

Java:
public class InstallerModel {
	
	private User user;
	private File rootDir;
	private Company company;
	
	static Preferences prefs = Preferences.userNodeForPackage(Editor.class);
	
	public InstallerModel() {
	}
	
	public void setApplicationRoot(File dir){
		this.rootDir = dir;
	}
	
	public void setUser(User user){
		this.user = user;
	}
	
	public void setCompany(Company company){
		this.company = company;
	}
	
	public void storeData(){
		
		//FIXME
	}

	public Preferences getPrefs()		{return prefs;}
	public User getUser() 				{return this.user;}
	public File getApplicationRoot() 	{return this.rootDir;}
	public Company getCompany() 		{return this.company;}
}

Vielleicht bin ich das Ganze auch Falsch angegangen, denn es scheint langsam aber sicher dann doch etwas unübersichtlich zu werden, vorallem durch die Listener, ich bin über jeden Ratschlag dankbar was die Umsetzung solcher Dinge angeht.

Was mich auch brennend interessieren würde ist ob mein Ansatz mit der Datenhaltung in einem gesondertem Model so richtig ist, hierzu habe ich mich an JTable und co. orientiert, das Model soll sämtliche Daten die während der Ausführung des Installers gesammelt werden halten , und später an die noch festzulegenden stellen speichern.
 
Zuletzt bearbeitet:

kaoZ

Top Contributor
./Push, los beachtet meinen Beitrag ^^, falls ich mal wieder zu verwirrend beschrieben haben sollte was ich meine erläutere ich den Teil der nicht verstanden wird gerne nochmal im Detail :D
 

kaoZ

Top Contributor
Ok, ich habe bis jetzt folgendes gemacht , und dies scheint auch zu funktionieren ,

In der DisclaimerCard

Java:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;

import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.event.ChangeListener;

import de.kaoz.util.FileUtil;


public class DisclaimerCard extends Card {
	private static final long serialVersionUID = 1L;

	private JScrollPane scrollPane;
	private JTextArea area;
	private JPanel btnPane;
	private JCheckBox box;
	
	public DisclaimerCard() {
		initComponents();
		setProperties();
		addComponents();
	}
	
	@Override
	void initComponents() {
		setContent(new JPanel(new BorderLayout()));
		
		this.area		 = new JTextArea();
		this.scrollPane	 = new JScrollPane(area);
		this.box 		 = new JCheckBox("AGB Akzeptieren");
		
		this.btnPane = createButtonPane();
	}

	@Override
	void setProperties() {
		getCard().setLayout(new BorderLayout());
		
		FileUtil.addTextToArea(getTextArea(), FileUtil.readFile("text/agb.txt"));
		
		getTextArea().setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
		getTextArea().setEditable(false);
		
	}

	@Override
	void addComponents() {
		getContent().add(BorderLayout.CENTER, getScrollPane());
		getContent().add(BorderLayout.PAGE_END, getButtonPane());
		
		getCard().add(getContent());
		
	}
	
	private JPanel createButtonPane(){
		JPanel panel = new JPanel();
		final Dimension panelSize = new Dimension(0,80);
		GridBagConstraints g = new GridBagConstraints();

		panel.setPreferredSize(panelSize);
		panel.setLayout(new GridBagLayout());
		
		
		g.gridx = 0;
		g.gridy = 0;
		g.weightx = 1;
		g.anchor = GridBagConstraints.LINE_START;
		panel.add(getCheckBox(), g);
		
		
		return panel;
	}
	
	public void addListener(ChangeListener l){
		getCheckBox().addChangeListener(l);
	}
	
	public JCheckBox getCheckBox() 				{return this.box;}
	public JPanel getButtonPane() 				{return this.btnPane;}
	public JTextArea getTextArea() 				{return this.area;}
	public JScrollPane getScrollPane()			{return this.scrollPane;}
}

habe ich eine Methode addListener geschrieben welche meiner CheckBox einen ChangeListener hinzufügt:

Java:
public void addListener(ChangeListener l){
		getCheckBox().addChangeListener(l);
	}

Im Installer welcher die Cards ja in einem Array hält habe ich nun folgendes geschrieben:

Java:
private void initComponents(){
		this.model			 = new InstallerModel();
		this.contentPane	 = new JPanel(new CardLayout());
		this.btnPane		 = createBtnPane();
		this.cards			 = new JPanel[4];
		
		cards[0] = new WelcomeCard();
		cards[1] = new UserCard();
		cards[2] = new RootCard();
		cards[3] = new DisclaimerCard();
		
		((DisclaimerCard) cards[3]).addListener(new CheckBoxListener(getContent()));  // <<--
	}

Hier der Listener als Innere Klasse dazu :

Java:
class CheckBoxListener implements ChangeListener{
		
		private JPanel container;
		
		private JCheckBox box;
		
		public CheckBoxListener(JPanel container) {
	        this.container = container;
	        this.box = ((DisclaimerCard)getCards()[3]).getCheckBox();
        }
		
		@Override
	    public void stateChanged(ChangeEvent e) {
		   	
			
		    
			if (box.isSelected()) {
	            getBtns()[1].setEnabled(true);
	            getBtns()[1].setText("Beenden");
            }
			else{
				getBtns()[1].setEnabled(false);
				getBtns()[1].setText("Weiter");
			}
	    }
		
		public JCheckBox getCheckBox()			{return this.box;}
		public JPanel getContainer() 			{return this.container;}
	}

Zugegeben , die Syntax von
Code:
getCards()[3]
sieht auch für mich etwas strange aus, funktioniert aber wie mit dem Array selbst.


Wenn ich jetzt die Checkbox Aktiviere, wird der Button der normalerweise durch die Cards schaltet aktiviert, meine Gedanke war nun diesem jetzt eine neue ActionCommand und einen neuen Text zuzuweisen, und ein Case für den ButtonListener zu erstellen, der dann benötigte Objekte aus den Eingabe der einzelnen Cards per getter holt und dann beim betätigen die Benötigten Verzeichnisse erstellt usw usw....

Einzig und allein das wenn die Checkbox aktiviert ist und ich nochmal durch die Cards blättere , dauert es insofern ich wieder auf diese Card gehe eine ganze weile eh der Button wieder aktiviert wird, bzw. neu gezeichnet wird, deshalt ist meine frage, wie macht man sowas im Alltag wenn man verschiedene Komponenten mit verschiedenen Listenern unter einen Hut bringen muss, ich kann mir nicht vorstellen das das mit den DownCasts usw. eine Standardisierte Lösung ist.

Controller ?!

Wäre super wenn mir einer der schon länger "Professionell" Software entwickelt da mal einen Tipp geben könnte :)
 
Zuletzt bearbeitet:

Neue Themen


Oben