JavaFX dodawanie Pane

0

Cześć
Uczę się JavaFX i mam pewien problem. Oprócz głównego GUI zrobiłem w pliku .fxml Pane który chciałbym wielokrotnie dodawać do GUI lecz za każdym razem trochę edytując jego dane (zmienić obrazek, zmienić tekst itd). I mam taki problem że nie wiem jak się dobrać do tych komponentów które chciałbym edytować.
Pane dodaje do GUI tak

centerVBox.getChildren().add(p);

Potrzebuję coś w rodzaju takiej metody:

	@FXML
	private ImageView img;

	@FXML
	private Label cena;

	@FXML
	private Label nazwa;

	@FXML
	private Button opisOferty;

	Pane getPane(Trip o) {
		Pane p = null;
		try {
			p = (Pane) FXMLLoader.load(getClass().getResource("SingleTripPane.fxml"));
			img.setImage(new Image("http://"));
			cena.setText("999");
			nazwa.setText("Australia");
			opisOferty.setOnAction(e -> {
				try {
					Desktop.getDesktop().browse(new URI("http://"));
				} catch (Exception e1) {
					e1.printStackTrace();
				}
			});

		} catch (Exception e1) {
			e1.printStackTrace();
		}
		return p;
	}

Próbowałem zrobić coś takiego w klasie kontrolera do mojego Pane ale niestety nie chce działać w ten sposób.
Załączam plik .fxml jak by ktoś chciał zerknąć.

Mógłby mi ktoś podpowiedzieć jak powinienem to zrobić ?

0

Co to znaczy "ale niestety nie chce działać w ten sposób."? Napisz coś więcej, bo trudno cokolwiek poradzić.

Generalnie widzę jeden błąd projektowy - mianowicie tworzysz obiekty typu Pane z referencją na ten sam Label i ImageView. Raczej bym to zrobił w tym stylu:

 
public class MyPane extends Pane {

	@FXML private Button fooButton;
	// Inne elementy

	public MyPane(){
		FXMLLoader loader = new FXMLLodader(new URL("Some URL"));
		loader.setRoot(this);
		loader.setController(this);
		try {
			loader.load();
		} catch(Exception e){
			// LOG ERROR
		}
	}
}
0

Tak najogólniej to potrzebuje zrobić taką klasę jak ta :

public class TestPane extends Pane {

	public TestPane(String s){
		Label nazwa = new Label(s);
		this.setPrefSize(450, 150);
		BorderPane borderPane = new BorderPane();
		borderPane.setCenter(nazwa);
		this.getChildren().add(borderPane);
	}
}

Tylko że elementy mają nie być tworzone w klasie tylko wczytane z pliku .fxml
Następnie zmienione wartości jakiś komponentów np. napis w Label

Spróbowałem zmodyfikować trochę twój kod:

public class MyPane extends Pane implements Initializable {

	@FXML
	private ImageView img;

	@FXML
	private Label cena;

	@FXML
	private Label nazwa;

	@FXML
	private Button opisOferty;

	public MyPane() {
		FXMLLoader loader;
		try {
			loader = new FXMLLoader(getClass().getResource("SingleTripPane.fxml"));
			loader.setRoot(this);
			loader.setController(this);
			loader.load();
		} catch (MalformedURLException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (Exception e) {
			// LOG ERROR
		}
	}
	public MyPane(Trip o){
		super();
		//img.setImage(new Image("http://cdntravelplanet.pl/53245A/NPL/sommer/miniature275x155/grecja/kreta/ammoudara/studios-la-palma_0.jpg"));
		cena.setText("999");
		nazwa.setText("Egipt");
		opisOferty.setOnAction(e -> {
			try {
				Desktop.getDesktop().browse(new URI("http://www.travelplanet.pl/wczasy/egipt/hurghada/hurghada/triton-empire,12072015ALFA11800.html?czas=7:7&wyzywienie=2&osoby=2&lotnisko=Warszawa&sortowanie=1&kolejnosc=up&dojazd=F"));
			} catch (Exception e1) {
				e1.printStackTrace();
			}
		});

	}

Niestety tutaj jak gdyby w ogóle nie został wczytany plik .fxml dlatego że przy używaniu konstruktora bezargumentowego nie ma błędów ale też nic się nie dodaje.
Natomiast używając konstruktora z argumentem dostajemy NullPointerException przy próbie zmiany jakiegoś elementu (np zmiana tekstu w Label)

0

Problem rozwiązany.
Zrobiłem tak:
Kontroler

public class SingleTripPaneController implements Initializable {

	@FXML
	 ImageView img;

	@FXML
	 Label cena;

	@FXML
	 Label nazwa;

	@FXML
	 Button opisOferty;
	

	@Override
	public void initialize(URL arg0, ResourceBundle arg1) {
		SingleTripPane.setControl(this);
	}

}

Tworzenie Pane

public class SingleTripPane {
	private static SingleTripPaneController control;
	private Pane p;
	
	public SingleTripPane(){
		Pane p = null;
		try {
			p = (Pane) FXMLLoader.load(getClass().getResource("SingleTripPane.fxml"));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		this.p = p;
	}

	public  Pane getPane(Trip trip) {
		control.img.setImage(new Image(trip.img));
		control.cena.setText(Integer.toString(trip.price));
		control.nazwa.setText(trip.country);
		control.opisOferty.setOnAction(e -> {
			try {
				Desktop.getDesktop().browse(new URI(trip.link));
			} catch (Exception e1) {
				e1.printStackTrace();
			}
		});
		
		return p;
		
	}

	public static void setControl(SingleTripPaneController o){
		control = o;
	}
	

}
0

W takim razie robisz to źle :)

Najprościej z Twojego punktu widzenia będzie użyć atrybutu fx:controller. Idąc za tutorialem z tej strony:
https://docs.oracle.com/javafx/2/api/javafx/fxml/doc-files/introduction_to_fxml.html

Kontroler możesz zadeklarować w FXMLu:

<VBox fx:controller="com.foo.MyController"
    xmlns:fx="http://javafx.com/fxml">
    <children>
        <Button text="Click Me!" onAction="#handleButtonAction"/>
    </children>
</VBox>

I później w dostępnym Classpath projektu dodajesz:

package com.foo;

public class MyController {
    public void handleButtonAction(ActionEvent event) {
        System.out.println("You clicked me!");
    }
}

Z doświadczenia wiem, że problemy się zaczynają, gdy masz kilka ekranów i chciałbyś zrobić pomiędzy nimi zależności - wtedy trzeba ALBO wyłuskiwać kontrolery podczas ładowania FXMLa, albo pójść na odwrót - przed ładowaniem FXMLa trzeba loaderowi wskazać już gotowy kontroler.

Ale w Twoim przypadku to powinno spokojnie wystarczyć.

1 użytkowników online, w tym zalogowanych: 0, gości: 1