mvc irgendwie ausser kontrolle gelaufen

  • Themenstarter Gelöschtes Mitglied 65838
  • Beginndatum
G

Gelöschtes Mitglied 65838

Gast
Also ich habe versucht irgendwie mvc in javafx umzusetzen was bis zu einem gewissen grad auch funktioniert hat nur komm ich jetzt in das problem dass der controller zu groß wird und im model eig gar nichts mehr passiert
Anmerkungen zuvor für die view
die PlayerView kann ansich gar nix und wäre gleichzusetzen wie in fxml mit import fxml datei
das gleiche gilt für die PointsCounterLayout diese können ansich nur sachen die auch eine View können sollte, die fügt halt punkte hinzu wenn es denn nötig ist
dh diese sind eig. unterviews
[CODE lang="java" title="View"]package playField;

import javafx.geometry.Pos;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import layout.PointsCounterLayout;
import player.PlayerView;
import test.CardsModel;

public class PlayFieldView extends BorderPane
{

private HBox handCards = new HBox();

private final PlayerView myView = new PlayerView(true);

private final PlayerView enemyView = new PlayerView(false);

private final VBox phaseLayout;
private final PointsCounterLayout myPoints = new PointsCounterLayout("My Points");
private final PointsCounterLayout enemyPoints = new PointsCounterLayout("Enemy Points");

private StackPane popUpStackPaneForEvents;

public PlayFieldView(VBox phaseLayout)
{
this.phaseLayout = phaseLayout;

this.setHandCardsAtTheBottom();
this.getStylesheets().add(getClass().getResource("playFieldView.css").toExternalForm());
this.setupPlayingInnerField();
this.setupCssForPointsSystem();
this.setPickOnBounds(false);
this.deactivateCreatures();

this.testCards(); // TODO nur für testzwecke

}

private void setupCssForPointsSystem()
{
myPoints.getMyPointsDisplay().setId("PointsBox");
enemyPoints.getMyPointsDisplay().setId("PointsBox");
}

private void setupPlayingInnerField()
{
BorderPane field = new BorderPane();
field.setTop(enemyView);
field.setRight(enemyPoints.getMyPointsDisplay());
field.setCenter(phaseLayout);

field.setBottom(myView);
field.setLeft(myPoints.getMyPointsDisplay());
myPoints.getMyPointsDisplay().setAlignment(Pos.CENTER);
popUpStackPaneForEvents = new StackPane(field);
this.setCenter(popUpStackPaneForEvents);
}

private void setHandCardsAtTheBottom()
{
ScrollPane handCardScrollPane = new ScrollPane(handCards);
handCardScrollPane.hbarPolicyProperty().set(ScrollBarPolicy.ALWAYS);
handCardScrollPane.vbarPolicyProperty().set(ScrollBarPolicy.NEVER);
this.setBottom(handCardScrollPane);
}

//TODO noch useless, erst mit fertigstellung von der sqlite db nützlich
/** public void drawCard()
{
if (phaseLayout.getPlayersTurn().getValue())
{
// handCards.getChildren().add();
}
}*/



public void activateCreatures()
{
myView.getCreatures().setDisable(false);
}

public void deactivateCreatures()
{
myView.getCreatures().setDisable(true);
}

public void testCards()
{
String s = "commander";
for (int i = 0; i < 10; i++)
{
Image image;
int counter = i;

if (i > 3)
{
counter = 3;
}

s = "main";
image = new Image(getClass().getResource("card" + counter + ".gif").toExternalForm());
ImageView imageview = new ImageView(image);

String str = "Once Per Turn -> Discard 1 card: \n Destroy " + i + " Creatures.";
String name = "Draco Wyvern Ruler of Air" + i;
CardsModel card = new CardsModel(s, name, image, imageview, 1 + i, 1 + i, "Kaiju", 3, "Laura Bornea", str,
3);
handCards.getChildren().add(card);
}
}
public HBox getHandCards()
{
return handCards;
}

public PointsCounterLayout getMyPoints()
{
return myPoints;
}

public PointsCounterLayout getEnemyPoints()
{
return enemyPoints;
}

public PlayerView getMyView()
{
return myView;
}


public PlayerView getEnemyView()
{
return enemyView;
}

}
[/CODE]
dann kommt mein bescheidenes model ich dachte ich brauche die gameStateProperty aber es ist irgendwie doch nur zu 1er methode gekommen was schon ein bisschen traurig ist
Code:
package playField;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import layout.playButtons.GamePhases;
import test.CardsModel;

