# Realisierung: JTable zur Laufzeit mit neuen Daten füllen



## Ollek (24. Mrz 2011)

Hallo,

ich brauche mal eure Meinungen zu einer Sache in meinem Projekt. Da ich bisher kaum mit JTable und AbstractTableModel gearbeitet. Nun stand ich vor einem Problem..

Situation:
Ich habe eine Breadcrumb Klasse, mit 3 verschiedenen ComboBoxen. Eine Box handelt die Applikationen, die andere die Hauptkategorien und die 3. die Unterkatgorien. Wenn ich nun ein App auswähle, bekomme ich die Hauptkategorien angezeigt, welche in diesem App verfügbar sind. Dann wird eine Hauptkategorie ausgewählt und in der 3. ComboBox werden hierzu die vorhandenen Unterkategorien angezeigt. Wenn nun eine Unterkategorie ausgewählt wird, dann sollen hierzu die vorhandenen Artikel in der JTable angezeigt werden. Da musste nun realisiert werden.

Hier habe ich die 3 Klassen in der ViewFactory initalisiert, da nur ein Objekt dieser im Programm bestehen darf. Das Model habe ich dann an die ArticleTable Klasse und an die Breadcrumb Klasse übergeben, damit beide das Model kennen. In dem Model habe ich eine ArrayList vom typ Article initalisiert. Diese kann durch getter und setter gesetzt oder geholt werden. Beim Start des Programs wird die Tabellen mit alle verfügbaren Artikeln angezeigt. Erst wenn der User eine APlikation selektiert ändert sich die liste. Wenn nun eine Unterkategorie ausgewählt wird, wird die aktuelle Liste in der Tabelle geleert(clear()) und die neue mit dem setter gesetzt. im setter wird mit fireTableDataChanged die ganze Tabelle aktualisiert. 

Ist dieser weg der saubere? Habt ihr dort verbesserungsvorschläge??
Möchte ja gerne was dazulernen. 

Freue mich auf eure Ratschläge udn die Kritik.. :rtfm:

Hier der Sourcecode der Klassen:

```
public class ViewFactory extends JFrame {
	
	private final int MINWIDTH = 1024;
	private final int MINHEIGHT = 768;
	private MenuFactory mf;
	private JMenuBar menuBar;
	private JToolBar toolBar;
	private Breadcrumb breadCrumb;
	private ArticleTable artTbl;
	private ArticleView artView;
	private ArticleAttribute artAtt;
	private ArticleImageArea artImgA;
	private JPanel north;
	private HashMap<String, JButton> toolBarButtons;
	private HashMap<String, JMenuItem> menuBarItems;

	public ViewFactory(){
		super();
		init();
	}

	/**
	 * Methode erzeugt das Haupfenster mit 
	 * Properties und Komponenten
	 */
	private void init() {
		this.setTitle("XXX");
		this.setLayout(new BorderLayout());
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setMinimumSize(new Dimension(MINWIDTH, MINHEIGHT));
		this.setLocationRelativeTo(null);
		
		north = new JPanel();
		north.setLayout(new BorderLayout());
		
		showMenuBar();
		showToolBar();
			
		
		
		//Breadcrumb
		ArticleTableModel tblModel = new ArticleTableModel();
		breadCrumb = new Breadcrumb(tblModel);
		north.add(breadCrumb, BorderLayout.SOUTH);
		this.add(north, BorderLayout.NORTH);
		
		artAtt = new ArticleAttribute();
		artImgA = new ArticleImageArea();
		artView = new ArticleView(artAtt, artImgA);
		this.add(artView, BorderLayout.EAST);
		
		artTbl = new ArticleTable(tblModel);
		this.add(artTbl, BorderLayout.CENTER);
		
		setEventHandling();
		
		this.setVisible(true);
		this.pack();
//		this.setExtendedState(JFrame.MAXIMIZED_BOTH);
		
	}
```


