2013-04-23 18 views
18

Próbuję utworzyć program Java w języku JavaFX przy użyciu języka FXML. Mam jednak problem z zarządzaniem układem. Chcę przełączać się między panelami, tak jak jestem przyzwyczajony do CardLayout na huśtawce, ale nie mogę tego zrozumieć.Przełączanie między panelami w języku JavaFX

Przeszukałem i nie znalazłem żadnych odpowiedzi.

Czy istnieje odpowiednik CardLayout w JavaFX? a jeśli tak, czy możesz podać mi przykład? To bardzo pomogłoby mojemu wieczorowi!

Oto mój kod FXML

<AnchorPane id="anchorPane" prefHeight="324.0" prefWidth="530.0" xmlns:fx="http://javafx.com/fxml" fx:controller="javafxapplication2.SampleController"> 
    <children> 
    <Pane fx:id="mainScreen" layoutX="6.0" prefHeight="324.0" prefWidth="518.0"> 
     <children> 
     <Button layoutX="254.0" layoutY="37.0" mnemonicParsing="false" text="Button" /> 
     </children> 
    </Pane> 
    <Pane fx:id="loginScreen" prefHeight="324.0" prefWidth="530.0"> 
     <children> 
     <TextField id="password" fx:id="username" layoutX="142.0" layoutY="106.0" prefWidth="200.0" /> 
     <TextField fx:id="password" layoutX="142.0" layoutY="140.0" prefWidth="200.0" /> 
     <Label fx:id="label" layoutX="126.0" layoutY="120.0" minHeight="16.0" minWidth="69.0" /> 
     <Button fx:id="button" layoutX="213.0" layoutY="196.0" onAction="#handleButtonAction" onKeyPressed="#handleButtonAction" text="Login" /> 
     </children> 
    </Pane> 
    </children> 
</AnchorPane> 

Odpowiedz

30

nieanimowane przejścia

Jeśli nie trzeba animowane przejścia między swoimi szyb, a następnie można:

  1. Wymienić całą scenę, tworząc nową scenę i zamień tylko specyfikację. okienko if w układzie nadrzędnym, usuwając stary panel z jego rodzica i dodając nowy panel (manipulując obiektem nadrzędnym children list) LUB umieszczając wszystkie panele w obiekcie StackPane i przesuwając okienko, które ma być wyświetlane na górze stack's child list.

Animowane przejścia

Jeśli chcesz animowane transtions między szybami, a następnie zobaczyć dwuczęściowej serii Angeli Caicedo w sprawie zarządzania wieloma ekranami w JavaFX:

Rozwiązaniem Angeli jest użycie StackPane z osobną niestandardową klasą ScreenController do zarządzania Transitions lub animations między panelami w stosie.


Konstrukcje

Konstrukcje takie jak JFXFlow i WebFX może również stanowić interfejs w stylu przeglądarki dla aplikacji, dzięki czemu użytkownicy mogą przełączać się między ekranami korzystających z powrotem i przyciski do przodu i listy historii.

Aktualizacja 2017

myślę rozwój obu przywołanych wyżej ram jest teraz zlikwidowany.Inne ramy, które są w fazie rozwoju są:

i wielu innych (nie zapewni pełną listę tutaj).


pokrewne

4

Oto jak to zrobić: (W tym przykładzie, stworzyliśmy dwa dokumenty FXML z odpowiednimi sterownikami Nazywane są FXMLLogin. .fxml i Home.fxml, odpowiednio).

Tak więc, aby przejść od FXMLLogin do domu,

W tym przykładzie, stworzył metodę obrębie FXMLLoginController który reaguje na przycisk „Zaloguj” w tej formie jest wciśnięty:

@FXML 
private void login(javafx.event.ActionEvent event) throws IOException 
{ 
    if(pwf1.getText().equals("alphabetathetagamma")) 
    { 
      Parent blah = FXMLLoader.load(getClass().getResource("Home.fxml")); 
      Scene scene = new Scene(blah); 
      Stage appStage = (Stage) ((Node) event.getSource()).getScene().getWindow(); 
      appStage.setScene(scene); 
      appStage.show(); 
    } 
    else 
    { 
      label1.setText("Password is incorrect. Please Try Again"); 
    } 
} 

Należy pamiętać, że format @FXML jest niezwykle ważny.

