2014-10-16 2 views
0

상단에 버튼 행이 있고 측면에 버튼 행이있는 프로그램을 만듭니다. 위쪽 단추는보기를 제어하고 측면 단추는보기에서 참조 할 개체를 제어합니다.JavaFX : 새로운 값으로 경계 판의 중심보기를 업데이트하는 방법

내 메인/루트보기가 경계선입니다.

이 단추 중 하나를 클릭하면 MainController에서 값을 변경 한 다음 이러한 새 값으로 가운데보기를 다시로드해야합니다. 값을 변경하고 이러한 값에 따라 새 센터를 설정하는 메소드를 작성하는 것이 매우 간단하다고 생각했습니다.

그러나 테스트 할 때 이미 표시하도록 요청한 두 값을 표시 할 수 있지만 실행할 때마다 큰 오류가 발생합니다. 다음과 같이

내 MainViewController 보인다 :

import java.io.IOException; 
import javafx.application.Application; 
import javafx.fxml.FXML; 
import javafx.fxml.FXMLLoader; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.layout.AnchorPane; 
import javafx.scene.layout.BorderPane; 
import javafx.stage.Stage; 



public class MainViewController extends Application { 


@FXML 
private Button cabin1; 
@FXML 
private Button cabin2; 
@FXML 
private Button tab1; 
@FXML 
private Button tab2; 



@FXML 
public void setCabinOne() throws IOException { 
    cabinIndex=1; 
    setCenterView(); 
} 
@FXML 
public void setCabinTwo() throws IOException { 
    cabinIndex=2; 
    setCenterView(); 
} 

@FXML 
public void setTabOne() throws IOException { 
    tabIndex=1; 
    setCenterView(); 
} 

@FXML 
public void setTabTwo() throws IOException { 
    tabIndex=2; 
    setCenterView(); 
} 

public int getCabinIndex() { 
    return cabinIndex; 
} 

public int getTabIndex() { 
    return tabIndex; 
} 

private int tabIndex=0; 
private int cabinIndex=1; 


public Stage primaryStage; 
private BorderPane mainPane; 

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

} 

@Override 
public void start(Stage primaryStage) throws Exception { 
    this.primaryStage=primaryStage; 
    primaryStage.setTitle("Test"); 
    FXMLLoader loader = new FXMLLoader(); 
    loader.setLocation(MainViewController.class.getResource("MainView.fxml")); 
    mainPane = loader.load(); 
    setCenterView(); 
    Scene scene = new Scene(mainPane); 
    primaryStage.setScene(scene); 
    primaryStage.show(); 

} 

public void setCenterView() throws IOException { 
    FXMLLoader loader = new FXMLLoader(); 
    loader.setLocation(MainViewController.class.getResource("TestView.fxml")); 
    AnchorPane testPane = loader.load(); 
    TestViewController tvc = loader.<TestViewController>getController(); 
    tvc.changeLabel(getCabinIndex()); 
    tvc.changeIndex(getTabIndex()); 
    mainPane.setCenter(testPane); 
} 

} 

를 다음과 같이 내 TestViewController 보이는 : 내가 잘못 뭐하는 거지

import javafx.fxml.FXML; 
import javafx.scene.control.Label; 


public class TestViewController { 

@FXML 
private Label cabinIndex; 
@FXML 
private Label tabIndex; 

public void initialise() { 
    this.changeLabel(0); 
    this.changeIndex(0); 

} 

public void changeLabel(int n) { 
    cabinIndex.setText("Cabin "+Integer.toString(n)); 
} 

public void changeIndex(int n) { 
    tabIndex.setText("Tab "+Integer.toString(n)); 
} 

} 

?

+0

모든 혼란을 제거하고 더 작은 예제로 제거하십시오. 게다가, 오류 메시지는 매우 도움이 될 것입니다. – rethab

+0

무슨 소리가 나는거야? 내 컴퓨터에 다시 액세스하면 오류 메시지를 게시합니다. –

+0