public class PlayFieldModel {
    ObjectProperty<GamePhases> gameStateProperty = new SimpleObjectProperty<GamePhases>();
    CardsModel currentCard;
    /**
     * @return if health is below 0 it returns true
     */
    public boolean attack (CardsModel attackedCard, int damage) {
        attackedCard.setHealth(attackedCard.getHealth() - damage);
        return attackedCard.getHealth() < 0 ? true : false;
    }
    public ObjectProperty<GamePhases> gameStateProperty()
    {
        return gameStateProperty;
    }
}
und dann kommt der controller dazu der irgendwie alles kann gefühlt
das PhaseButtonLayout ist sozusagen "zu klein geraten" um es in mvc umzusetzen dh das ist gleichzeitig alles drei was sich am anfang als gut durchdacht angefühlt hatte, wenigstens implementiert das layout mein controller interface das is ja schon ma was :D

nur ich weis nicht was ich mit den riesen handlern machen sollte oder wo man das noch irgendwie übersichtlich machen kann , und dass ich gefühlt alles im controller habe der hat jetzt um die 200 zeilen hat obwohl das model ziemlich traurig aussieht irgendwie sollte das doch halbwegs verteilt sein
[CODE lang="java" title="controller"]package playField;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.event.EventTarget;
import javafx.scene.input.MouseEvent;
import layout.PhaseButtonLayout;
import layout.PointsCounterLayout;
import layout.interfaces.ControllerInterface;
import layout.playButtons.CreatureButton;
import layout.playButtons.GamePhases;
import test.CardsModel;

public class PlayFieldController implements ControllerInterface
{
private final PlayFieldView view;
private final PlayFieldModel model = new PlayFieldModel();

private ObjectProperty<GamePhases> gameStateProperty = new SimpleObjectProperty<GamePhases>();
private PhaseButtonLayout phaseLayout;

public PlayFieldController()
{
boolean isMyTurn = true;
this.phaseLayout = new PhaseButtonLayout(isMyTurn);
this.view = new PlayFieldView(phaseLayout.getTheView());
this.model.gameStateProperty().bind(this.gameStateProperty);

this.gameStateProperty.bind(phaseLayout.getPhaseButton().getPhase());
this.gameStateProperty.addListener(eventHandlerController);
this.gameStateProperty.addListener(gameStatePropertyListener);

gameStateProperty.bind(phaseLayout.getPhaseButton().getPhase());
}
private PointsCounterLayout getCurrentPointsLayout()
{
if (phaseLayout.getPlayersTurn().getValue())
{
return view.getMyPoints();
} else
{
return view.getEnemyPoints();
}
}
private CardsModel currentCard;
public EventHandler<MouseEvent> cardClickedHandler = event -> {
setCurrentCard(event.getTarget());
};
private void setCurrentCard(EventTarget eventTarget) {
if (eventTarget instanceof CardsModel cardsModel)
{
currentCard = cardsModel;
}
}
private ChangeListener<GamePhases> gameStatePropertyListener = new ChangeListener<GamePhases>()
{
@Override
public void changed(ObservableValue<? extends GamePhases> observable, GamePhases oldValue, GamePhases newValue)
{
if (oldValue == GamePhases.DRAW_PHASE)
{
getCurrentPointsLayout().addPoints();
}
if (phaseLayout.getPlayersTurn().getValue())
{
switch (newValue)
{
case DRAW_PHASE:
//view.drawCard();
break;
case MAIN_PHASE:
view.activateCreatures();
break;
case BATTLE_PHASE:
view.getMyView().resetAttackBooleans();
break;
case END_PHASE:
view.deactivateCreatures();
}
}
}
};
public EventHandler<ActionEvent> buttonClickedHandler = new EventHandler<ActionEvent>()
{
private CardsModel attackCard;
private CreatureButton attackButton;
private CreatureButton targetButton;
private CreatureButton button;

public void handle(ActionEvent event)
{
setCurrentCard(event.getTarget());
if (event.getTarget()instanceof CreatureButton button)
{
this.button = button;
if (isMainPhase())
{
putDownCard();
} else if (isBattlePhase())
{
prepareAndBattleMonsters();
}
}
}

private void putDownCard()
{
if (currentCard != null && this.button.isPlayer()
&& view.getMyPoints().removePoints(currentCard.getLevel()))
{
putCardOnTheField(button);
}
}

private void prepareAndBattleMonsters()
{
if (this.button.isPlayer() && button.isAbleToAttack())
{
setAttacker();
} else if (attackCard != null)
{
this.button.setAbleToAttack(false);
setDefender();
dealDamage(targetButton, attackButton.getCard().getStrength());
dealDamage(attackButton, targetButton.getCard().getStrength());
resetHandler();
}
}

private void setAttacker()
{
attackCard = this.button.getCard();
attackButton = this.button;
}

private void setDefender()
{
targetButton = this.button;
}

private void resetHandler()
{
attackCard = null;
attackButton = null;
targetButton = null;
}
};

private void dealDamage(CreatureButton targetButton, int damage)
{
if (model.attack(targetButton.getCard(), damage))
targetButton.removeCard();
}

private void putCardOnTheField(CreatureButton button)
{
button.setCard(currentCard);
view.getHandCards().getChildren().remove(currentCard);
currentCard = null;
};

private boolean isMainPhase()
{
return this.gameStateProperty.getValue() == GamePhases.MAIN_PHASE;
}

private boolean isBattlePhase()
{
return this.gameStateProperty.getValue() == GamePhases.BATTLE_PHASE;
}

private boolean isPlayersTurn()
{
return phaseLayout.getPlayersTurn().getValue();
}

public ChangeListener<GamePhases> eventHandlerController = new ChangeListener<GamePhases>()
{

@Override
public void changed(ObservableValue<? extends GamePhases> observable, GamePhases oldValue, GamePhases newValue)
{
if (isPlayersTurn())
{
if (newValue == GamePhases.MAIN_PHASE)
{
view.addEventHandler(MouseEvent.MOUSE_CLICKED, cardClickedHandler);
view.addEventHandler(ActionEvent.ACTION, buttonClickedHandler);
} else if (newValue == GamePhases.END_PHASE)
{
view.removeEventHandler(MouseEvent.MOUSE_CLICKED, cardClickedHandler);
view.removeEventHandler(ActionEvent.ACTION, buttonClickedHandler);
}
}
}
};

@Override
public PlayFieldView getTheView()
{
// TODO Auto-generated method stub
return view;
}
}[/CODE]

