MVC - Anwendung auf mein Projekt

Ollek

Bekanntes Mitglied
Hallo,

ich habe einen Auftrag erhalten ein kleines Programm zu schreiben.
Auf diesem möchte ich nun das MVC Pattern anwenden.

Das Programm wird zum Upload von Jobs auf 3 Webserver benutzt.
Ein Job besteht aus Dateien.
Das ganze Programm soll eine GUI bekommen. Beim Start werden vorhandene Jobs in einer Tabelle aufgelistet. Jobs können ausgewählt werden und dann mit einem Button "Upload Starten" hochgeladen werden.

Nun möchte ich hier das MVC Pattern anwenden.

So sieht meine Auflistung aktuell aus:

Model
- Job

Controller
- JobController

View
- JMain
- JobTable
- JobTableModel

Den Code stelle ich euch auc mal zur Verfügung. Denn ich Frage mich nun, wie verwalte ich die verschiedenen Jobs nun in dem programm? Passiert das über die Controller klasse? Oder wie wird die Controller Klasse dort eingesetzt?

Java:
public class JMain extends JFrame {
	
	private JobTable table;
	private JobTableScrollPane spJobTable;
	

	public JMain() {
		init();
	}

	private void init() {
		this.setLayout(new BorderLayout());
		this.setTitle("UploadManager");
		this.setIconImage(createImageIcon("/icons/UploadManagerIcon.png").getImage());
		this.setSize(700, 300);
		this.setMinimumSize(new Dimension(700, 500));
		this.setLocationRelativeTo(null);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setResizable(false);
		
		table = new JobTable();
		spJobTable = new JobTableScrollPane(table);
		this.add(spJobTable, BorderLayout.CENTER);
		
		JobButtonBar toolbar = new JobButtonBar();
		this.add(toolbar, BorderLayout.SOUTH);
		
		this.setVisible(true);
	}
	
	/** Returns an ImageIcon, or null if the path was invalid. */
	protected ImageIcon createImageIcon(String path) {
	    URL imgURL = getClass().getResource(path);
	    if (imgURL != null) {
	        return new ImageIcon(imgURL);
	    } else {
	        System.err.println("Couldn't find file: " + path);
	        return null;
	    }
	}

	public JobTable getTable() {
		return table;
	}

	public void setTable(JobTable table) {
		this.table = table;
	}
	
}
Java:
public class JobTable extends JTable{
	
	private JobTableModel model;
	private Config config = Config.getInstance();
	private FileIO fileIO = new FileIO();
	
	public JobTable(){
		init();
	}

	private void init() {
		model = new JobTableModel(getData(fileIO.listFolders(config.getSourceRoot())));
		this.setModel(model);
		this.setAutoCreateRowSorter(true);
		this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		this.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
			
			@Override
			public void valueChanged(ListSelectionEvent e) {
				ListSelectionModel lsm = (ListSelectionModel)e.getSource();
				if(lsm.isSelectionEmpty()){
					
				}else{
					int selectedRow = lsm.getMinSelectionIndex();
					System.out.println(selectedRow);
				}
			}
		});
		
		
		JTableHeader tblHeader = this.getTableHeader();
		tblHeader.setResizingAllowed(false);
		tblHeader.setReorderingAllowed(false);
		
		// Spaltenbreite setzen
		this.getColumnModel().getColumn(0).setMaxWidth(43);
		this.getColumnModel().getColumn(1).setMinWidth(120);
		this.getColumnModel().getColumn(2).setMinWidth(450);
		this.getColumnModel().getColumn(3).setMinWidth(60);
			
	}
	
	private ArrayList<Job> getData(File[] files){
		ArrayList<Job> jobDataList = new ArrayList<Job>();
		for (File file : files) {
			String date = formatedDate(file.getName().substring(config.getFoldername().length()));
			Job jobObj = new Job(file.getName(), file.getPath(), date);
			jobDataList.add(jobObj);
		}
		return jobDataList;
	}
	
	/**
	 * Formatiert das Datum im EDV Format(YYMMDD) in ein
	 * Datum mit dem Basis Format (DD.MM.YYYY)
	 * 
	 * @param parmDate
	 * @return
	 */
	public String formatedDate(String parmDate){
		SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");
		String jahr= parmDate.substring(0, 2);
		String monat= parmDate.substring(3,4);
		String tag= parmDate.substring(4);
		Date date = null;
		try {
			date = sdf.parse(tag + "." +  monat + "." + "20" + jahr);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return sdf.format(date); 
	}
}

Java:
public class Job {
	
	private String sourceFolder;
	private String saveFolder;
	private String date;
	public boolean toUpload = false;
	private String name;
	
	public Job(String name, String sourceFolder, String date){
		this.setName(name);
		this.setSourceFolder(sourceFolder);
		this.setDate(date);
	}
	
	public String getSourceFolder() {
		return sourceFolder;
	}
	
	public void setSourceFolder(String sourceFolder) {
		this.sourceFolder = sourceFolder;
	}
	
	public String getSaveFolder() {
		return saveFolder;
	}
	
	public void setSaveFolder(String saveFolder) {
		this.saveFolder = saveFolder;
	}

	public String getDate() {
		return date;
	}

	public void setDate(String date) {
		this.date = date;
	}

	public boolean isToUpload() {
		return toUpload;
	}

	public void setToUpload(boolean toUpload) {
		this.toUpload = toUpload;
	}

	public String getName() {
		return name;
	}

Java:
public class JobController {
	