```
public class ArticleTableModel extends AbstractTableModel  {
	
	private String[] columnNames = new String[]{"Bezeichung", "SKU", "APP"};
	private ArrayList<Article> listOfArticles = new ArrayList<Article>();

	@Override
	public int getColumnCount() {
		return columnNames.length;
	}

	@Override
	public int getRowCount() {
		return listOfArticles.size();
		
	}

	@Override
	public Object getValueAt(int rowIndex, int columnIndex) {
		
		Article article = listOfArticles.get(rowIndex);
		switch(columnIndex){
			case 0: return article.getDescription();
			case 1: return article.getArtnr();
			case 2: return "GL";
		}
		return "Fehler";
	}
	
	public Article getValueAt(int rowIndex) {

		return listOfArticles.get(rowIndex);
	}
	
	public String getColumnName(int iColumn){
		return columnNames[iColumn];
	}

	public ArrayList<Article> getListOfArticles() {
		return listOfArticles;
	}

	public void setListOfArticles(ArrayList<Article> listOfArticles) {
		this.listOfArticles.addAll(listOfArticles);
		this.fireTableDataChanged();
	}
}
```


```
public class ArticleTable extends JPanel{

	private JTable tblArticle;
	private JScrollPane scpForTable;
	private ListSelectionModel listSelectionModel;
	private ArticleTableModel tblModel;
		
	public ArticleTable(ArticleTableModel tblModel){
		super();
		this.tblModel = tblModel;
		initalize();
	}

	private void initalize() {
		this.setLayout(new BorderLayout());
		this.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), null, 
				TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.BELOW_TOP, new Font("Arial", Font.PLAIN, 10)));
		
		scpForTable = new JScrollPane();
		scpForTable.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
		scpForTable.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		scpForTable.setViewportView(showArticleTable());
		this.add(scpForTable, BorderLayout.CENTER);
		
	}
	
	private JTable showArticleTable(){
		
		// TableModel
//		tblModel = new ArticleTableModel();
		tblModel.setListOfArticles(ArticleManagement.getInstance().getArticleList());
		
		// Table
		tblArticle = new JTable();
		tblArticle.setModel(tblModel);
		tblArticle.setRowSelectionAllowed(true);
		tblArticle.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		tblArticle.setAutoCreateRowSorter(true);
		tblArticle.setFont(FontStyle.DEFAULT);
		
		// Selektierungs Model - horcht auf selektierungen in der TableView von User
		listSelectionModel = tblArticle.getSelectionModel();
		listSelectionModel.addListSelectionListener(new ListSelectionListener() {
			
			@Override
			public void valueChanged(ListSelectionEvent e) {
				int iSelectedRow = tblArticle.getSelectedRow();
				
				if(iSelectedRow == -1){
					System.out.println("Nix ausgewählt ;-)");
				} else {
					int iModelIndex = tblArticle.convertRowIndexToModel(iSelectedRow);
					ArticleManagement.getInstance().setSelectedArticleInView(tblModel.getValueAt(iModelIndex));
				}			
			}
		});
		
		TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>();
		sorter.setModel(tblModel);
		tblArticle.setRowSorter(sorter);
		
		JTableHeader tblHeader = tblArticle.getTableHeader();
		tblHeader.setResizingAllowed(false);
		tblHeader.setReorderingAllowed(false);
		
		TableColumnModel columnModel = tblArticle.getColumnModel();
		
		columnModel.getColumn(1).setMinWidth(150); columnModel.getColumn(1).setMaxWidth(150);
		columnModel.getColumn(2).setMinWidth(50); columnModel.getColumn(2).setMaxWidth(50);
			
		
		return tblArticle;
	}
```


