我有一个具有此窗口结构的程序:
左侧有按钮,绿色区域是不同的窗口,可以改变用户在左侧按钮上的位置。
我有一个主类(调用Estructura),它作为主窗口的控件,绿色面板除外。对于绿色面板,我从左侧注入(感谢afterburner.fx DI)对应面板基于用户按钮选择。由于基于MVP的DI Framework,注入的面板有自己的控制器是懒惰的。
public class EstructuraPresenter implements Initializable {
private static final Logger LOG = getLogger(EstructuraPresenter.class.getName());
@FXML
ToggleButton btnPlantillas, btnAlumnos, btnEstadisticas;
@FXML
BorderPane pEstructura; //Correspond to all window except green zone
@FXML
StackPane pContenedor; //Green zone
//Injection of all child windows that i want to show in green zone
@Inject
private AlumnosView alumnosview;
@Inject
private PlantillasView plantillasview;
@Inject
private EstadisticasView estadisticasview;
@Override
public void initialize(URL url, ResourceBundle rb) {
//I set up green zone with alumnos panel so I call method whit request section to load
cambiarSeccion("Alumnos");
btnPlantillas.setOnAction((ActionEvent event) -> {
cambiarSeccion("Plantillas");
});
btnAlumnos.setOnAction((ActionEvent event) -> {
cambiarSeccion("Alumnos");
});
btnEstadisticas.setOnAction((ActionEvent event) -> {
cambiarSeccion("Estadisticas");
});
}
//I pass to this method, name of window/panel that I like to load in green zone
public void cambiarSeccion(String nombreVentana) {
try {
//First, reset all buttons (so when user select an option and enter in case, I select option button making like effect as a selected)
btnAlumnos.setSelected(false);
btnPlantillas.setSelected(false);
btnEstadisticas.setSelected(false);
switch (nombreVentana) {
case "Alumnos":
if (btnAlumnos.isSelected() == false) {
sepTitulo.setVisible(true);
lbTitulo.setText("Alumnos");
btnAlumnos.setSelected(true);
//I need to do this check because for first time program load because green zone hasn't got any previous panel load
if (pContenedor.getChildren().contains(alumnosview.getView())) {
pContenedor.getChildren().clear();
alumnosview.getViewAsync(pContenedor.getChildren()::add);
} else {
pContenedor.getChildren().add(alumnosview.getView());
}
}
break;
case "Plantillas":
if (btnPlantillas.isSelected() == false) {
sepTitulo.setVisible(true);
lbTitulo.setText("Plantillas");
btnPlantillas.setSelected(true);
pContenedor.getChildren().clear();
plantillasview.getViewAsync(pContenedor.getChildren()::add);
}
break;
case "Estadisticas":
if (btnEstadisticas.isSelected() == false) {
sepTitulo.setVisible(true);
lbTitulo.setText("Estadísticas");
btnEstadisticas.setSelected(true);
pContenedor.getChildren().clear();
estadisticasview.getViewAsync(pContenedor.getChildren()::add);
}
break;
//There are more cases but I use same configuration like above examples...
}
}
catch (Exception e) {
LOG.log(Level.SEVERE, e.toString());
new Dialogos().mostrarExcepcion(null, e);
}
}
}
好吧,当左侧按钮上的用户clic时,面板在绿色区域中加载正常。但问题是我的用户例如在绿色区域clic上的按钮/链接...加载另一个面板(类似于上面的描述)但在这种情况下我需要从绿色面板控制器调用方法cambiarSeccion(),这是在EstructuraPresenter控制器中。
因此,例如,在用户选择estadisticas按钮的情况下(我隐藏在图像中,抱歉我试图简化),那就是estadisticaspresenter控制器:
public class EstadisticasPresenter implements Initializable {
private static final Logger LOG = getLogger(EstadisticasPresenter.class.getName());
@FXML
Hyperlink linkTotalAlumnos;
@Inject
private EstructuraView estructuraview;
@Override
public void initialize(URL url, ResourceBundle rb) {
linkTotalAlumnos.setOnAction((ActionEvent event) -> {
//This call apparently works, I debug and call to method cambiarSeccion happend but screen isn't update
((EstructuraPresenter) estructuraview.getPresenter()).cambiarSeccion("Alumnos");
});
}
}
如果我加载了estadisticas窗口如果我单击左侧按钮,可以正常工作但是如果我在绿色加载面板上clic没有发生任何事情。我在下一张图片中恢复了问题:
答案 0 :(得分:1)
在我看来,你的方法有一个问题:当你打电话给任何一个孩子的主持人时
((EstructuraPresenter) estructuraview.getPresenter())
.cambiarSeccion("Alumnos");
estructuraview.getPresenter()
实际上是在创建主要演示者的新实例。
这意味着当您点击超链接时再次调用EstructuraPresenter.initialize()
,并且您有两次调用cambiarSeccion()
(一个来自Initialize
,一个来自操作),孩子们到了新的实例,而不是旧的,这是你看到的那个。这就是为什么你没有看到任何变化!
我建议采用不同的方法:让主要演讲者听听孩子们某些属性的变化。
例如,添加一个布尔属性以通知单击超链接:
public class EstadisticasPresenter implements Initializable {
@FXML Hyperlink linkTotalAlumnos;
private final BooleanProperty link = new SimpleBooleanProperty();
public boolean isLink() { return link.get(); }
public void setLink(boolean value) { link.set(value); }
public BooleanProperty linkProperty() { return link; }
@Override public void initialize(URL url, ResourceBundle rb) {
linkTotalAlumnos.setOnAction((ActionEvent event) -> {
link.set(true);
});
}
}
在主要演讲者身上:
@Override
public void initialize(URL url, ResourceBundle rb) {
...
EstadisticasPresenter estadisticas =
(EstadisticasPresenter)estadisticasview.getPresenter();
estadisticas.linkProperty().addListener((ob,b,b1)->{
if(b1){
cambiarSeccion("Alumnos");
// reset link property
estadisticas.setLink(false);
}
});
}
作为旁注,我不是clear()
和add
,而是使用pContenedor.getChildren().setAll(<view>);
,因为您一次只展示一个孩子。
答案 1 :(得分:0)
基于@josé-pereda回答,最后我可以将子窗口(绿色区域)中的按钮/超链接链接到主控制器。我的解决方案的优点是我避免使用布尔变量。
在EstructuraPresenter
控制器中,我将监听器添加到EstadisticasPresenter
(来自其中一个子窗口的控制器)的按钮中:
public class EstructuraPresenter implements Initializable {
private static final Logger LOG = getLogger(EstructuraPresenter.class.getName());
@FXML
ToggleButton btnAlumnos, btnEstadisticas;
@FXML
StackPane pContenedor;
@Inject
private AlumnosView alumnosview;
@Inject
private EstadisticasView estadisticasview;
@Inject
private DataModel datos;
@Override
public void initialize(URL url, ResourceBundle rb) {
((EstadisticasPresenter) estadisticasview.getPresenter()).getLinkTotalAlumnos().setOnAction((ActionEvent event) -> {
this.cambiarSeccion("Alumnos");
});
//This call is from first time, where program starts to show by default Alumnos sub-window
cambiarSeccion("Alumnos");
btnAlumnos.setOnAction((ActionEvent event) -> {
cambiarSeccion("Alumnos");
});
btnEstadisticas.setOnAction((ActionEvent event) -> {
cambiarSeccion("Estadisticas");
});
}
public void cambiarSeccion(String nombreVentana) {
try {
btnAlumnos.setSelected(false);
btnEstadisticas.setSelected(false);
switch (nombreVentana) {
case "Alumnos":
if (btnAlumnos.isSelected() == false) {
sepTitulo.setVisible(true);
lbTitulo.setText("Alumnos");
btnAlumnos.setSelected(true);
alumnosview.getViewAsync(pContenedor.getChildren()::setAll);
pContenedor.getChildren().setAll(alumnosview.getView());
}
break;
case "Estadisticas":
if (btnEstadisticas.isSelected() == false) {
sepTitulo.setVisible(true);
lbTitulo.setText("Estadísticas");
btnEstadisticas.setSelected(true);
estadisticasview.getViewAsync(pContenedor.getChildren()::setAll);
}
break;
}
}
catch (Exception e) {
LOG.log(Level.SEVERE, e.toString());
new Dialogos().mostrarExcepcion(null, e);
}
}
}
注意此外,我更改了getChildren().clear()
&amp;&amp; getChildren().add()
至getChildren().setAll()
;这些可以防止从我放入绿色区域的每个窗口重新初始化控制器。
estadisticasview.getViewAsync(pContenedor.getChildren():: SETALL);
在EstadisticasPresenter控制器中,我添加了来自该控件的getter,我想用户clic转到另一个窗口(所以当用户clic on control,绿色区域改变另一个窗口/窗格时)。
public class EstadisticasPresenter implements Initializable {
private static final Logger LOG = getLogger(EstadisticasPresenter.class.getName());
@FXML
Hyperlink linkTotalAlumnos;
@Inject
private DataModel datamodel;
@Override
public void initialize(URL url, ResourceBundle rb) {
}
//Getters that I use in EstructuraPresenter controller to set up event handlers
public Hyperlink getLinkTotalAlumnos() {
return linkTotalAlumnos;
}
}