EDIT: ja ich weis es ist blöd einen ausschnitt aus einem größeren projekt hier zu zeigen
 
Zuletzt bearbeitet von einem Moderator:

White_Fox

Top Contributor
Also ich habe versucht irgendwie mvc in javafx umzusetzen was bis zu einem gewissen grad auch funktioniert hat nur komm ich jetzt in das problem dass der controller zu groß wird und im model eig gar nichts mehr passiert
Hehe...bei meinem Projekt ist das genau anders herum: Model und View werden immer größer, Controller ist (noch) klein und harmlos.

Nur als Trost vorneweg: Ich habe damals auch hier gefragt und im Prinzip bekam ich zur Antwort, daß es da kein allgemeingültiges Rezept gibt. Aber so als Anstoß: Wenn du Controller und View durch ein neues Objekt austauschst, muß das Programm in seinem alten Zustand bleiben (oder diesen zumindest problemlos wiederherstellen können), es dürfen keine Daten fehlen.

Wenn das nicht gelingt, hast du was durcheinandergerührt.

Ich habe mir (nach mehrmaligem Wegwerfen von mehreren tausend Codezeilen) dann eine Struktur gebastelt, die für jeden Kommunikationskanal (also z.B. View->Controller, Controller->Model, Model->View) ein eigenes Interface vorsieht. Die View kennt dann nicht das ganze Model, sondern nur ein Objekt, daß das geforderte Interface implementiert hat. Das hat sehr viel gebracht.
 
G

Gelöschtes Mitglied 65838

Gast
Wenn du Controller und View durch ein neues Objekt austauschst, muß das Programm in seinem alten Zustand bleiben (oder diesen zumindest problemlos wiederherstellen können), es dürfen keine Daten fehlen.
das versteh ich nicht ganz ich wüsste nicht mal was ich jetzt raus schmeißen soll dass es weiterhin geht
ich kann halt keinen PlayMenuController erstellen dann hab ich halt keine play view mehr aber die deckview shopview usw funktioniert immer noch