	private JMain _view;
	
	public JobController(){
		this._view = new JMain();
	}

}

Wie ihr seht steht im Controller nicht wirklich viel.. Da weiß ich aktuell leider nicht weiter ;(
Ich weiß auch nicht, wie ich die aktuellen Jobs die in der JTable angezeigt werden im Programm verwalten soll.
Schreibe ich mir dort eine JobVerwaltung?

Ich bräuchte son paar Denkanstöße von euch.. :rtfm:

Viele Grüße

P.S. habe euch nen Screenshot beigefügt, wie das ganze aktuell aussieht...
 

Anhänge

  • UM.jpg
    UM.jpg
    73,2 KB · Aufrufe: 54

ARadauer

Top Contributor
Macht der Controller zu wenig, macht die View wahrscheinlich zu viel ;-)
Model würde ich im Controller instanzieren und der GUI übergeben.
Daten würde ich im Controller laden und dem Model setzen, Model kann dan gui informieren, dass es sich geändert hat..
 

hdi

Top Contributor
Wie ihr seht steht im Controller nicht wirklich viel..
Darüber würd ich mir nicht zu viel Gedanken machen. AWT/Swing adaptiert das MVC-Pattern ja selbst schon. D.h. es existiert bereits ein Controller, namentlich EDT. Dieser ist in die Widgets integriert (Nein, ich behaupte nicht dass ein Thread in Objekte integriert ist, aber es gibt bestimmte Methoden die intern vom EDT aufgerufen werden, und es macht auch keinen Sinn das auszuhebeln und selbst nachzuimplementieren, zB Repaint-Events).

Es ist halt nicht das "reine" MVC, funktioniert aber auch. Meiner Meinung nach musst du dir jetzt nicht auf Teufel komm raus einen eigenen Controller aufzwingen. Du hast dein TableModel, leite von DefaultTableModel ab und du hast deine Controller-Schnittstelle in Form der fireXXX-Methoden und dem ganzen anderen implementierten Zeugs wie addXXX() etc. Natürlich kannst du dir noch einen eigenen Listener als Schnittstelle zwischen Model und TableModel machen, aber diese Controller-Klasse würd ich einfach mal über Bord werfen...
 
Zuletzt bearbeitet:

Ollek

Bekanntes Mitglied
Hallo,

also ich habe ex nun mal versucht etwas zu verstehen..

Das Model ist nur dafür, die Daten zu halten.
bei mir wäre es der Job.

Ein Job hat ein Namen, Datum, SourceDirectory, SourceFolders. Hier gibt es die passenden getter/setetr Methoden.

Dann gibt es die JTable, die mit dem JobTableModel agiert. Hier kümmert sich das Model um die Anziege der Daten in der Tabelle.

Nun habe ich noch einen JobController, der auf den btnUploadStart und btnUploadNew horch und ggf. das passende weitergibt. Sprich beim btnUploadStart, einen JobUpload startet und bei btnUploadNew eine neue Ordnerstruktur anlegt.

Jetzt komme ich nur noch nicht so drauf, wie ich den Controller strukturiere. Übergebe ich die Instanzen der JTable und des Models?
Für den Upload schreibe ich eine eigene klasse, wo ein Job übergeben wird, der dann hochgeladen werden soll... Oder habe ich jetzt zu kompliziert gedacht??

Wo und wie speichere ich die ganzen Jobs? Direkt beim Start in einer ArrayList und die übergebe ich direkt ans TableModel, oder wie funktioniert es "richtig"? Oder mach ich eine Klasse, die mit den ganzen Jobs arbeitet und verwaltet und übergebe diese dem Controller?? :rtfm:

Bin gespannt auf eure Antworten...
 
Zuletzt bearbeitet:

Michael...

Top Contributor
Jetzt komme ich nur noch nicht so drauf, wie ich den Controller strukturiere.
Musst Dir einfach nur überlegen, was gesteuert werden muss: Neue Jobs müssen erzeugt werden, der Upload muss gestartet werden... und das ganze muss graphisch dargestellt werden. Also muss der Controller
mitbekommen, wenn auf einen der Buttons gedrückt wird und welcher Job in der Tabelle selektiert ist.
Das heißt die View muss dem Controller mitteilen können, dass ein neuer Upload erstellt werden soll oder dass und welcher spezifische Upload gestartet werden soll, gleichzeitig muss er Änderungen beim (Table)Model einsteuern.
Wo und wie speichere ich die ganzen Jobs? Direkt beim Start in einer ArrayList und die übergebe ich direkt ans TableModel, oder wie funktioniert es "richtig"?
Würde ich in dem Fall zu machen.

Wenn man es einfach halten will, könnte man bei diesem überschaubaren Programm die JTable, Buttons und das TableModel direkt im "Controller" erstellen, ohne da noch eine "Gesamtview" Komponente dazwischen zu schieben.
 

Ollek

Bekanntes Mitglied
Hallo,

leider hatte ich in der letzten Woche wenig zeit mich ums Projekt zu kümmern.

Ich habe mir nun mal meine struktur etwas erweitert.

Ich habe nun eine

JMain - hier werden alle GUI Elemente auf das JFram platziert. Es gibt verschiedene getter Methoden, um an die einzelnen Elemente zu kommen (Bspw. getTable())

Hier der Code:

Java:
public class JMain extends JFrame {
	
	private JobTable table;
	private JobTableScrollPane spJobTable;
	JobButtonBar btnBar;
	
	public JMain() {
		init();
	}