StackOverflow에 오신 것을 환영합니다. 예제를 게시 할 때 항상 문제를 재현하기에 충분하고 더 이상 재현 할 수없는 [최소, 완전한 예제] (http://stackoverflow.com/help/mcve)를 만들어보십시오. 귀하의 경우에는'TestView.fxml'과'TestViewController'를 완전히 없애고'mainPane'과 버튼 하나만 제외하고'MainViewController'의 모든 것을 제거 할 수 있습니다. 'setCenterPane'의 구현을'mainPane.setCenter (new Label ("Hello"))'로 바꾸면 여전히 같은 스택 추적을 볼 수 있습니다. (이것은 @rethab이 참조하는 "혼란"입니다.) –

답변

1

응용 프로그램은 기본적으로 구조적으로 잘못되었습니다. 응용 프로그램 하위 클래스를 컨트롤러로 사용하고 있으며, 간단히 작동하지 않습니다 (적어도 쉽지 않음). 컨트롤러와 구별되는 시작 클래스 (하위 클래스 Application)로 리팩터링해야합니다. 실제로 모든 완벽한 예제가 템플릿으로 사용되지만 Oracle tutorial을 시작하는 것이 좋습니다.

당신이 MainViewController.main(...)Application.launch() 전화

가, 외환 툴킷은 FX 응용 프로그램 스레드가 시작, 응용 프로그램 클래스 MainViewController의 인스턴스가 생성되고, 시작되며, start() 방법이 속하는 다음과 같이 어떤 일이 일어나고

입니다 FX 응용 프로그램 스레드에서 MainViewController 인스턴스로 호출됩니다.

FXMLLoaderload() 메서드를 호출하면 지정된 위치의 FXML 파일을 구문 분석합니다. 내가 fx:controller="MainViewController"이라고 가정하고있는 fx:controller 속성을 보면 지정한 컨트롤러 클래스의 인스턴스가 만들어집니다. FXML이 파싱되면 일치하는 모든 필드 (해당 인스턴스에 속하는)는 FXML 파일의 해당 개체로 초기화 된 다음 initialize() 메서드가 호출됩니다.

이제 MainViewController의 인스턴스가 두 개 있습니다. FXMLLoader.load()이 호출 된 인스턴스와 FXMLLoader으로 생성 된 인스턴스가 있습니다. FXMLLoader에 의해 생성 된 인스턴스의 축 번호 필드 @FXML은 초기화되지만 원래 인스턴스의 값은 기본값 null으로 설정되어 있습니다. 반대로 mainPane 필드는 원래 MainViewController 인스턴스의 start 메서드에서 초기화되지만 FXMLLoader으로 생성 된 인스턴스에서는 초기화되지 않습니다. 따라서 버튼을 누르고 setCenterView()을 호출하면 (FXML 설정 방법이라고 가정합니다) mainPane이 아직 null 일 때 mainPane.setCenter()으로 전화를 겁니다.

아마도 이런 식으로 작동하도록 할 수 있습니다.다음과 같이하십시오 : fx:controller 속성을 MainView.fxml에서 제거하고 loader.setController(this)으로 전화하십시오. 그러나 프레임 워크에서 사용하는 일반적인 패턴과는 거리가 멀어지면 코드를 유지 관리 및 디버그하기가 어려워집니다. API에서 의도 한 디자인을 따르는 것이 좋습니다.

+0

정말 고맙게 생각합니다. 이제 프로그램을 실행하고 뷰를 시작하는 Main 클래스를 갖도록 구조를 변경했습니다. 내 문제는 MainViewController에서 Main 클래스의 값을 변경하는 방법입니다. 값 cabinIndex를 사용하십시오. 0으로 초기화합니다. 센터 뷰를 설정하면 TestView.fxml을로드하고 TestViewController를 만들고 TVC에 레이블을 "Cabin 0"으로 변경하라고 요청합니다. 이것은 잘 작동합니다. MainView에서 버튼을 클릭하고 cabinIndex를 변경하면됩니다. 어떻게 이것을 올바르게 참조 할 수 있습니까? –

+0

메인 클래스에 애플리케이션 로직을 두지 마십시오. 단지 해당 속성 ('cabinindex' 등)을 컨트롤러로 옮기십시오. (더 큰 응용 프로그램에서는 모델과 같은 모든 속성을 캡슐화하는 별도의 클래스를 가지고 컨트롤러에 대한 참조를 전달할 수 있습니다. 그러나 지금은 간단하게 유지하고 컨트롤러의 해당 값을 정의합니다.) –

+0

Ok 그래서 cabinIndex를 MainViewController로 옮겼습니다. 내 질문은 지금 : MainViewController에서 Button 1을 클릭하고 cabinIndex를 1로 변경 한 다음 새 cabinIndex로 TestView를 다시로드하려고합니다. 어떻게해야합니까? TestViewController에서 MainViewController의 인스턴스를 생성하고 그 메소드를 사용할 수 있어야한다고 생각합니다. 어떻게하면 현재 MainViewController를 항상 참조하는지 확인할 수 있습니까? –

관련 문제