```
public class Breadcrumb extends JPanel{

	private JComboBox cbMainCatList;
	private JComboBox cbSubCatList;
	private JComboBox cbApplGrpList;
	private ArticleTableModel model;
	
	private Vector<String> vSubCats = new Vector<String>();
	
	public Breadcrumb(ArticleTableModel model){
		this.model = model;
		initalize();
	}
	
	
	public void initalize(){
		this.setLayout(new FlowLayout(FlowLayout.LEFT));
		
		this.add(new JLabel("Applikation: "));
		this.add(showSelectionOfApps());
		this.add(new JLabel("Hauptkategorie: "));
		this.add(showSelectionOfMainCats());
		this.add(new JLabel("Unterkategorie: "));
		this.add(showSelectionOfSubCats());
	}
	
	/**
	 * Methode zeigt und füllt die Auswahl der JComboBox der
	 * einzelnen Applikationen  
	 */
	private JComboBox showSelectionOfApps(){
		cbApplGrpList = new JComboBox(ApplikationManagement.getInstance().getAppList().toArray());
		cbApplGrpList.setPreferredSize(new Dimension(60, 25));
		cbApplGrpList.setRenderer(new ComboBoxAppRenderer());
		cbApplGrpList.addItemListener(new ItemListenerForAppBox());
		
		return cbApplGrpList;
	}
	
	/**
	 * Methode füllt und zeigt die Auswahl der 
	 * JComboBox für die jeweiligen Hauptkategorien
	 * 
	 * @return
	 */
	private JComboBox showSelectionOfMainCats(){
			
		cbMainCatList = new JComboBox(MainCatManagement.getInstance().getMainCatList().toArray());
		cbMainCatList.setRenderer(new ComboBoxMainCatRenderer());
		cbMainCatList.setPreferredSize(new Dimension(260, 25));
		cbMainCatList.setEnabled(false);
		cbMainCatList.addItemListener(new ItemListenerForMainCatBox());
		
		
		return cbMainCatList;
	}
	
	/**
	 * Methode füllt und zeigt die Auswahl der 
	 * JComoBox mit den Unterkategorien
	 * 
	 * @return
	 */
	private JComboBox showSelectionOfSubCats(){
	
		cbSubCatList = new JComboBox(SubCatManagement.getInstance().getSubCatList().toArray());
		cbSubCatList.setRenderer(new ComboBoxSubCatRenderer());
		cbSubCatList.setEnabled(false);
		cbSubCatList.addItemListener(new ItemListenerForSubCatBox());
		
		return cbSubCatList;
	}
	
	
	
	public JComboBox getMainCatList() {
		return cbMainCatList;
	}


	public void setMainCatList(JComboBox cbMainCatList) {
		this.cbMainCatList = cbMainCatList;
	}


	public JComboBox getSubCatList() {
		return cbSubCatList;
	}


	public void setSubCatList(JComboBox cbSubCatList) {
		this.cbSubCatList = cbSubCatList;
	}


	public JComboBox getApplGrpList() {
		return cbApplGrpList;
	}


	public void setApplGrpList(JComboBox cbApplGrpList) {
		this.cbApplGrpList = cbApplGrpList;
	}



	/**
	 * Klasse zum Erstellen eines Labels als
	 * ComboBox Item mit speziellem Hintergrund
	 * 
	 * @author 	 *
	 */
	class ComboBoxMainCatRenderer extends JLabel implements ListCellRenderer {
		
		private JLabel lblColor;
		
		public ComboBoxMainCatRenderer(){
			this.setOpaque(true);
			this.setPreferredSize(new Dimension(240, 21));
			this.setLayout(new FlowLayout(FlowLayout.LEFT, 180,0));
			
			lblColor = new JLabel();
			lblColor.setOpaque(true);
			lblColor.setPreferredSize(new Dimension(60, 20));
			add(lblColor);
		}

		@Override
		public Component getListCellRendererComponent(JList list, Object value,
				int index, boolean isSelected, boolean cellHasFocus) {
						
						
			if (isSelected) {
				this.setBackground(list.getSelectionBackground());
		        this.setForeground(list.getSelectionForeground());
		    } else {
		        this.setBackground(list.getBackground());
		        this.setForeground(list.getForeground());
		    }

			
			this.setText(((MainCategorie)value).getDescription());
			lblColor.setBackground(((MainCategorie)value).getColor());
						
			return this;
		}
	}
	
	/**
	 * Klasse erstellt ein JLabel für
	 * die ComboBox Applikation
	 * 
	 * @author 	 *
	 */
	class ComboBoxAppRenderer extends JLabel implements ListCellRenderer{

		public ComboBoxAppRenderer(){
			this.setOpaque(true);
			this.setPreferredSize(new Dimension(60, 20));
		}
		
		@Override
		public Component getListCellRendererComponent(JList list, Object value,
				int index, boolean isSelected, boolean cellHasFocus) {
			
			if (isSelected) {
		           this.setBackground(list.getSelectionBackground());
		           this.setForeground(list.getSelectionForeground());
		       } else {
		           this.setBackground(list.getBackground());
		           this.setForeground(list.getForeground());
		       }
			
			this.setText(((Applikation)value).getDescription());
			
			return this;
		}
	}
	
	/**
	 * Klasse erstellt ein JLabel für die 
	 * ComboBox SubCategorie
	 * 
	 * @author 	 *
	 */
	class ComboBoxSubCatRenderer extends JLabel implements ListCellRenderer {

		public ComboBoxSubCatRenderer(){
			this.setOpaque(true);
		}
		
		@Override
		public Component getListCellRendererComponent(JList list, Object value,
				int index, boolean isSelected, boolean cellHasFocus) {
			if (isSelected) {
		           this.setBackground(list.getSelectionBackground());
		           this.setForeground(list.getSelectionForeground());
		       } else {
		           this.setBackground(list.getBackground());
		           this.setForeground(list.getForeground());
		       }
			
			this.setText(((SubCategorie)value).getDescription());
			
			return this;
		}
	}
	
	
	/**
	 * Klasse reagiert auf die Auswahl des Users
	 * in der ComboBox der Applikation. 
	 * 
	 * @author 	 *
	 */
	class ItemListenerForAppBox implements ItemListener {

		@Override
		public void itemStateChanged(ItemEvent e) {
			Applikation app = null;
			ArrayList<MainCategorie> listOfMainCats = null;
			
			if(cbApplGrpList.getSelectedItem() != null){
				app = (Applikation)cbApplGrpList.getSelectedItem();
				// Alles Items aus der Liste rausschmeißen
				cbMainCatList.removeAllItems();
				if(app.getDescription().equals("Alle")){
					cbMainCatList.setEnabled(false);
					listOfMainCats = MainCatManagement.getInstance().getMainCatList();
				}else{
					cbMainCatList.setEnabled(true);
					listOfMainCats = MainCatManagement.getInstance().filteredListByApp(app);
				}
				
				// Liste mit neuen Items füllen
				for(MainCategorie mainCat : listOfMainCats)
					cbMainCatList.addItem(mainCat);	
				
				ApplikationManagement.getInstance().setSelectedAppInBreadcrumb(app);
				repaint();
			}
		}
		
	}
	
	/**
	 * Klasse reagiert auf die Auswahl
	 * des User in der ComboBox der 
	 * Hauptkategorien
	 * 
	 * @author 	 *
	 */
	class ItemListenerForMainCatBox implements ItemListener {

		@Override
		public void itemStateChanged(ItemEvent e) {
			MainCategorie mainCat = null;
			ArrayList<SubCategorie> listOfSubCats = null;
			
			if(cbMainCatList.getSelectedItem() != null){
				mainCat = (MainCategorie) cbMainCatList.getSelectedItem();
				// Alles aus der Liste rausschmeißen
				cbSubCatList.removeAllItems();
				if(mainCat.getDescription() == "Alle"){
					cbSubCatList.setEnabled(false);
					listOfSubCats = SubCatManagement.getInstance().getSubCatList();
				}else {
					cbSubCatList.setEnabled(true);
					listOfSubCats = SubCatManagement.getInstance().filteredListByMainCat(mainCat);
				}
				
				// Liste mit neuen Items befüllen
				for(SubCategorie subCat : listOfSubCats)
					cbSubCatList.addItem(subCat);
				MainCatManagement.getInstance().setSelectedMainCatInBreadcrumb(mainCat);
				repaint();
			}			
		}
	}
	
	/**
	 * Klasse reagiert auf die Auswahl des Users
	 * in der ComboBox der Unterkategorien
	 * 
	 * @author 	 *
	 */
	class ItemListenerForSubCatBox implements ItemListener {

		@Override
		public void itemStateChanged(ItemEvent e) {
			SubCategorie subCat = null;
			ArrayList<Article> listOfArticles = null;
			
			if(cbSubCatList.getSelectedItem() != null){
				subCat = (SubCategorie) cbSubCatList.getSelectedItem();
				if(subCat.getDescription() == "Alle"){
					listOfArticles = ArticleManagement.getInstance().getArticleList();
				}else {
					listOfArticles = ArticleManagement.getInstance().getFilteredListOfArticles(subCat);
				}
				
				model.getListOfArticles().clear();
				model.setListOfArticles(listOfArticles);
			}
		}
	}

	
}
```