Ich habe mir (nach mehrmaligem Wegwerfen von mehreren tausend Codezeilen) dann eine Struktur gebastelt, die für jeden Kommunikationskanal (also z.B. View->Controller, Controller->Model, Model->View) ein eigenes Interface vorsieht.
das vorgehen mit den pfeilchen versteh ich absolut 0 das müsstest du genauer erklären
Die View kennt dann nicht das ganze Model, sondern nur ein Objekt, daß das geforderte Interface implementiert hat. Das hat sehr viel gebracht.
meine view kennt im moment niemanden

meine struktur war bis jetzt immer diese ich nehm jetzt das hauptmenü da das noch klein ist
Java:
package mainMenue;

import layout.TopNavigationButtonLayout;
import layout.interfaces.ControllerInterface;

public class MainMenuController implements ControllerInterface{
    private MainMenuView view ;
    private MainMenuModel model = new MainMenuModel();
        public MainMenuController(TopNavigationButtonLayout topBar) {
            this.view = new MainMenuView(topBar);
        }
        public MainMenuView getTheView() {
            return view;
        }
}
das controllerinterface sagt nur dass es eine getTheView braucht dass man die View aus dem controller raus kriegt wenn ein anderer controller diesen erstellt

der controller gettet dann alles vom model und view und bastelts irgendwie zusammen und da kommt halt die "eskalation" zustande


die view bleibt halt relativ klein da ich kleine view teile habe die die view einbauen kann die keine logik haben sondern einfach nur vorgebaut sind wie zb
Java:
package layout;

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import layout.interfaces.ControllerInterface;

public class PointsCounterLayout implements ControllerInterface
{
    private static final int maxPoints = 10;
    private static final int pointsPerTurn = 3;
    private Label myPointsLabel;
    private HBox pointsBox = new HBox();
    private VBox myPointsDisplay = new VBox();

    public PointsCounterLayout(String title)
    {
        this.myPointsLabel = new Label(title);
        this.myPointsDisplay.getChildren().addAll(myPointsLabel, pointsBox);
        this.setStyle();
    }

    /**
     * adds default Amount of Points per Turn
     */
    public void addPoints()
    {
        addPoints(pointsPerTurn);
    }

    private void setStyle()
    {
        pointsBox.setAlignment(Pos.CENTER);
        myPointsDisplay.setAlignment(Pos.CENTER);
        pointsBox.setSpacing(9);
    }

    public void addPoints(int number)
    {
        for (int i = 0; i < number; i++)
        {
            if (pointsBox.getChildren().size() < maxPoints)
            {
                var point = new Circle(7, Color.BLACK);
                pointsBox.getChildren().add(point);
            } else
            {
                break;
            }
        }
    }

    public boolean removePoints(int number)
    {
        if (pointsBox.getChildren().size() < number)
        {
            return false;
        } else
        {
            for (int i = 0, j = pointsBox.getChildren().size() - 1; i < number; i++,j--)
            {
                pointsBox.getChildren().remove(j);
            }
            return true;
        }
    }

    public VBox getTheView()
    {
        return myPointsDisplay;
    }

    public int getPointsCounter()
    {
        return pointsBox.getChildren().size();
    }

}
diese implementieren auch das controllerinterface da diese irgendwie alle 3 sachen gleichzeitig sind und es sich nicht rentiert einen mvc umzusetzen (denke ich zumindest obs wirklich so ist keine ahnung) und ich extende sonst zu oft von nodes und delegation over inheritance weis ich auch dass es das gibt aber obs so richtig ist weis ich wiederum auch net

diese "layouts" verkürzen halt den view quellcode ziemlich



ich habe auch noch andere layouts die logik selbst beinhalten und die werden im controller erstellt und die view wird an die view des übergestellten controllers gegeben dass da dann die view die kleine view einbauen kann
der logik teil sollte dabei im controller bleiben was halbwegs funktioniert und auch etwas übersichtlich ist nur da ises schon wieder so dass der controller voll gepumpt wird

und ja ich benutz kein fxml das kapier ich nicht und ich hab bis jetzt immer dynamische anwendungen gebaut wo ich einfach zu dämlich war die fxml view immer so anzupassen dass es passt ka warum das so ist vllt stell ich mich an wie der erste mensch

keine ahnung ob das big brain time ist aber ich weis es halt nicht besser deswegen frag ich ja
 

White_Fox