	private void init() {
		this.setLayout(new BorderLayout());
		this.setTitle("UploadManager");
		this.setIconImage(createImageIcon("/icons/UploadManagerIcon.png").getImage());
		this.setSize(700, 300);
		this.setMinimumSize(new Dimension(800, 500));
		this.setLocationRelativeTo(null);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setResizable(false);
		
		table = new JobTable();
		spJobTable = new JobTableScrollPane(table);
		this.add(spJobTable, BorderLayout.CENTER);
		
		btnBar = new JobButtonBar();
		this.add(btnBar, BorderLayout.SOUTH);
		
		this.setVisible(true);
	}
	
	public JobTable getTable() {
		return table;
	}

	public void setTable(JobTable table) {
		this.table = table;
	}

Dann habe ich die JTable mit einem TableModel, die sich um das anzeigen der Jobs in einer Tabelle kümmert. Das wird von TableModel gesteuert. Aktuell ist es so, dass das TableModel weiß, welche Jobs angeklickt wurden und zum Upload markiert wurden. Ist das richtig so?
Denn meine Überlegung ist es, neben dem Job ein JobModel zu erstellen. Dieses JobModel weiß, welche Jobs aktuell in der Jtable angezeigt werden und welche selektiert wurden. Denn ich muss irgendwo meine ganzen Jobs, die ich am start einlese "verwalten". Das wollte ich durch das JOBModel machen.

Bisheriger Code zum JobModel

Java:
public class JobModel {
	
	private Config config = Config.getInstance();
	private ArrayList<Job> jobList;
	private FileIO fileIO;
	
	
	public JobModel(){
		setJobList(new ArrayList<Job>());
		fileIO = new FileIO();
	}


	public void listJobs(){
		File[] files = fileIO.listFolders(config.getSourceRoot());
		for (File file : files) {
			createJob(file);
		}
		
	}
	
	private void createJob(File file) {
		
		
	}


	public ArrayList<Job> getJobList() {
		return jobList;
	}


