[英]JavaFX App: Switching between Panes won't load set content
我有带有侧面菜单栏的桌面应用程序。 主窗口是BorderPane
其中InsertLeft
包含VBox
。 我设置了Hbox buttons
及其行为,然后将它们一个一个地添加到VBox
。 InsertCenter
有很多元素的Pane
。
我为每个 GUI 布局创建了 3 个 fxml 文件。
这些 fxml 文件中的每一个都有它们的控制器。
我想在单击菜单按钮时切换 sample.fxml 内的 borderPane.center() 的内容。
我已经设法解决了一些问题,但主要问题是将数据加载到 .fxml 视图中。
当我运行我的应用程序时,它运行良好,每个 fxml 文件都有他的 FXMLLoader,它将内容加载到主控制器内的 borderPane 中。
单击按钮时出现问题。 它将切换窗格,但实际内容将重置为默认状态并且 Main.class 初始化被完全忽略。 按钮侦听器和标签值未初始化。 它只是空的 fxml 布局。 Main.class 中的每个变量,我想从 Tab1Controller 访问的内容都返回 NullPointerException - 甚至方法。
每个控制器都扩展了 AbstractController,其中包含在 start() 方法中初始化的 Main.class 实例。 所以我应该能够随时访问每个 Main.class 方法/变量。
问题 Gif:
一些代码示例:
我的Main.class
start()
方法:
public Controller myController;
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/sample.fxml"));
myController = new Controller();
myController.setMainApp(this);
loader.setController(myController);
Parent root = loader.load();
primaryStage.setTitle("Simple App");
primaryStage.setScene(new Scene(root));
primaryStage.show();
<other stuff>
}
public void setDefaultViewProperties(){
currentScanningFileProperty = new SimpleStringProperty();
myController.tab1Controller.actualPath.textProperty().bind(currentScanningFileProperty); //NullPointerException while called from Controller
fileCounterProperty = new SimpleLongProperty();
myController.tab1Controller.numOfScanned.textProperty().bind(fileCounterProperty.asString());
maliciousFilesCounterProperty = new SimpleIntegerProperty();
myController.tab1Controller.numOfMaliciousFiles.textProperty().bind(maliciousFilesCounterProperty.asString());
myController.tab1Controller.fileChoiceBtn.setOnMouseClicked(event -> chooseFile());
myController.tab1Controller.runScanBtn.setOnMouseClicked(event -> new Thread(() -> {
try {
resetValues();
startFileWalking(chosenFile);
} catch (IOException e) {
e.printStackTrace();
}
}).start());
}
主控制器:
package sample;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class Controller extends AbstractController implements Initializable{
public HBox sideMenu;
public VBox mainMenu;
public BorderPane borderPane;
public Boolean isButton1Pressed = false;
public Boolean isButton2Pressed = false;
public static final String TAB_1 = "TAB-1";
public static final String TAB_2 = "TAB-2";
public Button malwareButton;
public Button webShieldButton;
public Tab1Controller tab1Controller;
public Tab2Controller tab2Controller;
@Override
public void initialize(URL location, ResourceBundle resources) {
createMenuButtons();
setSideMenu();
setMenuButtonsListeners();
}
private void setSideMenu(){
mainMenu.getChildren().add(item(malwareButton));
mainMenu.getChildren().add(item(webShieldButton));
mainMenu.setStyle("-fx-background-color:#004D40");
}
private HBox item(Button menuButton){
menuButton.setPrefSize(200, 50);
menuButton.setStyle("-fx-background-color: transparent;");
menuButton.setTextFill(Color.web("#E0F2F1"));
menuButton.setPadding(Insets.EMPTY);
sideMenu = new HBox(menuButton);
return sideMenu;
}
public void setMenuButtonsListeners(){
malwareButton.setOnMousePressed(event -> {
setButtonStylePressed(malwareButton);
setButtonStyleUnpressed(webShieldButton);
isButton1Pressed = true;
isButton2Pressed = false;
loadTab1Content();
main.setDefaultViewProperties();
});
webShieldButton.setOnMousePressed(event -> {
setButtonStylePressed(webShieldButton);
setButtonStyleUnpressed(malwareButton);
isButton1Pressed = false;
isButton2Pressed = true;
loadTab2Content();
});
malwareButton.setOnMouseExited(event -> {
if(!isButton1Pressed){
setButtonStyleUnpressed(malwareButton);
}
});
webShieldButton.setOnMouseExited(event -> {
if(!isButton2Pressed){
setButtonStyleUnpressed(webShieldButton);
}
});
malwareButton.setOnMouseEntered(event -> setButtonStylePressed(malwareButton));
webShieldButton.setOnMouseEntered(event -> setButtonStylePressed(webShieldButton));
}
public void setButtonStylePressed(Button btn){
btn.setStyle("-fx-background-color: #E0F2F1");
btn.setTextFill(Color.web("#004D40"));
}
public void setButtonStyleUnpressed(Button btn){
btn.setStyle("-fx-background-color: transparent");
btn.setTextFill(Color.web("#E0F2F1"));
}
private void loadTab1Content(){
FXMLLoader tab1loader = new FXMLLoader();
tab1loader.setLocation(getClass().getResource("/tab_1_content.fxml"));
try {
if (tab1Controller == null){
tab1Controller = new Tab1Controller();
}
tab1loader.setController(tab1Controller);
borderPane.setCenter(tab1loader.load());
} catch (IOException e) {
e.printStackTrace();
}
}
private void loadTab2Content(){
FXMLLoader tab2loader = new FXMLLoader();
tab2loader.setLocation(getClass().getResource("/tab_2_content.fxml"));
try {
if (tab2Controller == null){
tab2Controller = new Tab2Controller();
}
tab2loader.setController(tab2Controller);
borderPane.setCenter(tab2loader.load());
} catch (IOException e) {
e.printStackTrace();
}
}
private void createMenuButtons(){
malwareButton = new Button();
malwareButton.setText(TAB_1);
webShieldButton = new Button();
webShieldButton.setText(TAB_2);
}
}
Tab1Controller:
package sample;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.ResourceBundle;
/**
* Created by admin on 5. 5. 2018.
*/
public class Tab1Controller extends AbstractController implements Initializable {
public ProgressBar progressBar;
public Button runScanBtn;
public Button fileChoiceBtn;
public Label chosenPath;
public Label actualPath;
public Label numOfMaliciousFiles;
public Label hashValue;
public Label scanFinishedMsg;
public Label numOfScanned;
public Button showFoundMalwareButton;
@Override
public void initialize(URL location, ResourceBundle resources) {
runScanBtn.setDisable(true);
scanFinishedMsg.setVisible(false);
showFoundMalwareButton.setVisible(false);
showFoundMalwareButton.setOnAction(event -> showPopupWindow());
}
更新#1 - 单击按钮后通过 Main.class 更新 fxml 值
我终于设法无一例外地运行了应用程序。 我必须为名为 Tab1Controller 的窗格 fxml 布局创建下一个控制器。 当我初始化 Controller 时,它立即在内部初始化了 Tab1Controller。 因此,当我想更改 Center BorderPane 标签时,我必须调用myController.tab1Controller.tabLabel.setText()
我不知道这是否是解决这个问题的好方法。 但现在我又回到了我的老问题。 当我单击 TAB-1 时,它将加载内容,但值未初始化为默认状态。
例如,我有几个实时更新的标签。 我使用默认值将一些 SimpleProperties 绑定到其中。 它以前工作过,但由于我有三个控制器,它会第一次加载数据,但是当我单击 TAB-1 按钮时,它只会加载 fxml 内容,但不会设置这些标签。
所以我在 Main.class 中创建了公共方法,每次我从 Controller 切换到 TAB-1 时都会调用它。
public void setDefaultViewProperties(){
myController.tab1Controller.actualPath.textProperty().bind(currentScanningFileProperty);
myController.tab1Controller.numOfScanned.textProperty().bind(fileCounterProperty.asString());
myController.tab1Controller.numOfMaliciousFiles.textProperty().bind(maliciousFilesCounterProperty.asString());
}
但是现在每次我点击 TAB-1 我都会
java.lang.NullPointerException: Cannot bind to null
您可以使用setVisible()
方法制作两个窗格并在它们之间切换
例子:
void btn1Clicked() {
pane1.setVisible(true);
pane2.setVisible(false);
}
void btn2Clicked() {
pane1.setVisible(false);
pane2.setVisible(true);
}
您可以使用 TabPane 来实现此行为: https ://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/TabPane.html
解决了。 我不确定如何,但 setDefaultViewProperties() 目前没有抛出 NullPointerException。 我没有更改代码中的任何内容:
malwareButton.setOnMousePressed(event -> {
setButtonStylePressed(malwareButton);
setButtonStyleUnpressed(webShieldButton);
isButton1Pressed = true;
isButton2Pressed = false;
loadTab1Content();
main.setDefaultViewProperties();
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.