Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Wie mache ich einem JPanel mein bereits instanziertes Model bekannt
ich habe versucht meinem Programm die MVC-Struktur zugrunde zu legen.
Die Klasse ProgrammTest enthält die main-Methode.
Java:
public class ProgrammTest {
private static ProgrammModel model;
private static ProgrammView view;
private static ProgrammController controller;
/**
* @param args
* Startet die Anwendung
*/
public static void main(String[] args) {
model = new ProgrammModel();
view = new ProgrammView();
view.createAndShowGUI();
controller = new ProgrammController(view, model);
}
}
In der Klasse ProgrammView benutze ich ein JPanel, mit welchem ich gerne auf Methoden des Models zugreifen würde. Jetzt würde ich gerne wissen, wie ich an das Model, welches in ProgrammTest instanziiert wurde. Müsste ich es dafür als Einzelstück implementieren? Das wollte ich nämlich eigentlich vermeiden.
Ich weiß nicht, ob es für das Problem relevant ist, was mich aber auch ein wenig irritiert ist, dass die Klasse ProgrammView bei mir auch keine Kenntnis vom Model hat. Kann es sein, dass hier bei mir ein prinzipieller Strukturfehler vorliegt?
Bei MVC kennt die View in der Regel das Model.
Während das Model die View nur indirekt benachrichtigt (Listener).
Richtig ist es beim Controller. Der kennt sowohl die View als auch das Model. Die View benachrichtigt den Controller wieder indirekt.
Um also auf dein Model in deiner View zugreifen zu können, musst du das Model der View übergeben.
Ein Merkmal des MVC ist, dass die View das Model kennt und eine Referenz darauf hält.
Zur Veranschaulichung der Zusammenhänge zwischen den Komponenten, siehe z.B. Abbildung auf folgender Seite: Model View Controller ? Wikipedia
Ich danke Euch und habe das nun korrigiert. Das erste Teil des Problem besteht allerdings immer noch.
Die Klasse ProgrammView kümmert sich um den Aufbau des Fensters. Darin verwende ich unter anderem eine Klasse DrawingArea, die von JPanel erbt, als Zeichenfläche. Um jetzt beim Überschreiben der paintComponent-Methode auf Methoden des Models zugreifen zu können, brauche ich hier ja ebenfalls eine Referenz auf das Model. Ich habe nur leider keine Idee, wie ich das am geschicktesten machen soll.
Hat jemand da einen Tipp?
Die View darf -falls nötig - selbstverständlich eine Referenz auf ihr Model an Subkomponenten weiterreichen.
Ich würde mir das aber ganz genau überlegen. Oft reicht es aus, dass die View (die ja letztendlich "Controller" ihrer Subkomponenten ist) bei Änderungsmeldung des Models die notwendigen Werte an die Subkomponente weiterreicht.
Hab gerade in den letzten paar Tagen eine kleine App mit Swing und SWT View geschrieben - ich kommt ja sonst nicht aus dem Fat Client Bereich Aber da hab ichs ganz einfach gemacht: Controller hört beim Model und der View. Wenn sich das Model updated, dann leitet dies - falls nötig - der Controller an die View weiter, welche ein repaint macht. Wenn vom GUI ein Command (F*-Taste, Menu, ...) an den Controller geleitet wird, dann updated dieser natürlich wieder ensprechend das Model (welches sich dann wieder beim Controller meldet usw.).
Die View darf -falls nötig - selbstverständlich eine Referenz auf ihr Model an Subkomponenten weiterreichen.
Ich würde mir das aber ganz genau überlegen. Oft reicht es aus, dass die View (die ja letztendlich "Controller" ihrer Subkomponenten ist) bei Änderungsmeldung des Models die notwendigen Werte an die Subkomponente weiterreicht.
Ich glaube, ich weiß immer noch nicht so ganz genau, was du meinst.
Ich werde mal versuchen, so gut es geht, meine Struktur zu abstrahieren, sodass wir hier etwas konkreten Code haben.
ProgrammView
Java:
package view;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import model.ProgrammModel;
public class ProgrammView {
private JFrame frame;
private JScrollPane scrollPaneForDrawingArea;
private JTabbedPane tabbedPaneForDrawingArea;
private JPanel rightWindowSide;
private JSplitPane contentSplitPane;
private JPanel contentPane;
private DrawingArea drawingArea;
private JMenuBar menuBar;
private JMenu menuDatei;
private JMenuItem menuItemNeu;
private JMenuItem menuItemOeffnen;
private JMenuItem menuItemSpeichern;
private JMenuItem menuItemSchliessen;
private JMenu menuBearbeiten;
private JMenu submenuHinzufügen;
private JMenuItem menuItemKreisHinzufuegen;
private JMenuItem menuItemRechteckHinzufuegen;
private JMenuItem menuItemPfeilHinzufuegen;
private PetrinetzEditorModel model;
public PetrinetzEditorView(PetrinetzEditorModel model) {
super();
this.model = model;
}
public void createAndShowGUI() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(createContentPane());
frame.setJMenuBar(createMenuBar());
frame.pack();
frame.setVisible(true);
}
private JPanel createContentPane() {
// Zeichenfläche innerhalb eines Scroll-Panes
scrollPaneForDrawingArea = new JScrollPane(createDrawingArea());
// Linkes Element für contentSplitPane
tabbedPaneForDrawingArea = new JTabbedPane();
tabbedPaneForDrawingArea.setTabPlacement(JTabbedPane.BOTTOM);
tabbedPaneForDrawingArea.addTab("Tab1", scrollPaneForDrawingArea);
// Rechtes Element für contentSplitPane
rightWindowSide = new JPanel();
rightWindowSide.setPreferredSize(new Dimension(150, 300));
contentSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, tabbedPaneForDrawingArea, rightWindowSide);
contentPane = new JPanel();
contentPane.add(contentSplitPane);
return contentPane;
}
private DrawingArea createDrawingArea() {
// Zeichenfläche fürTabbedPane (linke Bildschirmhälfte)
drawingArea = new DrawingArea();
return drawingArea;
}
private JMenuBar createMenuBar() {
// Dürfte wohl klar sein, was die Methode macht
}
// Methoden, um die ActionListener durch den Controller zu setzen
}
DrawingArea
Java:
package view;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.ArrayList;
import javax.swing.JPanel;
import model.DrawingMode;
import model.ProgrammModel;
public class DrawingArea extends JPanel {
private ProgrammModel model; // irgendwie muss dies hier initialisiert werden
public DrawingArea() {
super();
setPreferredSize(new Dimension(300, 300));
setBackground(Color.WHITE);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// hier soll auf das Model zugegriffen werden, um evtl. Werte zu erhalten
}
}
Vom Gefühl her hätte ich jetzt das Model über den Konstruktor von DrawingArea übergeben, aber da hast Du ja von abgeraten. Wie würde ich so etwas sonst machen? Habe nicht ganz verstanden, was du mit
Oft reicht es aus, dass die View (die ja letztendlich "Controller" ihrer Subkomponenten ist) bei Änderungsmeldung des Models die notwendigen Werte an die Subkomponente weiterreicht.
Vom Gefühl her hätte ich jetzt das Model über den Konstruktor von DrawingArea übergeben, aber da hast Du ja von abgeraten. Wie würde ich so etwas sonst machen? Habe nicht ganz verstanden, was du mit * meintest.