	public void setJobList(ArrayList<Job> jobList) {
		this.jobList = jobList;
	}

Und natürlich gibts die Kalsse Jobs noch, die ein Job Object darstellt. Diese habe ich im ersten post schon beigefügt.

Der Controller steuert dann die Action Auslösungen, die der user tätigt. Das Anlegen eines neuen Jobs und das Starten eines Uploads der Job.

habe ich die richtigen gedanken um das MVC richtig anzuwenden??

Wäre nett wenn ihr mir hier nocht helfen würdet....

Viele Grüße
 
V

vanny

Gast
Naja fast ^^

Ich habe mir deinen Code jetzt nicht durchgeschaut, aber das Model sollte nicht wissen, was in der GUI geschieht, also auch nicht, welche Jobs ausgewählt wurden.
Dazu ist dein Controller also dein Button zuständig, der holt sich die passenden Jobs aus deinem Model und verschickt die Jungs.

Gruß Vanny
 

Ollek

Bekanntes Mitglied
Das ist klar.

Also der Controller packt so gesehen einen selektierten Job in die Liste für ausgewählte Jobs im Model, oder??

Macht es Sinn, GUI Elemente sprich hier JTable und JTableModel im Controller zu instanzieren??
sonst wird es schwierig an die verschiedenen ausgewählten Jobs zu kommen, denn nur das JTableModel weiß, welche ausgewählt wurden :-(
 
V

vanny

Gast
... denn nur das JTableModel weiß, welche ausgewählt wurden :-(

genau da liegt noch der Denkfehler bei dir ^^.

Das Model weiß nix von der GUI.
Wo du die GUI und das Model instanzierst ist nicht festgeschrieben, aber du solltest dem Controller auf jeden Fall jeweils eine Referenz mitgeben, damit er halt an beides rankommt.

Gruß Vanny

//Edit: Der Controller holt sich die selektierten Jobs z.Bsp. per Key oder Index aus der View, holt sich dann die Richtigen Job-Objekte aus dem Model und schickt den Kram dann wech.
 
Zuletzt bearbeitet von einem Moderator:

Ollek

Bekanntes Mitglied
Eventuell reden wir etwas aneinander vorbei..

Also das JTableModel extends AbstractTableModel, das ist für die JTable zuständig, damit diese die passenden Daten anzeigt. Und da ich eine Spalte als boolean deklariert habe, und durch den TableModelListener wird hier auf änderen dort gehorcht. Wenn dort true drin steht, ist der job relevant für den Upload..

Das JobModel, weclhes die selektierten Jobs und alle Jobs beinhaltet und den Controller informiert, dass eventuell ein neuer Job jinzugekommen ist und der es an die View weitergibt, dieses Model kennt die View gar nicht, sondern nur der Controller...

Ist doch jetzt der richtige Gedanke, oder? ^^

Dann habe ich nun die JMain (wo die ganze GUI zusammengebaut wird) und das JobModel im Controller instanziert. Die JMain hat noch weitere Panels, Bsp. das panel mit den Buttons oder die ScrollPane mit der JTable. Auf die Buttons und JTable greife ich ihm Controller über die getMethode zu. Ist das eine schöne Programmierung? Anders weiß ich nicht, wie es realisierbar sein sollte. ^^ Oder ich habe nen derben gedankenfehler drin.

Hier mal nen Beispiel aus der Controller Klasse:

_view.getTable().getModel().setJobList(_model.getJobList());

Dadurch erhält das JTableModel die aktuell verfügbaren Jobs, aus dem JobModel.

Das soltle doch soweit passen, oder?

Weiteres Beispiel aus dem Controller, der Listener für den Button wird gesetzt.

_view.getBtnBar().setUploadStartListener(new UploadStartListener());

Viele Grüße
 

Michael...

Top Contributor
Das JobModel, weclhes die selektierten Jobs und alle Jobs beinhaltet und den Controller informiert, dass eventuell ein neuer Job jinzugekommen ist und der es an die View weitergibt, dieses Model kennt die View gar nicht, sondern nur der Controller...
Macht es Sinn hier zwischen JobModel und TableModel zu trennen? Ich denke mal das in der JTable doch auch der aktuelle Status der Jobs dargestellt werden soll(te)? z.B. Job ist für Upload eingeplant, Job wird aktuell hochgeladen, Upload des Jobs abgeschlossen...
Eventuell könnte der Job seinen Status selbst verwalten.

Ich hab's jetzt nicht mehr in Erinnerung, aber würde mir sowas vorstellen:
- JTable zeigt Liste möglicher Jobs an
- Anwender selektiert Job(s) und drückt einen Upload Button
- Controller wird über ActionListener des Buttons darüber informiert und holt sich die selektierten Jobs. Diese steckt er entweder in eine Upload Queue oder startet direkt den Uploadprozess. Anschließend übergibt er die Statusänderung an das TableModel oder setzt den Status des Jobs

Also benötigt man grundsätzlich vier Klassen für:
Controller, GUI (bestehend aus JTable und Button), TableModel und Job
Falls man den Upload noch auslagert, bräucht man noch einen Upload Controller
 

Ollek

Bekanntes Mitglied
Macht es Sinn hier zwischen JobModel und TableModel zu trennen? Ich denke mal das in der JTable doch auch der aktuelle Status der Jobs dargestellt werden soll(te)? z.B. Job ist für Upload eingeplant, Job wird aktuell hochgeladen, Upload des Jobs abgeschlossen...
Eventuell könnte der Job seinen Status selbst verwalten.

Ich hab's jetzt nicht mehr in Erinnerung, aber würde mir sowas vorstellen:
- JTable zeigt Liste möglicher Jobs an
- Anwender selektiert Job(s) und drückt einen Upload Button
- Controller wird über ActionListener des Buttons darüber informiert und holt sich die selektierten Jobs. Diese steckt er entweder in eine Upload Queue oder startet direkt den Uploadprozess. Anschließend übergibt er die Statusänderung an das TableModel oder setzt den Status des Jobs

Also benötigt man grundsätzlich vier Klassen für:
Controller, GUI (bestehend aus JTable und Button), TableModel und Job
Falls man den Upload noch auslagert, bräucht man noch einen Upload Controller

Also der Job hat einen boolean toUpload. Dieser wird durch das JTableModel auf true bzw. false gesetzt. Je nach dem, ob der User diesen Job hochladen möchte oder nicht. Die GUI habe ich schon in 4 Klassen aufgeteilt(JobTable, JobTableScrolPane, JMain und JButtonBar). In der JMain werden alle instanziert. Somit ist die JMain mein GUI Herzstück. Sobald der Buton gedrückt wird, löst er ein Event im Contrller aus, der den upload startet. Der Job wird an einen Upload übergeben, entweder File oder FTP Upload.
Das TableModel weiß, welche Jobs selektiert wurden und welche nicht. Hier stehe ich noch davor, wie ich diese weitergebe. Aber der tableModelListener ist doch richtig in dem TableModel, oder nicht?

Also der controller kann sich die Jobs aus dem TableModel holen, da dort eine ArrayList mit den ganzen Jobs sowie aktuell selektierten Jobs befindet. Ist das sinnvoll??

Ja es macht schon Sinn zwischen einem UI abhängigen Model und einem Business Model zu trennen.

Schon mal überlegt einen EventBus einzusetzen anstatt reines MVC, wird immer populärer siehe GWT, e4 usw.

EventBus? Das sagt mir gar nichts, müsste ich mal googlen.. Ich wollte nur mal das MVC ausprobieren und verstehen :rtfm::rtfm:
 

Ollek

Bekanntes Mitglied
Habe jetzt mal einen Vorschlag, wie es bei dem Projekt aussieht...

Also als Beispiel, wenn ein job in der JobTable selektiert wurde, wird dieser im TableModel in eine ArrayList gespeichert(seletedJobs). Diese kann mit einen getter vom Controller geholt werden, wenn der User auf Upload starten gedrückt hat. Der Controller stößt dann für jeden Job einen Upload an. Der Upload kopiert die Dateien auf Webserver und FTP Server und verschiebt se in den "erledigt" Ordner.
Danach wird die JTable, durch den Controlelr aktualisiert. Hier gibt er die aktuellen Jobs wiederunm an das TableModel und dieses kümmer sich um die Anzeige in der Tabelle.

Damit ihr euch etwas mehr darunter vorstellen könnt, habe ich euch die Klassen beigefügt...

Job-Klasse, hier ist nur wichtige, was übergeben wird beim anlegen eines Jobs.
Java:
public Job(String name, String sourceDirectory, File[] sourceFolders){
		this.setName(name);
		this.setSourceDirectory(sourceDirectory);
		this.setSourceFolders(sourceFolders);
		if(!name.isEmpty())
			this.setDate(formatedDate(name.substring(config.getFoldername().length())));
	}

Dann die JTable für die Jobs. Hier wird nur mit angezeigt, sprich dort befinden sich keine Daten! Die Tabelle ist dumm ;-)
Java:
public class JobTable extends JTable {
	
	private JobTableModel model;
	private Config config = Config.getInstance();
	private FileIO fileIO = new FileIO();
	
	
	public JobTable(){
		init();
	}

	private void init() {
		model = new JobTableModel();			

		this.setModel(model);
		this.setAutoCreateRowSorter(true);
		this.setSurrendersFocusOnKeystroke(true);
		this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);	
		
		// Setzen der passenden Ausrichtung innerhalb der Zelle
		this.setDefaultRenderer(Object.class, new DefaultTableCellRenderer()
		{
			public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
			{
				/* Sollten die Spalten durch den User neu sortiert sein,
				 * dann haben die spalten einen neuen Index. Man benötigt den Modelindex
				 */
				final int modelColumn = table.convertColumnIndexToModel(column);
				switch (modelColumn)
				{
						/* alignment left setzen */
					default :
						setVerticalAlignment(JLabel.TOP);
				}
				return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
			}
		});
		
		// Tabellen Header Einstellungen - aktuellen holen, von der JTable um damit abreiten zu können
		JTableHeader tblHeader = this.getTableHeader();
		tblHeader.setResizingAllowed(false);
		tblHeader.setReorderingAllowed(false);
				
		// Spaltenbreite setzen
		this.getColumnModel().getColumn(0).setMaxWidth(43);
		this.getColumnModel().getColumn(1).setMinWidth(120);
		this.getColumnModel().getColumn(2).setMinWidth(380);
		this.getColumnModel().getColumn(3).setMinWidth(60);
		this.getColumnModel().getColumn(4).setMinWidth(60);
		
		
		TableColumn column = this.getColumnModel().getColumn(3);
		column.setCellRenderer(new TwoLinesCellRenderer());
			
	}
	

	
	public JobTableModel getModel(){
		return model;
	}
	

	/**
	 * Renderer für eine mehrzeilige Zellen.
	 * 
	 * @author 
	 *
	 */
	class TwoLinesCellRenderer extends JTextArea implements TableCellRenderer {

		@Override
		public Component getTableCellRendererComponent(JTable table,
				Object value, boolean isSelected, boolean hasFocus, int row,
				int column) {
			
			if (isSelected){		    	
	      		setForeground(table.getSelectionForeground());
	      		setBackground(table.getSelectionBackground());
		    }	 
	    	else{
	      		setForeground(table.getForeground());
	      		setBackground(table.getBackground());
	    	} 
			
			setFont(table.getFont());
			setText(value.toString());
			
			if (table.getRowHeight()!= (int) this.getMinimumSize().height) 
				table.setRowHeight(row, (int) this.getMinimumSize().height);
			
			return this;
		}
	}]

Das TabelModel, was sich um die Daten in der Tabelle kümmert.
Java:
public class JobTableModel extends AbstractTableModel {
	