Jeśli dobrze zrozumiałem twoje pytanie, powinno to wystarczyć.

Przełączanie między panelami nie jest wcale oczywiste i nie jest jasno opisane w samouczku internetowym, który znalazłem. Musiałem bardzo szeroko google, zanim odkryłem to po raz pierwszy. Na szczęście jest to całkiem proste, kiedy już to zrozumiesz.

Mam nadzieję, że źle zrozumiałem twoje pytanie? Daj mi znać, jeśli tego potrzebujesz :)

0

JRebirth Application Framework zapewnia niestandardowy "CardLayout" przy użyciu dedykowanego wzoru wB-CSMvc.

Wykonuje zadanie klasa StackModel (dostarczona przez org.jrebirth.af: artefakt komponentu), można znaleźć 2 zastosowania here i here.

Każdy model "karty" można wywołać za pomocą identyfikatora enum | modelKey, a każdy stos ma unikalną nazwę.

Pierwsza próbka jest używana dla JRebirth Demo Application, jest to dość prosta aplikacja, która pozwoli wyświetlić inne aplikacje JRebirth prezentowane dynamicznie jako moduł JRebirth (z oddzielnego i niezależnego słoika).

public final class JRebirthDemo extends DefaultApplication<StackPane> { 

    public static void main(final String... args) { 
     Application.launch(JRebirthDemo.class, args); 
    } 

    @Override 
    public Class<? extends Model> firstModelClass() { 
     return MainModel.class; 
    } 

    @Override 
    protected String applicationTitle() { 
     return "JRebirth Demo Application"; 
    } 

    @Override 
    protected void customizeScene(final Scene scene) { 
     super.customizeScene(scene); 

     addCSS(scene, DemoStyles.DEFAULT); 
     addCSS(scene, WorkbenchStyles.DEFAULT); 
    } 

    @Override 
    protected void customizeStage(final Stage stage) { 
     // Center the stage 
     stage.centerOnScreen(); 
    } 

    @Override 
    protected List<? extends ResourceItem<?, ?, ?>> getResourceToPreload() { 
     return Collections.emptyList(); 
    } 
} 

Ta aplikacja załaduje swój pierwszy model (MainModel) i umieścić swoje węzła głównego do węzła głównego scena (StakPane automatycznie zbudowany).

MainModel wyświetli wszystkie podrzędne moduły aplikacji, aby dodać wpisy przycisków w lewym menu oraz StackModel, który wyświetli zawartość każdego modułu. Moduł StackModel jest ładowany przy użyciu specjalnej adnotacji przy użyciu unikalnego klucza String.

public final class MainModel extends DefaultModel<MainModel, MainView> { 

    private final List<ModuleModel> modules = new ArrayList<>(); 

    @Link("DemoStack") 
    private StackModel stackModel; 

    @Override 
    protected void initModel() { 
     for (final ModuleModel mm : getModels(ModuleModel.class)) { 
      this.modules.add(mm); 
     } 
    } 

    @Override 
    protected void showView() { 
     view().node().setCenter(this.stackModel.node()); 
    } 

    @Override 
    protected void hideView() { 
     // Nothing to do yet 

    } 

    List<ModuleModel> getModules() { 
     return this.modules; 
    } 
} 

MAINVIEW będzie za stworzyć menu modułu:

public final class MainView extends DefaultView<MainModel, BorderPane, MainController> { 

    private final List<Button> buttonList = new ArrayList<>(); 

    public MainView(final MainModel model) throws CoreException { 
     super(model); 
    } 

    @Override 
    protected void initView() { 

     node().setPrefSize(800, 600); 

     node().setLeft(createMenu()); 

    } 

    @Override 
    public void start() { 
     this.buttonList.stream().findFirst().ifPresent(button -> button.fire()); 
    } 

    private Node createMenu() { 
     final VBox box = new VBox(); 

     for (final ModuleModel mm : model().getModules()) { 
      final Node n = createModuleButton(mm); 
      VBox.setMargin(n, new Insets(4, 4, 4, 4)); 
      box.getChildren().add(n); 
     } 
     return box; 
    } 

