JAVAFX observer und threads

Hey leute,

im moment arbeite ich immer noch an meinem programm, welches die wärmeausbreitung im raum simulieren soll. stellt euch einfach vor ein raum wird erwärmt und ein digitales thermometer soll die aktuellle raumtemperatur anzeigen. wenn es wärmer wird, ändert sich natürlich die anzeige von z.B 22 auf 23 grad Celsius.

Die werte kann ich nun berechnen und in der konsole ausgeben lassen. Es läuft eine while schleife in der die werte in jedem durchlauf neu berechnet werden.
Ein wert der ausgegeben wird soll in einem label angezeigt werden und sich immer aktualisieren. Sprich die Raumtemperatur darstellen. Nun hab ich ein video gesehen auf youtube wo ein kerl genau dies macht. auch mit temperatur aber es gibt noch große unterschiede. ich arbeite mit dem scenebuilder und fxml und er nicht . und er hat keine "komplizierte methode um die temperatur wirklich zu berechnen aber das gerüst muss ja irgendwie gleich sein.

hier ist mal das video. wäre natierlich cool wenn ihr euch das angucken könntet. wichtig sind die ersten drei minuten in etwa dann kann man skippen weil er erst eine nicht so elegante methode zeigt. ab Minute 10 geths dann weiter

ich habe soweit alles nachprogrammiert aber im label tut sich gar nichts ich musste einige sachen an meine klasse anpassen und da hab ich wohl was falsch gemacht. keine ahnung irgendwas an der falschen stelle oder der falsche aufruf oder sowas in der art. hier sind meine klassen


Klasse 1 welche den Wert enthaelt der im label angezeigt werden soll

Code:
public class Raum {
    int zeit;
    int startTemperatur;

    // length, width, height
    int x;
    int y;
    int z;

    double sensorwert;
    String sensorwertString;
    private final List<TemperaturSensorListener> listeners = new ArrayList();
    //and so on

    public Raum() {   
        ExecutorService service = Executors.newCachedThreadPool();
        service.submit(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {

            }
            temperaturverlauf(); // is this correct?
            for (TemperaturSensorListener listener : listeners) {
                listener.onReadingChanged();
            }
        });   
    }

    // Calculate Heat equation
    public void temperaturverlauf() {
        double[][][] raumTemp = new double[x][y][z];
        double[][][] raumTempneu = new double[x][y][z];
        zeit = 0;

        //Start temperature for every position
        for (int posX = 0; posX < x; posX++) {
            for (int posY = 0; posY < y; posY++) {
                for (int posZ = 0; posZ < z; posZ++) {
                    raumTemp[posX][posY][posZ] = startTemperatur;   
                }
            }
        }

        /*Heater*/
        raumTemp[0][0][0] = startHeizung;

        while (zeit < 100) {
            for (int posX = 0; posX < x; posX++) {
                for (int posY = 0; posY < y; posY++) {
                    for (int posZ = 0; posZ < z; posZ++) {
                        // Compute the heat of every quadrant in the room
                        // upper left corner
                        if (posX == 0 && posY == Array.getLength(raumTemp[0]) - 1 && posZ == 0) {
                            raumTempneu[posX][posY][posZ] = raumTemp[posX][posY][posZ] - temperaturleitfähigkeit * (4 * raumTemp[posX][posY][posZ] - raumTemp[posX + 1][posY][posZ] - raumTemp[posX][posY - 1][posZ] - raumTemp[posX][posY][posZ + 1] - mauertemp);
                        }   
                        // Upper right corner , walls and so on
                    }   
                }
            }

            raumTemp = raumTempneu;

            // print out the heat of the sensor position and convert it to a string. this String has to be displayed in a label
            System.out.println("raum1:" + raumTemp[Array.getLength(raumTemp) - 1][Array.getLength(raumTemp[0]) - 1][1]);
            sensorwert = raumTemp[Array.getLength(raumTemp) - 1][Array.getLength(raumTemp[0]) - 1][1];
            sensorwertString = Double.toString(sensorwert);
        }
    }

    public void addListener(TemperaturSensorListener listener) {
        listeners.add(listener);
    }

    public String getSensorwertString() {
        return sensorwertString;
    }
}


Da bin ich mir mit dem konstruktor nicht so sicher. bzw weiss ich nicht ob ich an meiner temperaturverlauf() Methode was haette hizufuegen müssen.


