2016-08-17 4 views
0

FXML에서 DialogPane을 만들고, onAction이 ButtonType의 유효한 매개 변수가 아니기 때문에 대화 상자의 버튼 누르기에 응답하는 방법을 알아 내려고하고 있습니다. 내 FXML 및 컨트롤러 클래스를 첨부했습니다. DialogPane에 관한 문서는 거의 없으며, FXML로 처리하는 방법에 대한 정보가 거의 없으므로 진행 방법을 잘 모릅니다.FXML 설정 ButtonType onAction

<?xml version="1.0" encoding="UTF-8"?> 

<?import javafx.scene.control.ButtonType?> 
<?import javafx.scene.control.DialogPane?> 
<?import javafx.scene.control.Label?> 
<?import javafx.scene.control.TextField?> 
<?import javafx.scene.layout.ColumnConstraints?> 
<?import javafx.scene.layout.GridPane?> 
<?import javafx.scene.layout.RowConstraints?> 

<DialogPane fx:id="loginPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="LoginController"> 
    <content> 
     <GridPane hgap="5.0" vgap="5.0"> 
      <columnConstraints> 
       <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> 
       <ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="300.0" /> 
      </columnConstraints> 
      <rowConstraints> 
       <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> 
       <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> 
       <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> 
       <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> 
      </rowConstraints> 
      <children> 
       <Label text="Driver Name" /> 
       <TextField fx:id="driverTxt" GridPane.columnIndex="1" /> 
       <Label text="URL" GridPane.rowIndex="1" /> 
       <TextField fx:id="urlTxt" GridPane.columnIndex="1" GridPane.rowIndex="1" /> 
       <Label text="Username" GridPane.rowIndex="2" /> 
       <TextField fx:id="userTxt" GridPane.columnIndex="1" GridPane.rowIndex="2" /> 
       <Label text="Password" GridPane.rowIndex="3" /> 
       <TextField fx:id="passTxt" GridPane.columnIndex="1" GridPane.rowIndex="3" /> 
      </children> 
     </GridPane> 
    </content> 
    <buttonTypes> 
     <ButtonType fx:id="loginButton" text="Login" /> 
     <ButtonType fx:id="cancelBtn" text="Cancel" /> 
    </buttonTypes> 
</DialogPane> 

import javafx.fxml.FXML; 
import javafx.scene.Scene; 
import javafx.scene.control.ButtonType; 
import javafx.scene.control.DialogPane; 
import javafx.scene.control.TextField; 

public class LoginController { 

    @FXML 
    DialogPane loginPane; 
    @FXML 
    TextField driverTxt; 
    @FXML 
    TextField urlTxt; 
    @FXML 
    TextField userTxt; 
    @FXML 
    TextField passTxt; 
    @FXML 
    ButtonType loginButton; 

    @FXML 
    private void loginButtonAction(){ 
     // How do I do something here 
    } 

    public void initialize() { 
     driverTxt.setText("org.postgresql.Driver"); 
     urlTxt.setText("jdbc:postgresql://localhost/postgres"); 
     userTxt.setText("postgres"); 
     passTxt.setText("postgres"); 
    } 

} 

답변

2

일반적으로이 작업을 수행하지 않아도됩니다. 일반적으로 Dialog<ButtonType>에서 showAndWait() 메서드를 호출하면 DialogPane이 표시되며,이 메서드는 누를 단추를 나타내는 Optional<ButtonType>을 반환합니다. 그래서 정상적인 사용이

public class LoginController { 

    public static final ButtonType LOGIN = new ButtonType("Login"); 

    @FXML 
    DialogPane loginPane; 
    @FXML 
    TextField driverTxt; 
    @FXML 
    TextField urlTxt; 
    @FXML 
    TextField userTxt; 
    @FXML 
    TextField passTxt; 


    public void initialize() { 
     driverTxt.setText("org.postgresql.Driver"); 
     urlTxt.setText("jdbc:postgresql://localhost/postgres"); 
     userTxt.setText("postgres"); 
     passTxt.setText("postgres"); 
    } 

    public String getDriver() { 
     return driverTxt.getText(); 
    } 

    public String getUrl() { 
     return urlTxt.getText(); 
    } 

    public String getUser() { 
     return userTxt.getText(); 
    } 

    public String getPass() { 
     return pass.getText(); 
    } 

} 

같은 수와 FXML 파일을 다음과 같이 변경 만들 것입니다 : 노출에 대한 대안으로

Dialog<ButtonType> dialog = new Dialog<>(); 
FXMLLoader dialogLoader = new FXMLLoader(getClass().getResource("Login.fxml")); 
dialog.setDialogPane(dialogLoader.load()); 
LoginController controller = dialogLoader.getController(); 
dialog.showAndWait().filter(LoginController.LOGIN::equals) 
    .ifPresent(button -> { 
     String driver = controller.getDriver(); 
     // etc etc 
     // process login... 
    }); 

:

<buttonTypes> 
    <LoginController fx:constant="LOGIN" /> 
    <ButtonType fx:constant="CANCEL" /> 
</buttonTypes> 

그런 다음 당신이이을 사용을 텍스트 필드의 텍스트를 입력하면 컨트롤러 자체에 processLogin() 메서드를 정의하여 텍스트 필드를 읽고 필요한 작업을 수행 할 수 있습니다.

public class LoginController { 

    public static final ButtonType LOGIN = new ButtonType("Login"); 