```
public class ArticleManagement extends Observable implements Observer {
	
	private ArrayList<Article> listOfArticles;
	private static ArticleManagement articleManagement = null;
	private DatabaseArticle dbArt = DatabaseFatory.getInstance().createDatabaseArticle();
	private Article selectedArticleInView = null;
	private ArrayList<Article> filteredListOfArticles = null;
	
	private ArticleManagement(){
		
	}
	
	public static ArticleManagement getInstance(){
		if(articleManagement == null)
			articleManagement = new ArticleManagement();
			
		
		return articleManagement;
	}
	
	
	public void setFilteredListOfArticles(ArrayList<Article> filteredListOfArticles) {
		this.filteredListOfArticles = filteredListOfArticles;
	}

	public ArrayList<Article> getFilteredListOfArticles(SubCategorie selectedSubCat) {
		if(filteredListOfArticles == null)
			filteredListOfArticles = new ArrayList<Article>();
		else
			filteredListOfArticles.clear();
		
		for(Article article : listOfArticles){
			if(article.getSubCat() == selectedSubCat.getId())
				filteredListOfArticles.add(article);
		}
		return filteredListOfArticles;
	}


}
```

Hoffe es ist nicht zu viel Code :autsch:


----------



## Shulyn (24. Mrz 2011)