Top Contributor
das vorgehen mit den pfeilchen versteh ich absolut 0 das müsstest du genauer erklären
Ich habe ehrlich gesagt momentan nicht die Zeit, mich durch deinen Code zu arbeiten.

Es geht halt darum, Zuständigkeiten herzustellen. Im Allgemeinen will man nicht, daß jedes Objekt an jeder Stelle von jedem anderen Objekt geändert werden kann. Es gibt Dinge, die gehen fremde Objekte nichts an.
Also baut zieht man eine Struktur mit einem definierten Datenfluß auf.

Vielleicht demonstriert ein kleines Beispiel, was ich meine. Wir nehmen ein gaaanz einfaches Programm an: Es habe zwei Buttons und ein Label, daß einfach ein Integer zeigt. Mit den zwei Buttons kann das Integer inkrementiert und dekrementiert werden.

Java:
public class Model implements ModelsControllerside, {
    int i = 0;
    
    ViewsModelside model;
    
    @Override
    public void increment(){
        i++;
        model.tellMeAboutModelchages();
    }
    
    @Override
    public void decrement(){
        i--;
        model.tellMeAboutModelchages();
    }
    
    @Override
    public int getTheInt(){
        return i;
    }
}

//Interface, daß das Model implementiert und dem Controller übergeben wird
public interface ModelsControllerside{
    public void increment();
    public void dedrement();
}

//Interface, daß das Model implementiert und der View übergeben wird
public interface ModelsViewside{
    public int getTheInt();
}



public interface ControllersViewside{
    public void increment();
    public void decrement();
}

//Interface, daß der Controller implementiert und der View übergeben wird
public class Controller implements ControllersViewside{
    Model model;
    
    @Override
    public void increment(){model.increment();}
    
    @Override
    public void decrement(){model.decrement();}
}



public interface ViewsModelside{
    public void tellMeAboutModelchages();
}

public class View{
    ModelsViewside model;
    ControllersViewside controller;
    
    @Override
    public void tellMeAboutModelchages(){
        int theIntegerIShow = model.getTheInt();
        //Zeige den neuen Integerwert an
    }
    
    //Methode, die ein Klickevent auf den Inkrement-Button verarbeitet
    void IncrementButtonWasClicked(){
        controller.increment();
    }
    
    //Dito für Dekrement-Button
    void DecrementButtonWasClicked(){
        controller.decrement();
    }
}

Ich hoffe, ich habe es vollständig genug gemacht. Was haben wir da jetzt geschafft:

-Der gesamte Zustand des Programms (besteht ja nur aus dem Integer) wird im Model beschrieben.
-Die View hat keinen direkten Schreibzugriff auf das Model, nur Lesezugriff.
-Alle Änderungen des Programmzustands laufen über den Controller.

Und was ist daran jetzt so toll?
-Du kannst die View nach Belieben ändern. Du kannst z.B. von JavaFX auf Swing wechseln, oder eine Kommanzeilenversion von deinem Programm machen, und mußt dazu nur die View umschreiben. Viel Arbeit, aber deutlich weniger als wenn du das komplette Programm neu schreiben müßtest.
-Du hast weitaus übersichtlicheren Quellcode.
-Du verhedderst dich deutlich weniger in deiner Viewaktualisierung. Stell dir vor du hättest jetzt noch ein Kontextmenü, eine Menüleiste und Schnellzugriffe über die Tastatur. Und zeigst das Integer nicht nur in einem Label, sondern sondern auch in der Programmleiste oben und in einer Messagebox an. Und hast nicht nur ein Integer, sondern zehn. Das wird richtig stressig, das alles in einer Klasse machen zu wollen.
-Du kannst im Controller z.B. Zugriffe blockieren oder freigeben. Der Controller kann sich auch merken, welche Aktion zuletzt ausgeführt wurde. Und kann diese bei Bedarf wieder rückgängig machen.

Und da geht noch viel mehr...aber vielleicht reicht das ja als Anregung erstmal. Ob das bei deinem Programm notwendig ist...mußt du wissen. ;)
 
G

Gelöschtes Mitglied 65838

Gast
Java:
   //Methode, die ein Klickevent auf den Inkrement-Button verarbeitet
    void IncrementButtonWasClicked(){
        controller.increment();
    }
    
    //Dito für Dekrement-Button
    void DecrementButtonWasClicked(){
        controller.decrement();
    }

