Pytania do SceneBuilder'a javafx

0

Witam. Pisze programik w javfx i nie raz napotykam problemy, na które nie mogę znaleźć odwiedzi w internecie. Dlatego, będę zadawał pytania w tym temacie, gdy trafie na jakieś trudności. O to pierwsze dwa pytania.
1.) Korzystam z obiektów shapes, ale przy zmianie rozmiaru okna te obiekty , nie zmieniają rozmiaru, więc chciałem się zapytać, czy zmiana rozmiaru okna wywołuje jakiś setEvent, jeśli tak to jaki? Jeśli nie to jak w inny sposób mogę wywołać metode przy zmianie rozmiaru okna.

2.) Chciałbym , żeby po kliknięciu w button, przy kursorze pojawiał mi się jakiś obiekt i podążał za nim , do czasu upuszczenia go w innym miejscu. Jak mógłbym się za to zabrać ?

1

Ad 1. Ani Scene ani Stage nie tworzą żadnego eventu związanego ze zmianą rozmiaru. Najprościej jest podpiąć się z ChangeListenerm pod scene.widthProperty() i scene.heightProperty().
Ad 2. Po kliknięciu w button zmienić obrazek kursora na customowy a potem nasłuchiwać na event MouseEvent.MOUSE_RELEASED.

0

Dobrze, potrzebuje jeszcze małej podpowiedzi co do poprzednich dwóch pytań :)

Mam klase main, które ładuje plik Intersection.fxml zbudowany wscene builderze, który korzysta z klasy controller. I tu pojawia się problem, jak moge korzystać z metod wywoływanych na scene w tym kontrolerze ? Typu scene.heightProperty(), scene.setCursor ?

package application;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            BorderPane root = (BorderPane) FXMLLoader.load(getClass()
                    .getResource("Intersection.fxml"));
            Scene scene = new Scene(root, 500, 500);
            scene.getStylesheets().add(
                    getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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

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

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.ColorPicker;
import javafx.scene.control.TextArea;
import javafx.scene.shape.Rectangle;

public class Controller implements Initializable {

	@FXML
	private Rectangle road3;

	@FXML
	private Rectangle road0;

	@FXML
	private Rectangle road2;

	@FXML
	private Rectangle road1;

	@FXML
	private TextArea text;

	@FXML
	private Button addcar;

	@FXML
	private Button addsign;


	@FXML
	private Button start;

	@Override
	public void initialize(URL arg0, ResourceBundle arg1) {
		
		
		start.setOnAction(e -> startSymulation(e));
		addcar.setOnAction(e -> carAddition(e));
		addsign.setOnAction(e -> signAddition(e));
		
		
		
		
		
	}
	
	
	private void startSymulation(ActionEvent e){
		
	}
	
	private void carAddition(ActionEvent e){
		
	}
	
	private void signAddition(ActionEvent e){
		
	}
	
	
		
	//}
}
1

Dokumentacja naprawdę nie gryzie, jak się przynajmniej pobieżnie przejrzy dostępne dla poszczególnych komponentów metody to się znacząco łatwiej pisze:P
Dla dowolnego elementu na scenie wywołaj metodę getScene(), np:

start.getScene().heightProperty().addListener(...
start.getScene().setCursor(...

Druga opcja, ja osobiście częściej ją stosuję to dodać sobie pole w kontrolerze i ręcznie je ustawiać po załadowaniu kontrolera. Trzeba tylko pamiętać, że w momencie wywołania metody initialize() to pole jeszcze nie jest ustawione, np:

public abstract class AbstractController {
	
	private Stage stage;

	public Stage getStage() {
		return stage;
	}

	public void setStage(Stage stage) {
		this.stage = stage;
	}
}

Wywołanie w metodzie main wygląda wtedy mniej więcej tak:

public void start(Stage primaryStage) throws Exception {
		FXMLLoader loader = new FXMLLoader();
		loader.setLocation(App.class.getResource("gui/view/MainScreen.fxml"));
		primaryStage.setScene(new Scene(loader.load()));
		AbstractController controller = loader.getController();
		controller.setStage(primaryStage);
		primaryStage.show();

	}
0

Dzięki za pomoc :) Naprawdę bardzo mi ułatwia prace twoja pomoc . Mam następne pytanie. Mam taki fragment kodu. Jak zrobić, aby po wejściu w tą metodę i po załączeniu się jednego z tych Eventów, stały się nie aktywne

 public void handleMouseClickedCar(Rectangle car,MouseEvent p){
		
		TextArea.setText("Wybierz kierunek jazdy samochodu");
		
		road0.setOnMouseClicked(e -> handleMouseClickedDestination(road0,e));
		road1.setOnMouseClicked(e -> handleMouseClickedDestination(road1,e));
		road2.setOnMouseClicked(e -> handleMouseClickedDestination(road2,e));
		road3.setOnMouseClicked(e -> handleMouseClickedDestination(road3,e));
		
		}
1

No i ponownie: Dokumentacja nie gryzie:) Metoda setOnMouseClicked jest zdefiniowana dla klasy Node. Jest to taka typowa "Convenience Method", która po prostu rejestruje EventHandler dla konkretnego zdarzenia. A skoro da się zarejestrować EventHandler to da się go też "odrejestrować". Metoda temu służąca nazywa się removeEventHandler. Jako argumenty podajesz EventType i EventHandler.
Podsumowując:
W przypadku zajścia jakiegoś Eventu musisz usunąć wszystkie EventHandlery i wywołać procedurę obsługi dla tego który zaszedł.
Pozdrawiam:)