	//Columns Number.
    public static final int    JOB_SEL_COL = 0;                                   
    public static final int    JOB_NAME_COL = 1;
    public static final int    JOB_SOURCE_COL = 2;
    public static final int    JOB_FOLDERS_COL = 3;
    public static final int    JOB_DATE_COL = 4;
	
    private String[] columnNames = new String[]{"Upload", "Job Name", "Verzeichnis", "Unterordner", "Datum" };
	private ArrayList<Job> jobList;
	private ArrayList<Job> jobListSeleted;
	
	public JobTableModel(){
		super(); 
		this.jobList = new ArrayList<Job>();
		this.jobListSeleted = new ArrayList<Job>();
		this.addTableModelListener(new TableModelListener() {
			
			@Override
			public void tableChanged(TableModelEvent e) {
				int column = e.getColumn();
				int row = e.getFirstRow();
				System.out.println("In Zeile " + row + " Spalte " + column);			
				//aktuellen Job holen
				Job job = (Job) getValueAt(row);
				if(job.isToUpload())
					jobListSeleted.add(job);
				else
					jobListSeleted.remove(job);
			}
		});
	}
	
	
	@Override
	public int getColumnCount() {
		return columnNames.length;
	}

	@Override
	public int getRowCount() {
		return jobList.size();
	}
	
	/**
	 * Aktualisiert die Daten im TableModel
	 * nachdem diese in der Tabelle geändert 
	 * wurden
	 */
	public void setValueAt(Object value, int row, int col){
		
		Job job = jobList.get(row);	
		switch(col){
		case JOB_SEL_COL: job.setToUpload((Boolean)value); break;
		case JOB_NAME_COL: job.setName((String)value); break;
		case JOB_SOURCE_COL: job.getSourceDirectory(); break;
		case JOB_FOLDERS_COL: value.toString(); break;
		case JOB_DATE_COL: job.setDate((String)value); break;
		}
		fireTableCellUpdated(row, col);
	}

	/**
	 * Gibt den Wert, welcher sich in den 
	 * übergebenen Parametern befindet zurück
	 * 
	 */
	@Override
	public Object getValueAt(int row, int column) {
		Job job = jobList.get(row);
		
		String folders = "";
		for (File folder : job.getSourceFolders()) {
			if(folders.isEmpty())
				folders += folder.getName();
			else
				folders += "\n" + folder.getName();
		}		
		
		switch(column){
		case JOB_SEL_COL: return job.isToUpload();
		case JOB_NAME_COL: return job.getName();
		case JOB_SOURCE_COL: return job.getSourceDirectory();
		case JOB_FOLDERS_COL: return folders;
		case JOB_DATE_COL: return job.getDate();
		}
		return new Object();
	}
	