wieso darf das die view wissen?

hatte irgendwie den eindruck gekriegt dss die view komplett "dämlich" gehalten werden sollte

z.b hatte ich es so gemacht in deinem beispiel:
eventhandler increment im controller
im controller getViewButton von der view und dann addEventhandler

da ist halt die komplette eventhandler kontrolle über den controller gelaufen, sollte man das nicht machen?


und du hast jetzt 3 interfaces ist es normal dass man da diese gleich mitbaut?

hätte jetzt bei meinem dann 3 klassen, 3 interfaces und 1 css datei in einem package da ich immer die 3 die zusammen gehören in ein package haue
 

White_Fox

Top Contributor
wieso darf das die view wissen?
Naja, ein bisschen was muß die View ja wissen, sie soll ja Daten anzeigen - und die muß sie sich schon holen können.
Die View kann aber sonst nix. Deshalb bittet sie den Controller, was zu machen. Der Controller kann was (Daten ändern), hat aber keine Möglichkeit die Daten zu lesen.

Nachtrag:
Und wie gesagt - so ganz einheitlich ist das auch nicht. Das ist eine Struktur, die ich mir mal ausgedacht habe. Andere Entwickler machen das etwas anders...je nach dem.
 
G

Gelöschtes Mitglied 65838

Gast
Also ich hab in meiner App das so durchgezogen hab eine der klassen genommen die nicht so viele von mir erstellten objekte drin haben

Der Controller hat immer diese Jobs:
die properties die man von der View kriegt mit denen aus dem model verbinden
der View Eventhandler hinzufügen und weg nehmen
andere controller beinhalten von denen die view raus nehmen und sie an die view übergeben
[CODE lang="java" title="Controller"]import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import play.layout.playButtons.CardButton;
import test.CardsModel;

public class LeftInfoBoxController {
private LeftInfoBoxView view = new LeftInfoBoxView();
private LeftInfoBoxModel model = new LeftInfoBoxModel();
public LeftInfoBoxController()
{
view.getPictureButton().bind(model.pictureInfoProperty);
model.heightProperty.bind(view.heightProperty);
model.widthProperty.bind(view.widthProperty);
view.getStrengthValueTextProperty().bind(model.getStrengthValueProperty());
view.getHealthValueTextProperty().bind(model.getHealthValueProperty());
view.getlevelValueTextProperty().bind(model.getLevelValueProperty());
view.getTypeValueTextProperty().bind(model.getTypeValueProperty());
view.getArtistValueTextProperty().bind(model.getArtistValueProperty());
view.getEffectTextValueTextProperty().bind(model.getEffectTextValue());
view.getEntireView().parentProperty().addListener(changeListener);
}
public Pane getTheView() {
return this.view.getEntireView();
}
public EventHandler<MouseEvent> getHoverHandlerForSuperView(){
return this.mouseHoveredHandler;
}
public EventHandler<MouseEvent> mouseHoveredHandler = event -> {
CardsModel cardModel = null;
if (event.getTarget() instanceof CardsModel) {
cardModel = (CardsModel) event.getTarget();
} else if (event.getTarget()instanceof CardButton cardButton && cardButton.getCard() != null) {
cardModel = cardButton.getCard();
}
if (cardModel != null) {
model.setThisCardValues(cardModel);
}
};
final ChangeListener<? super Node> changeListener = new ChangeListener<Node>() {
@Override
public void changed(ObservableValue Node, Node oldVal,
Node newValue) {
if (newValue != null) view.getEntireView().getParent().addEventFilter(MouseEvent.MOUSE_ENTERED_TARGET, mouseHoveredHandler);
else oldVal.removeEventFilter(MouseEvent.MOUSE_ENTERED_TARGET, mouseHoveredHandler);
}
};
}[/CODE]
die view hat die jobs:
properties preis geben die der Controller braucht
einbauen von anderen views die der Controller anbietet
und halt alles view mäßige übernehmen wie größe und skalierung
[CODE lang="java" title="View"]public class LeftInfoBoxView extends View {
private VBox lefti = new VBox();
private Button pictureInfo = new Button();
private Button strengthValue = new Button("Strength");
private Button healthValue = new Button("Health");
private Button typeInfo = new Button("Type");
private Button levelInfo = new Button("Level");
private Button artistInfo = new Button("Artist");
private TextArea effectText = new TextArea();

ReadOnlyDoubleProperty widthProperty= pictureInfo.widthProperty();
ReadOnlyDoubleProperty heightProperty= pictureInfo.heightProperty();

LeftInfoBoxView() {
effectText.setEditable(false);
lefti.getStylesheets().add(getClass().getResource("leftInfoBoxStyle.css").toExternalForm());
artistInfo.setId("artistinfo");
pictureInfo.setId("pictureInfo");
this.setBindings();

lefti.getChildren().addAll(pictureInfo,new HBox(healthValue,strengthValue),new HBox(typeInfo,levelInfo),artistInfo,effectText);

}

private void setBindings() {
ReadOnlyDoubleProperty widthProperty = pictureInfo.widthProperty();
this.strengthValue.prefWidthProperty().bind(widthProperty.divide(2));
this.healthValue.prefWidthProperty().bind(widthProperty.divide(2));
this.typeInfo.prefWidthProperty().bind(widthProperty.divide(2));
this.effectText.prefWidthProperty().bind(widthProperty);
this.artistInfo.prefWidthProperty().bind(widthProperty);
this.levelInfo.prefWidthProperty().bind(widthProperty.divide(2));
}
public ObjectProperty<Node> getPictureButton() {
return pictureInfo.graphicProperty();
}
public ObjectProperty<Node> getPictureInfoGraphicProperty() {
return pictureInfo.graphicProperty();
}
public StringProperty getStrengthValueTextProperty() {
return strengthValue.textProperty();
}
public StringProperty getHealthValueTextProperty() {
return healthValue.textProperty();
}
public StringProperty getTypeValueTextProperty() {
return typeInfo.textProperty();
}
public StringProperty getlevelValueTextProperty() {
return levelInfo.textProperty();
}
public StringProperty getArtistValueTextProperty() {
return artistInfo.textProperty();
}
public StringProperty getEffectTextValueTextProperty() {
return effectText.textProperty();
}
public Pane getEntireView()
{
return lefti;
}
}[/CODE]
das model hat diese jobs:
einen haufen an properties haben
komplett alleine stehend sein
auf befehl vom controller werden die properties geändert, durch die änderung und den bindings ändert es sichs halt in der view
[CODE lang="java" title="model"]import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import play.layout.playButtons.CardButton;
import test.CardsModel;