0

Popraw mnie jeśli źle rozumuje. Żeby zaimplementować removeEventHandler nie mogę korzystać z lambdy i klas anonimowych ?

Kurcze ciężkie to , bo jak zrobię coś takiego to nie wiem jak przekazac parametry :(

EventHandler ClickedDestination = new EventHandler<InputEvent>() {
	      public void handle(InputEvent event ) {
	    	  
	    			
	    	String DesID = Destination.getId().toString();
	  		TextArea.setText("Wybrałeś kierunek jazdy w strone" + DesID);
	  		cc.setDestination(DesID);
	  		cc.setDest();
	  		
	  		road0.removeEventHandler(MouseEvent.MOUSE_CLICKED, ClickedDestination);
	  		road1.removeEventHandler(MouseEvent.MOUSE_CLICKED, ClickedDestination);
	  		road2.removeEventHandler(MouseEvent.MOUSE_CLICKED, ClickedDestination);
	  		road3.removeEventHandler(MouseEvent.MOUSE_CLICKED, ClickedDestination);
	    			
	      }
	    };


	
		TextArea.setText("Wybierz kierunek jazdy samochodu");
		road0.addEventHandler(MouseEvent.MOUSE_CLICKED,ClickedDestination);
	    road1.addEventHandler(MouseEvent.MOUSE_CLICKED,ClickedDestination);
	    road2.addEventHandler(MouseEvent.MOUSE_CLICKED,ClickedDestination);
	    road3.addEventHandler(MouseEvent.MOUSE_CLICKED,ClickedDestination);
 
1

Koralu złoty, weź sobie do serca mój drugi post w tym temacie i przejrzyj metody i pola dostępne dla klasy Node. Ja sobie zdaję sprawę, że jest ich dużo ale bez znajomości API nie da się programować. Nie musisz tego umieć na pamięć wystarczy, że będziesz mniej więcej wiedział jakie masz możliwości. Spodziewałem się, że pójdziesz tą drogą i usuniesz lambdy, żeby mieć referencję do EventHandlera. A jakbyś zajrzał do dokumentacji to byś zobaczył metodę getOnMouseClicked(), która zwraca EventHandler. Nigdy z niej nie korzystałem ale spodziewam się, że zwróci ona referencję do czegoś, czego będzie można użyć jak argumentu do removeEventHandler().
Sprawdź i daj znać.

0

Napisałem to w taki sposób, ale niestety nie wyrejestrowywuje Event'ów. Co prawda błędu kompilator nie zgłasza, więc może coś źle wywołuje tą metodę.

 road0.setOnMouseClicked(e -> handleMouseClickedDestination(road0,cc, e));
		  road1.setOnMouseClicked(e -> handleMouseClickedDestination(road1,cc, e));
		  road2.setOnMouseClicked(e -> handleMouseClickedDestination(road2,cc, e));
		  road3.setOnMouseClicked(e -> handleMouseClickedDestination(road3,cc, e));
	      
	
		
	}

	public void handleMouseClickedDestination(Rectangle Destination,CarController cc, MouseEvent p) {
		
	
		String DesID = Destination.getId().toString();
		TextArea.setText("Wybrałeś kierunek jazdy w strone " + DesID);
		cc.setDestination(DesID);
		cc.setDest();
	
		road0.removeEventHandler(MouseEvent.MOUSE_CLICKED,road0.getOnMouseClicked());
		road1.removeEventHandler(MouseEvent.MOUSE_CLICKED,road1.getOnMouseClicked());
		road2.removeEventHandler(MouseEvent.MOUSE_CLICKED,road2.getOnMouseClicked());
		road3.removeEventHandler(MouseEvent.MOUSE_CLICKED,road3.getOnMouseClicked());
	} 