    @FXML 
    DialogPane loginPane; 
    @FXML 
    TextField driverTxt; 
    @FXML 
    TextField urlTxt; 
    @FXML 
    TextField userTxt; 
    @FXML 
    TextField passTxt; 


    public void initialize() { 
     driverTxt.setText("org.postgresql.Driver"); 
     urlTxt.setText("jdbc:postgresql://localhost/postgres"); 
     userTxt.setText("postgres"); 
     passTxt.setText("postgres"); 
    } 

    public void processLogin() { 
     String driver = driverTxt.getText(); 
     // etc... 
     // process login... 
    } 
} 

는 당신이 정말로 로그인 버튼으로 onAction 핸들러를 등록해야하는 경우,

// ... 
dialog.showAndWait().filter(LoginController.LOGIN::equals) 
    .ifPresent(button -> controller.processLogin()); 

을 컨트롤러에 initialize() 방법을 수행

public void initialize() { 
    driverTxt.setText("org.postgresql.Driver"); 
    urlTxt.setText("jdbc:postgresql://localhost/postgres"); 
    userTxt.setText("postgres"); 
    passTxt.setText("postgres"); 

    Button login = (Button) loginPane.lookupButton(loginButton); 
    login.setOnAction(e -> { /* ... */ }); 
} 

그러나 이것은이다 실제로 대화 상자 창 API의 의도 된 사용에 반대합니다.


마지막으로 대안은 DialogPanecreateButton 메소드를 오버라이드 (override)하는 것입니다. 이렇게하려면 DialogPane 하위 클래스가 필요합니다. 이는 FXML custom component pattern을 사용하는 것을 의미합니다. 당신이 찾고 있다면 당신은 너무

Dialog dialog = new Dialog(); 
dialog.setDialogPane(new LoginPane()); 
dialog.showAndWait(); 

이 버전을 사용하는 것과 FXML 다음

<?xml version="1.0" encoding="UTF-8"?> 

<?import javafx.scene.control.ButtonType?> 
<?import javafx.scene.control.DialogPane?> 
<?import javafx.scene.control.Label?> 
<?import javafx.scene.control.TextField?> 
<?import javafx.scene.layout.ColumnConstraints?> 
<?import javafx.scene.layout.GridPane?> 
<?import javafx.scene.layout.RowConstraints?> 

<fx:root type="DialogPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1"> 
    <content> 
     <GridPane hgap="5.0" vgap="5.0"> 
      <columnConstraints> 
       <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> 
       <ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="300.0" /> 
      </columnConstraints> 
      <rowConstraints> 
       <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> 
       <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> 
       <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> 
       <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> 
      </rowConstraints> 
      <children> 
       <Label text="Driver Name" /> 
       <TextField fx:id="driverTxt" GridPane.columnIndex="1" /> 
       <Label text="URL" GridPane.rowIndex="1" /> 
       <TextField fx:id="urlTxt" GridPane.columnIndex="1" GridPane.rowIndex="1" /> 
       <Label text="Username" GridPane.rowIndex="2" /> 
       <TextField fx:id="userTxt" GridPane.columnIndex="1" GridPane.rowIndex="2" /> 
       <Label text="Password" GridPane.rowIndex="3" /> 
       <TextField fx:id="passTxt" GridPane.columnIndex="1" GridPane.rowIndex="3" /> 
      </children> 
     </GridPane> 
    </content> 
    <buttonTypes> 
     <LoginPane fx:constant="LOGIN" /> 
     <ButtonType fx:constant="CANCEL" /> 
    </buttonTypes> 
</fx:root> 

과 같을 것이다

public class LoginPane extends DialogPane { 

    public static final ButtonType LOGIN = new ButtonType("Login"); 

    @FXML 
    TextField driverTxt; 
    @FXML 
    TextField urlTxt; 
    @FXML 
    TextField userTxt; 
    @FXML 
    TextField passTxt; 

    public LoginPane() { 
     try { 
      FXMLLoader loader = new FXMLLoader(getClass().getResource("LoginPane.fxml")); 
      loader.setRoot(this); 
      loader.setController(this); 
      loader.load(); 
     } catch (IOException exc) { 
      // bad if you get here... 
      throw new UncheckedIOException(exc); 
     } 
    } 

    @Override 
    public Node createButton(ButtonType buttonType) { 
     Node button = super.createButton(buttonType); 
     if (buttonType == LOGIN) { 
      ((Button) button).setOnAction(e -> processLogin()); 
     } 
     return button ; 
    } 


    public void initialize() { 
     driverTxt.setText("org.postgresql.Driver"); 
     urlTxt.setText("jdbc:postgresql://localhost/postgres"); 
     userTxt.setText("postgres"); 
     passTxt.setText("postgres"); 
    } 

    public void processLogin() { 
     String driver = driverTxt.getText(); 
     // etc... 
     // process login... 
    } 
} 

과 :

그래서이 같을 것 가능하면 로그인 창과 fxml에 캡슐화하기 위해, 이것은 아마도 가장 깨끗한 옵션 일 것입니다. 의 사용은 DialogDialogPane에 대한 API 문서에 완전히 설명되어 있습니다.

+0

마지막으로, 대화 상자에서 DialogPane을 감싸기 위해 FXML을 업데이트 한 다음 FXMLLoader를 사용하여 FMXL에서 Dialog의 인스턴스를 만들고 예제를 사용하여 showAndWait을 만들 수있었습니다. 가장 어려운 부분은 내가 찾던 모든 예제가 FXML을 기본으로 사용하지 않고 가능한 많은 작업을 수행하려고한다는 것입니다. – Shawn

관련 문제