public class LeftInfoBoxModel {

private SimpleStringProperty strengthValue = new SimpleStringProperty("STRENGTH");
private SimpleStringProperty healthValue = new SimpleStringProperty("HEALTH");
private SimpleStringProperty levelValue = new SimpleStringProperty("LEVEL");
private SimpleStringProperty typeValue = new SimpleStringProperty("TYPE");
private SimpleStringProperty artistValue = new SimpleStringProperty("ARTIST");
private SimpleStringProperty effectTextValue = new SimpleStringProperty();
public ObjectProperty<Node> pictureInfoProperty = new SimpleObjectProperty<>();
DoubleProperty widthProperty = new SimpleDoubleProperty();
DoubleProperty heightProperty = new SimpleDoubleProperty();
LeftInfoBoxModel()
{

}



/**
* Sets the hover handler to show Card information<br>
* Needs To be set on a Super View ( Deck, Shop, Play )
*
* @implNote all "CardsModel" Objects in the layout will execute the Hover
* Handler<br>
*/


void setThisCardValues(CardsModel cardModel) {
this.strengthValue.set("STR: " + cardModel.getStrength());
this.healthValue.set("HP: " + cardModel.getHealth());
this.levelValue.set("LVL: " + cardModel.getLevel());
this.typeValue.set("TYPE: " + cardModel.getType());
this.artistValue.set("ARTIST: " + cardModel.getArtist());
this.effectTextValue.set("Effect:\n" + cardModel.getEffectString());
ImageView img = cardModel.getCardImage();
img.setFitHeight(this.heightProperty.multiply(0.9).getValue());
img.setFitWidth(this.widthProperty.multiply(0.9).getValue());
this.pictureInfoProperty.set(cardModel.getCardImage());
}

public SimpleStringProperty getStrengthValueProperty() {
return strengthValue;
}

public SimpleStringProperty getHealthValueProperty() {
return healthValue;
}

public SimpleStringProperty getLevelValueProperty() {
return levelValue;
}

public SimpleStringProperty getTypeValueProperty() {
return typeValue;
}

public SimpleStringProperty getArtistValueProperty() {
return artistValue;
}
public SimpleStringProperty getEffectTextValue() {
return effectTextValue;
}
}[/CODE]
bei mir hat der controller viele jobs zu erledigen ... an sich die meisten deswegen ist der obrige auch wahrscheinlich so groß geworden