1

Temat okazuje się nie być tak prosty jak myślałem. Wygląda na to, że nie da się w ten sposób usunąć EventHandler, jeżeli był on dodany za pomocą metody setOnMouseClicked(). Natomiast można tak usunąć EventHandler dodany za pomocą addEventHandler() ale i tak tylko w przypadku gdy mamy do niego refrencję.
Jeżeli chcesz to zrobić za pomocą wyrażeń labda to możesz tak:

EventHandler<MouseEvent> handler = e -> handleMouseClickedDestination(road0,cc, e));
road0.addEventHandler(MouseEvent.MOUSE_CLICKED, handler);
road0.removeEventHandler(MouseEvent.MOUSE_CLICKED, handler);

Powinno zadziałać.
Druga opcja to klasyczny EventHandler. Nie rozumiem dokładnie jaki masz problem z przekazaniem parametrów. Twoje e z wyrażenia lambda to po prostu event z metody handle(). Reszta działa dokładnie tak samo.

0

Ok. Nie wiedziałem jak dokładnie przekazać handler do zarejestrowanego eventu, ale zdeklarowałem EventHandlery globalnie i działa. Dzięki za pomoc i poświęcony czas :)

        private EventHandler handler_0;
	private EventHandler handler_1;
	private EventHandler handler_2;
	private EventHandler handler_3;

	public void handleMouseClickedCar(Rectangle car, MouseEvent p) {

		 
		  EventHandler<MouseEvent> handler0 = e -> handleMouseClickedDestination(road0,cc, e);
		  EventHandler<MouseEvent> handler1 = e -> handleMouseClickedDestination(road1,cc, e);
		  EventHandler<MouseEvent> handler2 = e -> handleMouseClickedDestination(road2,cc, e);
		  EventHandler<MouseEvent> handler3 = e -> handleMouseClickedDestination(road3,cc, e);
		  
		  handler_0 = handler0;
		  handler_1 = handler1;
		  handler_2 = handler2;
		  handler_3 = handler3;
		  
		  road0.addEventHandler(MouseEvent.MOUSE_CLICKED, handler0);	  
		  road1.addEventHandler(MouseEvent.MOUSE_CLICKED, handler1);		  
		  road2.addEventHandler(MouseEvent.MOUSE_CLICKED, handler2);	  
		  road3.addEventHandler(MouseEvent.MOUSE_CLICKED, handler3);
		
		  
	
		
	}

	public void handleMouseClickedDestination(Rectangle Destination,CarController cc, MouseEvent p) {
		
	
		road0.removeEventHandler(MouseEvent.MOUSE_CLICKED,handler_0);
                road1.removeEventHandler(MouseEvent.MOUSE_CLICKED,handler_1);
                road2.removeEventHandler(MouseEvent.MOUSE_CLICKED,handler_2);
                road3.removeEventHandler(MouseEvent.MOUSE_CLICKED,handler_3);
	}
		
 

edit: W sumie, zaraz te globalne zrobię jako tablice :)

0

Zacząłem testowanie mojej aplikacji i natrafiłem na małą trudność. Mianowicie, mam zrobiony przycisk reset, który przywraca mi widok do stanu początkowego. Na pierwszy rzut oka wszystko wygląda w porządku. Ale, gdy uruchomię reset, a w tle jakiś event czeka ma moją akcje, to się zaczyna wszystko sypać. I to moje następne pytanie. Czy można jakoś zakończyć event, który czeka na jakaś moją reakcje ? Zawsze mogę zrobić zabezpieczenie w resecie, że nie zadziała, jeśli event się nie zakończy, ale chyba nie o to chodzi :)

0

a co czeka na ten event? kontroler?

jak dla mnie jeżeli od nowa inicjujesz jakiś tam widok to kontoler tak samo powinieneś. czyli to i to zasięg prototype

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