	/**
	 * Gibt das Object zurück, was sich
	 * in der übergebenen Zeile befindet
	 * zurück
	 * 
	 * @param row
	 * @return
	 */
	public Object getValueAt(int row){
		return jobList.get(row);
	}
	
	public String getColumnName(int iColumn){
		return columnNames[iColumn];
	}
	
	// passendes Format in der Spalte wird angezeigt
	public Class getColumnClass(int columnIndex){
		return getValueAt(0, columnIndex).getClass();
	}
	
	public boolean isCellEditable(int row, int col) {
        //Note that the data/cell address is constant,
        //no matter where the cell appears onscreen.
        if (col == 0)
            return true;
        
            return false;
    }
	
	public ArrayList<Job> getSelectedJobs() {
		return jobListSeleted;
	}

	public void setSelectedJobs(ArrayList<Job> arrlSelectedJobs) {
		this.jobListSeleted = arrlSelectedJobs;
	}
	
	public ArrayList<Job> getJobList() {
		return jobList;
	}


	public void setJobList(ArrayList<Job> jobList) {
		this.jobList.clear();
		if(jobList.size() > 0){
			this.jobList = jobList;
			this.fireTableDataChanged();
		}else
			jobList.add(new Job("", "", null));
	}

Der Job Controller, der auf die Aktionen vom User agiert und die View, sowie das Model kennt.
Java:
public class JobController {
	
	private JMain _view;
	private JobModel _model;
	private FileIO fileIO;
	private Config config = Config.getInstance();
	
	public JobController(){
		this._view = new JMain();
    	this._model = new JobModel();
		fileIO = new FileIO();
		
    	_view.getTable().getModel().setJobList(_model.getJobList());
    	
		addListener();
	}
	
	public void addListener(){
		_view.getBtnBar().setUploadStartListener(new UploadStartListener());
		_view.getBtnBar().setCreateFolderListener(new CreateFolderListener());
	}
	
	class UploadStartListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			ArrayList<Job> selectedJobs = _view.getTable().getModel().getSelectedJobs();
			for (Job job : selectedJobs) {
				Upload fileUpl = new Upload(job);
				boolean result_upload = fileUpl.upload();
				if(result_upload)
					result_upload = fileUpl.copyInSaveAndDelete();
				if(result_upload)
					updateJobList();
				
			}
		}
		
	}

	
	class CreateFolderListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
			Date date = new Date();
			String strDate = sdf.format(date);
			_model.createJob(config.getSourceRoot() + config.getFoldername() + strDate);
			updateJobList();
		}
		
	}
	public void showView() {
		this._view.setVisible(true);		
	}

	private void updateJobList(){
		_view.getTable().getModel().setJobList(_model.listJobs());
	}

Und natürlich das JobModel. Das JobModel kennt alle vorhandenen Jobs, die im Dateisystem vorhanden sind.
Wird ein neuer Job angelegt, wird von Controller der Job an das Model übergeben.
Java:
public class JobModel {
	
	private Config config = Config.getInstance();
	private ArrayList<Job> jobList;
	private ArrayList<Job> jobSelectedList;
	private FileIO fileIO;
	
	
	public JobModel(){
		fileIO = new FileIO();
		
		this.jobList = listJobs();
	}

	/**
	 * Es werden alle vorhandenen
	 * Jobs aus dem Dateisystem als Job-Objekt 
	 * angelegt
	 * 
	 * @return
	 */
	public ArrayList<Job> listJobs(){
		File[] files = fileIO.listFolders(config.getSourceRoot());
		ArrayList<Job> jobDataList = new ArrayList<Job>();
		for (File file : files) {
			Job jobObj = new Job(file.getName(), file.getPath(), file.listFiles());
			jobDataList.add(jobObj);
		}
		return jobDataList;
	}
	
	/**
	 * Neue Ordnerstruktur für
	 * einen Job wird angelegt
	 * 
	 * @param dirName
	 */
	public void createJob(String dirName) {
		fileIO.createDirectory(dirName);
	}

	public ArrayList<Job> getJobList() {
		return jobList;
	}

	public void setJobList(ArrayList<Job> jobList) {
		this.jobList = jobList;
	}
	
	public void addSelectedJob(Job job){
		jobSelectedList.add(job);
	}
	
	public void removeSelectedJob(Job job){
		jobSelectedList.remove(job);
	}

Würde mich über eure Beurteilung freuen. Kommt dieses son bisschen ans MVC ran? Ich denke habe mir nen flasches Projekt fürs MVC ausgesucht. Eventuell hätte ich es hier auch nicht anwenden müssen, aber wollte dies gerne testen. Was sagt ihr sonst zur Aufteilung der einzelnen Klassen?

Freue mich auf Eure Verbesserungsvorschläge!!

VG
 

Anhänge

