2013-04-23 168 views
18

我想使用FXML在JavaFX中创建一个Java程序。不过,我在布局管理方面遇到了麻烦。我想在Panes之间切换,就像我习惯于在CardLayout中挥杆一样,但我似乎无法得到它。在JavaFX中的窗格之间切换

我搜索了一遍,没有找到任何答案。

JavaFX中是否有任何CardLayout等效项?如果是这样,你能提供一个例子吗?这将有助于我的晚上很多!

这里是我的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> 

回答

30

非动画过渡

如果你不需要你的窗格之间的过渡动​​画,那么你可以:

  1. 更换整个场景通过创建一个新的场景和set that scene on your Stage
  2. 替换只是一个规范通过删除父窗格中的旧窗格并添加新窗格(通过操纵父窗口的children list)或
  3. 将所有窗格放置在StackPane中,然后将要显示的窗格移动到顶部stack's child list

动画过渡

如果你想你的窗格之间动画transtions,然后看到JavaFX中管理多个屏幕安吉拉·凯塞多的两个部分系列:

Angela的解决方案是使用StackPane和一个单独的自定义ScreenController类来管理堆栈中窗格之间的Transitionsanimations


框架

框架,如JFXFlowWebFX还可以提供一个浏览器风格的界面为你的应用程序,允许用户使用回历史记录列表屏幕和前进按钮之间来回切换。

更新2017年

我认为以上两个参考框架的发展现在已经不存在。正在开发其他的框架是:

和无数人(我不会在这里提供一个全面的列表)。


相关

4

这里是我如何做到这一点: (在这个例子中,我创建了两个FXML文件及其相应的控制器他们被称为FXMLLogin。 .fxml和Home.fxml)。

所以,从FXMLLogin首页去,

在这个例子中,我创建FXMLLoginController内的方法以回应那些表格上的“登录”按钮被按下:

@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"); 
    } 
} 

请注意,@FXML非常重要。

如果我正确理解你的问题,那么这应该做的伎俩。

在窗格之间切换并不明显,在我找到的任何Web教程上都没有清楚地概述。在我第一次想到它之前,我必须自己广泛地使用Google。幸运的是,一旦你掌握了它,它确实很简单。

我希望我没有误解你的问题?让我知道如果这是你需要:)

0

JRebirth Application Framework提供了一个自定义'CardLayout'使用其专用模式wB-CSMvc。

StackModel类将做的工作(由org.jrebirth.af:component神器提供),你可以找到2个用法herehere

可以使用枚举| modelKey标识符调用每个'卡'模型,并且每个堆栈都有唯一的名称。

第一个样本用于JRebirth Demo Application,这是一个非常简单的应用程序,它允许显示其他JRebirth展示应用程序,这些应用程序是作为JRebirth模块(从独立和独立的jar中)动态加载的。

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(); 
    } 
} 

此应用程序将装载它的第一个模型(MainModel),并把它的根节点到场景根节点(StakPane,自动构建)。

MainModel将列出所有应用程序的子模块,将按钮条目添加到其左侧菜单中,并显示一个StackModel,它将显示每个模块的内容。 StackModel使用特殊的注解使用其唯一的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将负责创建模块菜单:

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; 
    } 
} 

而且MainController将加载时任何菜单按钮被触发模块内容:

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")); 
    } 
} 

第二例子将加载StackModel作为innerComponent并且每张卡片将通过枚举项(存储到FXMLPage中)来标识,让我们来看看FXMLShowCaseModel:

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

与模型链接枚举项的枚举:

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; 
    } 
} 

由于卡列表是已知的,工具栏项目静态创建成FXMLShowCaseView和事件处理也staically用别的技术定义为FXMLShowCaseController:

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)); 

    } 
} 

让我知道如果您有任何问题