    private Node createModuleButton(final ModuleModel mm) { 
     final Button b = new Button(mm.moduleName()); 
     b.getStyleClass().add("menuButton"); 
     b.setPrefSize(100, 50); 
     b.setOnAction(controller()::onButtonFired); 
     b.setUserData(Key.create(mm.getClass())); 
     this.buttonList.add(b); 
     return b; 
    } 
} 

A MainController wczyta zawartość modułu gdy dowolny przycisk menu jest wyzwalany:

public final class MainController extends DefaultController<MainModel, MainView> implements ActionAdapter { 

    public MainController(final MainView view) throws CoreException { 
     super(view); 
    } 

    public void onButtonFired(final ActionEvent event) { 
     final Button b = (Button) event.getSource(); 
     final UniqueKey<? extends Model> data = (UniqueKey<? extends Model>) b.getUserData(); 

     model().sendWave(StackWaves.SHOW_PAGE_MODEL, 
         WBuilder.waveData(StackWaves.PAGE_MODEL_KEY, data), 
         WBuilder.waveData(StackWaves.STACK_NAME, "DemoStack")); 
    } 
} 

Drugi przykład załaduje StackModel jako innerComponent i każda karta zostanie zidentyfikowana przez wpis enum (zapisany w FXMLPage), zobaczmy FXMLShowCaseModel:

final InnerComponent<StackModel> stack = CBuilder.innerComponent(StackModel.class, FXMLPage.class); 
    this.stackModel = findInnerComponent(stack); 

Wyliczenie że odwołuje wpis enum z Model:

public enum FXMLPage implements PageEnum { 

    StandaloneFxml, 
    IncludedFxml, 
    ViewEmbeddedFxml, 
    HybridFxml; 

    @Override 
    public UniqueKey<? extends Model> getModelKey() { 
     UniqueKey<? extends Model> modelKey; 

     switch (this) { 

      default: 
      case ViewEmbeddedFxml: 
       modelKey = Key.create(EmbeddedModel.class); 
       break; 
      case StandaloneFxml: 
       modelKey = Key.create(StandaloneModel.class); 
       break; 
      case HybridFxml: 
       modelKey = Key.create(HybridModel.class, FXMLModel.KEYPART_FXML_PREFIX + "org.jrebirth.af.showcase.fxml.ui.hybrid.Hybrid"); 
       break; 
      case IncludedFxml: 
       modelKey = Key.create(IncludedModel.class, new LoremIpsum()); 
       break; 
     } 

     return modelKey; 
    } 
} 

Ponieważ lista karta jest znana, poz Pasek są statycznie stworzony do FXMLShowCaseView i obsługi zdarzeń jest również staically zdefiniowane w FXMLShowCaseController użyciu innej techniki:

public final class FXMLShowCaseController extends DefaultController<FXMLShowCaseModel, FXMLShowCaseView> { 

    private static final Logger LOGGER = LoggerFactory.getLogger(FXMLShowCaseController.class); 

    public FXMLShowCaseController(final FXMLShowCaseView view) throws CoreException { 
     super(view); 
    } 

    @Override 
    protected void initEventAdapters() throws CoreException { 

     // WaveData<Class<? extends PageEnum>> stackName = Builders.waveData(StackWaves.STACK_PAGES, FXMLShowCaseModel.STACK_PAGES); 

     // Manage Ui Command Button 
     linkWave(view().getShowIncluded(), ActionEvent.ACTION, StackWaves.SHOW_PAGE_ENUM, 
       WBuilder.waveData(StackWaves.PAGE_ENUM, FXMLPage.IncludedFxml)); 

     linkWave(view().getShowEmbedded(), ActionEvent.ACTION, StackWaves.SHOW_PAGE_ENUM, 
       WBuilder.waveData(StackWaves.PAGE_ENUM, FXMLPage.ViewEmbeddedFxml)); 

     linkWave(view().getShowStandalone(), ActionEvent.ACTION, StackWaves.SHOW_PAGE_ENUM, 
       WBuilder.waveData(StackWaves.PAGE_ENUM, FXMLPage.StandaloneFxml)); 

     linkWave(view().getShowHybrid(), ActionEvent.ACTION, StackWaves.SHOW_PAGE_ENUM, 
       WBuilder.waveData(StackWaves.PAGE_ENUM, FXMLPage.HybridFxml)); 

    } 
} 

Daj mi znać, jeśli masz jakieś pytanie

Powiązane problemy