  • UploadManager.jpg
    UploadManager.jpg
    74,6 KB · Aufrufe: 34

hdi

Top Contributor
Also ich bin nur kurz drübergeflogen, und kann jetzt nichts zum Großen Ganzen sagen. Aber ein paar Kuriositäten bzw. Unfeinheiten sind mir aufgefallen.

z.B., was hast du dir dabei gedacht:

Java:
switch (modelColumn)
{
      /* alignment left setzen */
      default :
           setVerticalAlignment(JLabel.TOP);
}

Dahingegen wäre solch eine default-Klausel in deiner getValueAt-Methode angebracht:

Java:
default: return new Object();

Dann ein kleines Vergehen gegen Coding Convetions, bei dem if-Statement:

Java:
public boolean isCellEditable(int row, int col) {
        //Note that the data/cell address is constant,
        //no matter where the cell appears onscreen.
        if (col == 0)
            return true;
        
            return false;
}

Anweisungen nach einem if immer in {}-Klammern, selbst wenn es nur eine einzige Anweisung ist. Besser noch kannst du hier auch einfach schreiben:
Code:
return col == 0;

Als nächstes noch ein Verstoß gegen Naming Conventions: _view -> view

Und als letztes solltest du die inneren Klassen wie zB den Renderer private machen. Wenn du deiner Tabelle schon eine eigene Klasse spendierst, dann kann sie ihren Renderer ja gleich richtig kapseln. Es sei denn, du hast einen guten Grund dafür warum die inneren Klassen nicht private sind?

Naja und ich würde vllt noch die Leerzeilen im Source Code bewusster einsetzen. Scheint z.T. recht willkürlich. Ich finde es hilft immer sehr, wenn du zusammenhängende Logik auch als zusammenhängenden Block schreibst, also rein optisch. Dazu zählt auch dass nach der letzten Anweisung in einem Code-Block nicht noch 5 Leerzeilen folgen bevor der Block geschlossen wird. Das ist einfach unschön, sieht noch recht Baustellen-mäßig aus der Code.

Was das zusammenhängende Design angeht hab ich wie gesagt nicht wirklich geschaut. Sieht auf den ersten Blick aber so verkehrt nicht aus.
 
Zuletzt bearbeitet:
Ähnliche Java Themen
  Titel Forum Antworten Datum
K Java Anwendung machen Anleitung Allgemeine Java-Themen 5
P JavaFX Anwendung beendet sich selbst nur als Jar Allgemeine Java-Themen 40
OSchriever Externe Anwendung beenden Allgemeine Java-Themen 41
I Eine Anwendung so gut wie möglich beschützen Allgemeine Java-Themen 9
J exe Anwendung CPU-/Speicherverbauch Allgemeine Java-Themen 5
alderwaran Hoher Sys-Load bei Multithreaded Anwendung Allgemeine Java-Themen 8
S Anwendung die alle Abhaengigkeiten einer Library listet..? Allgemeine Java-Themen 5
P Methoden Anwendung der allMatch()-Methode Allgemeine Java-Themen 5
D Anwendung öffnet hinter Taskleiste Allgemeine Java-Themen 7
I Anwendung auf Netzlaufwerk von mehreren Usern gleichzeitig nutzbar. Allgemeine Java-Themen 3
A Garbage Collector in NetBeans vs. exe Anwendung Allgemeine Java-Themen 33
D Java Anwendung mit dll File Allgemeine Java-Themen 5
B JAVA Prozesse in einer eigenen Anwendung laufen lassen Allgemeine Java-Themen 9
D RMI Einfache Chat-Anwendung mit RMI Allgemeine Java-Themen 0
J Jasper ireport - wieso beendet die Anwendung wenn ich die Preview schließe Allgemeine Java-Themen 1
Tort-E Datenmodell / Struktur der Anwendung Allgemeine Java-Themen 4
E Anwendung verhält sich unter Mac anders als Unter Windows. Allgemeine Java-Themen 4
S Anwendung zum ausrechnen der Differenz von zwei Tagen Allgemeine Java-Themen 9
B Web-Anwendung funktioniert mit Java 1.8, aber nicht mit Java 1.7 (auf Client) Allgemeine Java-Themen 5
L Stack overflow bei einer endrekursiven Funktion (Anwendung: Spezialform des Package Merge) Allgemeine Java-Themen 4
P Anwendung läuft nur mit JDK Allgemeine Java-Themen 2
D Java-Anwendung mit DB, GUI, etc. Allgemeine Java-Themen 3
D OOP Design Pattern für GUI - Datenbank Anwendung Allgemeine Java-Themen 1
F Unlimited Strength Policy. Frage Verbreitung der Anwendung Allgemeine Java-Themen 1
T Bot für Mql-Anwendung Allgemeine Java-Themen 10
F Java Anwendung Remote starten geht nicht Allgemeine Java-Themen 0
D neuen Prozess starten und anwendung beenden. Allgemeine Java-Themen 3
L Input/Output IO Anwendung Allgemeine Java-Themen 6
M Suche Framework/API für Monitoring-Anwendung Allgemeine Java-Themen 3
M Problem beim Starten der Anwendung Allgemeine Java-Themen 3
C Anwendung läuft nicht auf Mac OS X Allgemeine Java-Themen 2
M Java Anwendung ausführen Allgemeine Java-Themen 5
eskimo328 Swing Client Anwendung für MAC OS (Update Routine) Allgemeine Java-Themen 6
M Process wird gestoppt und nach beenden der Anwendung fortgeführt Allgemeine Java-Themen 4
J Interpreter-Fehler Anwendung startet nicht Allgemeine Java-Themen 5
W Framework für RichClient Anwendung? Allgemeine Java-Themen 4
D Mini Webserver für GUI Anwendung Allgemeine Java-Themen 5
U (Land-)Karten in Java Anwendung einbinden (GoogleMaps/OpenStreetMap) Allgemeine Java-Themen 7
S "Katalog"-Anwendung in Java eine gute Idee? Allgemeine Java-Themen 12
S Wie eine verteilte Anwendung in die Cloud? Allgemeine Java-Themen 4
E Anwendung nutzt plötzlich nicht mehr 100% CPU Allgemeine Java-Themen 2
R Geht das? JRE 1.4 global, 1.6.20 nur für eine Anwendung? Allgemeine Java-Themen 9
K Anwendung bringt JAVA Speicherfehler Allgemeine Java-Themen 11
C Java Anwendung nur einmalig starten Allgemeine Java-Themen 10
eskimo328 Offline/Online Web-Anwendung, Datensynchronisation etc. Allgemeine Java-Themen 9
E Anwendung starten Allgemeine Java-Themen 3
W Java Anwendung in HTML Allgemeine Java-Themen 2
DEvent Aktuelle Uhrzeit per Anwendung Allgemeine Java-Themen 4
C Idee für Anwendung/ Bücher Allgemeine Java-Themen 8
Y Anwendung starten(JAR) - Entscheidung Konsole oder Swing Allgemeine Java-Themen 5
P Java Anwendung mehr Speicher zur Verfügung stellen?? Allgemeine Java-Themen 3
C Kontextmenü erweitern und mit Java Anwendung verknüfen. Allgemeine Java-Themen 3
7 Problem mit webbasierter Anwendung Allgemeine Java-Themen 6
D Java Anwendung in der Shell Allgemeine Java-Themen 5
D Versuch Server - Client anwendung Allgemeine Java-Themen 9
T Welcher Server? JSP und Client-Anwendung Allgemeine Java-Themen 4
M Anwendung des MVC Konzepts Allgemeine Java-Themen 7
R Ausführbare Java Anwendung Allgemeine Java-Themen 27
A Java-Anwendung "richtig" schließen ohne JVM zu beenden Allgemeine Java-Themen 2
B In Anwendung jar file bauen Allgemeine Java-Themen 2
A Webspace für Grails-Anwendung Allgemeine Java-Themen 3
M WebStart Anwendung nicht dauerhaft Cachen Allgemeine Java-Themen 3
A An alle Cracks: Anwendung beenden mit ShutdownHook? Allgemeine Java-Themen 13
D Anwendung startet im Remote Desktop nicht Allgemeine Java-Themen 14
S Testen einer Anwendung durch klicken von Koordinaten Allgemeine Java-Themen 7
M SMS aus Desktop-Anwendung verschicken Allgemeine Java-Themen 8
G Unterschied Enterprise Anwendung und Web Anwendung Allgemeine Java-Themen 30
? Swing Anwendung aus Konsole starten Allgemeine Java-Themen 7
G Weboberfläche für Java Anwendung? Allgemeine Java-Themen 10
Y ProcessBuilder, Prozess wird gestartet, aber Anwendung nicht Allgemeine Java-Themen 5
S jar aus anwendung heraus ausführen Allgemeine Java-Themen 2
J Konsolen Anwendung mit while(true) Allgemeine Java-Themen 6
-MacNuke- Frage zu einer 3-Tier Anwendung Allgemeine Java-Themen 9
M Anwendung nur einmal starten / Zeichen in String zählen Allgemeine Java-Themen 7
F Hilfe beim Starten einer Java Anwendung unter Windows gesuch Allgemeine Java-Themen 8
L Java 1.5 - Anwendung unter 1.6 JRE sehr langsam geworden Allgemeine Java-Themen 8
B getResourceAsStream - standalone Anwendung vs. Web-Anwendung Allgemeine Java-Themen 2
J I18n einer existierenden Anwendung Allgemeine Java-Themen 2
C Java-Anwendung beenden Allgemeine Java-Themen 3
G Auslesen mit welcher Java-Version Anwendung kompiliert wurde Allgemeine Java-Themen 2
C Anwendung nur einmal Starten Allgemeine Java-Themen 11
Z Uralt-Applet in JFrame Anwendung konvertieren Allgemeine Java-Themen 12
J OpenOffice.org Events in eigene Anwendung umleiten Allgemeine Java-Themen 4
T Socket Server Anwendung - Empfang eines Byte-Arrays Allgemeine Java-Themen 7
G Datenbank-Anwendung schnell erstellen. Allgemeine Java-Themen 7
M Versionswechsel bei einer Web-Anwendung Allgemeine Java-Themen 5
A Client/Server-Anwendung Allgemeine Java-Themen 3
G java als anwendung? Allgemeine Java-Themen 11
N externe Anwendung aktivieren (nicht starten!) Allgemeine Java-Themen 3
L Speicherverbrauch einer Anwendung unter Windows Allgemeine Java-Themen 2
C Fehler bei der Anwendung von Transformen. Allgemeine Java-Themen 2
M 1. Probleme mit MouseListener, 2. Anwendung in Infobar Allgemeine Java-Themen 8
P Anwendung minimiert starten Allgemeine Java-Themen 11
G Java Anwendung für Multi-User Allgemeine Java-Themen 2
N Linux-Commands über Java Anwendung ausführen Allgemeine Java-Themen 12
E Anwendung ließt .ini-Datei nicht Allgemeine Java-Themen 3
M Java-Anwendung von CD-ROM Allgemeine Java-Themen 19
E externe Anwendung aufrufen und sich selbst beenden Allgemeine Java-Themen 8
M Datei auf Anwendung ziehen und starten Allgemeine Java-Themen 11
T unsatisfiedlinkerror -> Diese Anwendung konnte nicht gest Allgemeine Java-Themen 2

Ähnliche Java Themen

Neue Themen


Oben