nur ich weis nicht ob man das so machen sollte auch wenn mvc schwammig beschrieben wird und gefühlt 1000 implementationen hat
 

White_Fox

Top Contributor
Mal eine Frage: Was soll dein Programm eigentlich machen? Kannst du das mal beschreiben?

Edit: Deine Klassen heißen ja alle LeftInfoBoxXYZ.
LeftInfoBox heißt für mich aber schonmal, daß es irgendwas mit Viewkram zu tun hat. Davon sollten aber weder Model noch Controller etwas wissen...meiner Meinung nach. Ich muß allerdings auch sagen, daß ich von Software eigentlich keine Ahnung habe. Obgleich ich durchaus relativ viel programmiere würde ich mich in diesem Zusammenhang nicht gerade als vom Fach bezeichnen, meine Profession ist die E-Technik.
 
Zuletzt bearbeitet:
G

Gelöschtes Mitglied 65838

Gast
also leftinfo box ist noch der Name der aus alten zeiten übergeblieben ist ...

das programm ist ein karten spiel man kann im moment ein deck bauen und auch karten ausspielen usw

ich habe halt 3 "Richtige Views"
das deck menü
das spiel menü
das haupt menü

diese beinhalten dann wiederum wieder kleinere "layouts" also kleinere mvcs und die "richtigen Controller" bauen sich aus den kleinen teilen die "Richtige view" zusammen , wenn ich alles in 1e sache packen würde wäre die klasse paar hundert zeilen lang

es ist sozusagen so eine baum verkettung von controllern es darf jeder controller von einem anderen die view verlangen um sie einzubauen
aber managen tut die view jeder controller für sich selbst
 

White_Fox

Top Contributor
Ich denke, dein Hauptproblem ist allgemein überbordende Komplexität. Mit anderen Worten: du hast keinen Überblick mehr, was da wie zusammenhängt.

Das waren so die Momente, wo ich mir erstmal mein Notizbüchlein (ich führe für mein Projekt tatsächlich so ein altmodisches Buch aus Papier zum reinschreiben) nehme, und schreibe mir auf was für Probleme ich konkret habe. "Übersicht vollständig verloren" kam da mehr als einmal vor.

Danach aufgeschrieben, was ich viel lieber hätte. Sauber definierte Schnittstellen (welche Zugriffe dürfen von wo aus erfolgen, und von wo aus nicht, usw.), keine Überschneidung in Zuständigkeiten, und ähnliches. Bei dir würde ich aussagekräftige Klassennamen, definierte Zuständigkeiten und ein sauberes Klassengerüst fordern. Z.B. ist es kein Widerspruch, zwar nur eine View, aber mehrere Fenster zu haben.
In meinem Projekt habe ich nur ein Fenster (ok, stimmt auch nicht ganz, ich habe auch mehrere, aber die meiste Zeit verbringt man nur in einem Hauptfenster), aber dieses Fenster besteht aus mehreren Klassen. Die "View-Hauptklasse" verwaltet eigentlich nur die einzelnen Fensterteile, aber wesentiche "View-Funktionselemente" wie z.B. Menüleiste, eine Baumübersicht in irgendeinem Panel, Inhalte verschiedener Tabs, usw. sind eigene Klassen die ihr eigenes Ding machen. Aber alle Kommunikation nach außen läuft über die Viewhauptklasse.

Tja, und am Ende kommt dann das was wirklich schwer ist: Erst ein letzter Commit mit entsprechendem Kommentar, und dann ein Totalabriss und von vorne anfangen.
 
G

Gelöschtes Mitglied 65838

Gast
ich versteh dich, ich denke dadurch dass das was ich habe ist, dass mein programm von "ich hab keine ahnugn" zu "ich denke schon dass ich weis was ich tu" gewachsen ist und alte schnipsel hinterher hinken

wie ich das umsetzen wollte hat sich gefühlt 3 mal während des projektes geändert , aber langsam hab ich zumindest den dreh raus , auch wenn es waahrscheinlich sehr verschieden zu anderen mvc und programmier arten is
 

Ähnliche Java Themen


Oben