Ollek hat gesagt.:


> Ist dieser weg der saubere? Habt ihr dort verbesserungsvorschläge??
> Möchte ja gerne was dazulernen.
> Freue mich auf eure Ratschläge udn die Kritik.. :rtfm:



Ja der weg ist sauber.
Verbessern könntest du noch das Ändern der Daten. Wenn sich nur wenig Daten im Model ändern sollte ein clear() unnötig sein. fireTableDataChanges sollte dies von sich aus durchführen.

Wenn du die Daten "nur" Filtern willst (Unterkategorien), könntest du dir ein filterableTableModel schreiben. Dann müsstest du nicht immer alle Daten neu rein stopfen. Kommt aber auf die Menge der Daten an. Bei einigen wenigen Einträgen wird es kaum ins gewicht fallen.


----------



## Ollek (24. Mrz 2011)

Shulyn hat gesagt.:


> Ja der weg ist sauber.
> Verbessern könntest du noch das Ändern der Daten. Wenn sich nur wenig Daten im Model ändern sollte ein clear() unnötig sein. fireTableDataChanges sollte dies von sich aus durchführen.
> 
> Wenn du die Daten "nur" Filtern willst (Unterkategorien), könntest du dir ein filterableTableModel schreiben. Dann müsstest du nicht immer alle Daten neu rein stopfen. Kommt aber auf die Menge der Daten an. Bei einigen wenigen Einträgen wird es kaum ins gewicht fallen.



Punkt 1 werde ich gleich umsetzen..

Also wir haben dort maximal 50 Artikel ja Unterkategorie drin.. Das sollte dann nicht ins gewicht fallen, oder?


----------



## Shulyn (25. Mrz 2011)

50 Artikel, ich denke das wird kaum einen unterschied machen


----------