Zweite klasse welches das label enthält

Code:
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;

import java.net.URL;
import java.util.ResourceBundle;

public class FXMLDocumentController implements Initializable {
    private Raum r = new Raum();

    // Slider for heater temperature
    @FXML
    private Slider slider1;

    // Label with the String from the other class
    @FXML
    private final Label anzeigetempaktuell1 = new Label(r.getSensorwertString());

    // Textfields so user can type in the size of the room
    @FXML
    private TextField laenge;

    @FXML
    private TextField breite;

    @FXML
    private TextField hoehe;

    // starttemperature
    @FXML
    private TextField tempAktuell;

    // target temperature
    @FXML
    private TextField tempGewuenscht;

    //this button should start the application after the user typed in the required values
    @FXML
    private Button button;

    @FXML
    private void handleButtonAction(ActionEvent event) {
        r.temperaturverlauf();// i think this is wrong
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        slider1.setMin(17);
        slider1.setMax(85);
        slider1.setValue(45);

        slider1.valueProperty().addListener((ov, old_val, new_val) -> {
            r.maxHeizung = (double) new_val;
            System.out.println(r.maxHeizung);
        });

        // this is a relevant part i think but i think its the same like in the video
        r.addListener(new TemperaturSensorListener() {
            @Override
            public void onReadingChanged() {
                updateTemperatureLabel();
            }

            private void updateTemperatureLabel() {
                Platform.runLater(() -> anzeigetempaktuell1.setText(r.getSensorwertString()));
            }
        });
    }
}

Hier bin ich mir relativ sicher, das in die handleButtonAction methode NICHT r.temperaturverlauf hineinkommt. ich weiss aber nicht was sonst. dieser button ist sehr wichtig da der nutzer erst verschiedene werte wie raumgröße und so eingeben muss und DANN soll da Programm gestartet werden. Aber mit dem aufruf den ich im moment mache startet er wirklich nur diese methode und ALLES andere wie die threads, runnables usw ueberliest er einfach bzw passiert da anscheind NULL

dirtte klasse ist die normale startklasse

Code:
public class SmartHome extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

        Scene scene = new Scene(root);

        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}


Ich hoffe auf basis des videos kann mirirgendwer weiter helfen. Ich hoffe es liegt einfach nur an einem flaschen aufruf oder das ich irgendwas an einer falschen stelle aufrufe oder so.

mfg
shisui
 
Hi UchihaSevenfold,

vorweg eine Kleinigkeit: wenn du deinen Code als Java-Code einfügst und nicht als Text-Code, dann kann man das deutlich besser lesen...

Zu deinem Problem: ich habe mir das Video nicht ganz angeschaut und auch deinen Code noch nicht 100 % durchdrungen, aber verstehe ich dich richtig, dass dein Problem verallgemeinert ist, dass du ein Label öffnen möchtest, dessen Textinhalt durch einen Thread im Hintergrund (auf welcher Rechnung auch immer basierend) fortlaufend geändert werden soll? Falls dem so ist und es dir weiterhilft: Ich wäre das anders angegangen und hätte einen neuen FX-Thread erzeugt (dazu unten mehr), der per updateMessage() einen String aktualisierst. Damit dies der Textinhalt deines Labels ist, musst du das Label an den Thread binden.

Ich weiß nicht wie sauber dass ist, bin selber noch Anfänger, aber bei mir gehts.

Java:
import javafx.application.Application;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;

public class FX_Thread_Label extends Application{
   
    Label label = new Label();

    @Override
    public void start(Stage stage) throws Exception {
       
        //neuer FX-Thread
        Service<String> fxThread = new Service<String>() {
             protected Task<String> createTask() {
                 return new Task<String>(){
                     @Override
                     protected String call() throws Exception {
                         int zahl = 0;
                         while(true){
                             updateMessage(zahl+" °C");
                             zahl++;                        //<-hier komplizierte Rechnung einfügen
                             Thread.sleep(100);
                         }
                     }
                 };
             }
         };          
        
         label.textProperty().bind(fxThread.messageProperty());            //Textinhalt an Thread binden
         fxThread.restart();                                                //Thread starten
        
         Scene scene= new Scene(label,100,50);
         stage.setScene(scene);
         stage.show();
    }
   
    public static void main(String[] args){
        launch(args);
    }

}

Ich hoffe das hilft weiter.

LG
Sugan
 

Neue Themen


Zurück
Oben