Javafx:Menuitem not taking value from controller - javafx

I am trying to make a browser using javafx in which i want to add the bookmark functionality.I want to bookmark the webpage and display it in the menuitem.Bookmarking is working but the problem is that it is not displaying the bookmark field in the menuitem.I try to print the value in the console it is printing the value in the console but it is not displaying in the menuitem.
Now ,FirstpageController is the main controller whose fxml file is "Firstpage.fxml".This fxml only contain a tabpane.It contain an included file that is TabpageController which contains following code:
TabpageController contains a button "bookmark_btn" which is used to add bookmark in the browser using addbookmark() method.It's fxml file is "Tabpage.fxml" which is included in "Firstpage.fxml".
TabpageController.java
public class TabpageController implements Initializable
{
#FXML public TextField addressField;
#FXML private Button bookmark_btn;
#FXML private Menu bookmenu;
#FXML public MenuItem bkmenuitem;
#FXML
private void addbookmark() throws IOException
{
Bookmodel bm = new Bookmodel(addressField.getText(), first.tab1.getText()); //Take the url and tile
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("/tabcheck/Bookmarkpage.fxml"));
AnchorPane bookmarkpane = loader.load();
Stage bookstage = new Stage();
bookstage.setResizable(false);
bookstage.show();
Scene bookscene = new Scene(bookmarkpane);
bookstage.setScene(bookscene);
Bookmarkcontroller bc = loader.getController();
bc.setBookinfo(bm);
//bkmenuitem.setText(DEFAULT_HOME.toString());
}
public void setBookinfo(Bookmodel bookinfo)
{
System.out.println("setbookinfo enetring for add btn");
bkmenuitem.setText(bookinfo.getTitile());
System.out.println(bookinfo.getTitile());
System.out.println(bkmenuitem.getText());
System.out.println("setbookinfo");
this.bookinfo = bookinfo;
}
Now by clicking on "bookmark_btn" it open new scene that is "Bookmarkpage.fxml" which a simple bookmarking window which contain 2 textfield for url,title and "add" button.Now by clicking on "Add" button it should bookmark the current page.There is the menu "bookmenu" in the "tabpage.fxml" which contain menuitem "bkmenuitem".All the bookmark field should be display in the menuitem "bkmenuitem" which is in the "tabpage.fxml" file.
Also the controller of this "Bookmarkpage.fxml" is "Bookmarkcontroller.java" which contain following code:
Bookmarkcontroller.java
public class Bookmarkcontroller {
#FXML
TextField bookmarkTitleTextField;
#FXML
TextField bookmarkURLTextField;
#FXML private Button addbook;
TabpageController tabpageController;
private Bookmodel bookinfo;
#FXML private void BookmarkToModelActionEvent(ActionEvent event) throws IOException
{
((Node) event.getSource()).getScene().getWindow().hide();
Bookmodel addbm = new Bookmodel(bookmarkTitleTextField.getText());
System.out.println(bookmarkTitleTextField.getText());
System.out.println("add to menuitems");
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("/tabcheck/Tabpage.fxml"));
AnchorPane bookmarkpane = loader.load();
TabpageController addtc = loader.getController();
addtc.setBookinfo(addbm);
//bkmenuitem.setText(bookmarkTitleTextField.getText());
}
public void setBookinfo(Bookmodel bookinfo) {
bookmarkURLTextField.setText(bookinfo.getUrl());
bookmarkTitleTextField.setText(bookinfo.getTitile());
this.bookinfo = bookinfo;
}
This the model class of the "Bookmarkcontroller"
Bookmodel.java
public class Bookmodel {
private String url;
private String titile;
public Bookmodel() {
}
public Bookmodel(String url, String titile) {
this.url = url;
this.titile = titile;
}
public Bookmodel(String titile) {
this.titile = titile;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getTitile() {
return titile;
}
public void setTitile(String titile) {
this.titile = titile;
}
}
Output from Bookmarkcontroller.java
google
add to menuitems
Output from TabpageController.java
setbookinfo enetring for add btn
google
google
setbookinfo
As it is printing the output of these 2 lines as"google"
System.out.println(bookinfo.getTitile());
System.out.println(bkmenuitem.getText());
but not showing anything in the menuitem field for following line...
bkmenuitem.setText(bookinfo.getTitile());
I try a lot and also check it on stackoverflow on how to pass parameter from one controller to another but nothing is working.Also I am not getting any error.But the menuitem "bkmenuitem " is not printing the value.Any help would be appreciated as i am struggling a lot sorry for the long code .If i don't provide this much code then i won't understand anything.

I was able to get this to work by changing the TabpageController addbookmark method to
FXMLLoader loader = new FXMLLoader();
loader.setLocation( ....);
loader.load();
AnchorPane bookmarkpane = loader.getRoot();
Bookmarkcontroller bc = loader.getController();
Stage bookstage = new Stage();
bookstage.setResizable(false);
Scene bookscene = new Scene(bookmarkpane);
bookstage.setScene(bookscene);
bookstage.show();
bc.setMenuItem(bkmenuitem);
bc.setBookinfo(bm);
showing the stage after scene is added and passing thru the menuitem then
in Bookmarkcontroller creating a setter for the menu item and updating it
MenuItem menuitem;
public void setMenuItem(MenuItem bkmenuitem)
{
this.menuitem = bkmenuitem ;
}
public void setBookinfo(Bookmodel bookinfo) {
bookmarkURLTextField.setText(bookinfo.getUrl());
bookmarkTitleTextField.setText(bookinfo.getTitile());
this.bookinfo = bookinfo;
menuitem.setText(bookinfo.getTitile());
}

Related

Javafx setText for label is not working if scene is changed after

maybe someone will explain. I have a method, that sets label text if login is successful.
#FXML
private void loginUser(ActionEvent event) throws IOException {
String user = username.getText();
String pass = password.getText();
if(validateFields(user, pass) && validateLogin(user, pass)) {
welcome.setText("Welcome, " + globalUser.getUserName()); //works
infoLine.setText("Redirecting to main dashboard..."); //works
}
}
And if I add additional code, which changes the scene after login, the label text is not changing:
#FXML
private void loginUser(ActionEvent event) throws IOException {
String user = username.getText();
String pass = password.getText();
if(validateFields(user, pass) && validateLogin(user, pass)) {
welcome.setText("Welcome, " + CurrentUser.getCurrentUser().getUserName());//not working
infoLine.setText("Redirecting to main dashboard..."); //not working
//Changing scene after successful login
Parent home = FXMLLoader.load(getClass().getResource(ScenePath.HOME.getPath()));
Scene homeScene = new Scene(home);
Stage appStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
appStage.setScene(homeScene);
appStage.show();
}
}
How to solve this problem?
My controller class looks like this. Nothing special. After 2 validations it set texts of labels and changes scenes.
public class LoginController {
#FXML
private TextField username;
#FXML
private PasswordField password;
#FXML
private Label infoLine;
#FXML
private Label welcome;
#FXML
private Button exitBtn;
UserDao userDao = new UserDao();
#FXML
private void initialize() {
close();
}
#FXML
private void loginUser(ActionEvent event) throws IOException {
String user = username.getText();
String pass = password.getText();
if(validateFields(user, pass) && validateLogin(user, pass)) {
welcome.setText("Welcome, " + CurrentUser.getCurrentUser().getUserName());
infoLine.setText("Redirecting to main dashboard...");
//Changing scene after successful login
Parent home = FXMLLoader.load(getClass().getResource(ScenePath.HOME.getPath()));
Scene homeScene = new Scene(home);
Stage appStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
appStage.setScene(homeScene);
appStage.show();
}
}
private boolean validateFields(String userName, String password) {
if (userName.isEmpty() || password.isEmpty()) {
infoLine.setText("Username and password can't be empty!");
return false;
}
return true;
}
private synchronized boolean validateLogin(String userName, String password) {
User user = userDao.getConnectedUser(userName, password);
if (user == null) {
infoLine.setText("User not found!");
return false;
}
CurrentUser.setCurrentUser(user);
return true;
}
private void close() {
exitBtn.setOnAction(SceneController::close);
}
}
Basically, the text is changing. The problem is as soon as the text is changed, you load the next view. This is happening really fast. The solution is to slow things down. Mainly, give the user time to see the text change before loading the new view. This can be done using PauseTransition.
After the text change, try the following code. After the text changes, this code gives a two-second delay before loading the new view.
PauseTransition pause = new PauseTransition(Duration.seconds(2));
pause.setOnFinished(
e -> {
Parent home = FXMLLoader.load(getClass().getResource(ScenePath.HOME.getPath()));
Scene homeScene = new Scene(home);
Stage appStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
appStage.setScene(homeScene);
appStage.show();
}
);
pause.play();

Pass Variable to another Controller

Hello I need to pass The User and Pass Values to another Controller:
like this AdminController ->UserController.
In my code I have This in AdminController:
private TextField fusuario;
#FXML
private PasswordField fcontrasena;
String a;
String b;
public void captura() {
a=fusuario.getText().toString();
System.out.println("el usuario es x:"+a);
b=fcontrasena.getText().toString();
System.out.println("la contraseƱa es x:"+b);
}
public String setFusuario(String a) {
this.fusuario.setText(a);
return a;
}
public String setFcontrasena(String b) {
this.fcontrasena.setText(b);
return b;
}
This is in my UserController:
Stage administrador=new Stage();
FXMLLoader carga = new FXMLLoader(getClass().getResource("Admin.fxml"));
Parent StackPane =(Parent) carga.load();
AdminScreenController control = carga.<AdminScreenController>getController();
control.deshabilitarespuesta();
Scene scene = new Scene(StackPane);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
administrador.setScene(scene);
administrador.setTitle("AdminScreen");
Stage userstage=(Stage)comentarios.getScene().getWindow();
userstage.hide();
administrador.show();
How i Pass this Values, some help or orientation?
This is easy you need to declare a static variable like this in the FIRST Controller
static String alertTYPE;
Then in our ERROR checking code we give alertTYPE a value
if(txtAmount.getLength() == 0){
alertTYPE = "1";
customAlert();
txtAmount.requestFocus();
return;
}
Now we call customAlert() method still in the same Controller class
Her is the customAlert method code
public void customAlert() throws IOException{
// This method displays the MODAL Alert alert.fxml and it is controlled by AlertController
// =========================================================================================
alertPane = FXMLLoader.load(getClass().getResource("alert.fxml"));// pane you are GOING TO
//Scene Sscene = new Scene(merrorPane, 600, 400);
// NO NEED TO RE-SIZE but this is code to change size
Scene Mscene = new Scene(alertPane);
Mstage = new Stage();
Mstage.initStyle(StageStyle.UNDECORATED);
Mstage.setResizable(false);
Mstage.initModality(Modality.APPLICATION_MODAL);
Mstage.setScene(Mscene);
Mstage.showAndWait();
}
Here in the AlertController we make use of the alertTYPE value
#Override
public void initialize(URL url, ResourceBundle rb) {
if(alertTYPE.equals("1")){
lblMessage.setText("Enter "+type+" Amount");
}else if(alertTYPE.equals("2")){
You need to be sure the Controller you are going to imports the static variable alertTYPE like this
import static checkbook.CBManagerController.alertTYPE;
This was a long way around but we hope you get the idea
One word of caution once static variables are declared and given a value that value is retained until a new value is given to the variable or you set it to nothing like this for a String alertTYPE = ""; With great power comes great responsibility ha ha

How can I use .setText on a non-Static Label from a different Class [duplicate]

I have written a controller for two windows /stages.
The first window is opened in the MainClass. The second in the Controller, if the user clicks onto a button.
How can I get the TextFields from second.fxml in the applyFor()-method?
Thanks.
#FXML
protected void requestNewAccount(ActionEvent event) {
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("second.fxml")); // TextFields in there
Parent root = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.setTitle("Second Window");
Scene scene = new Scene(root);
String css = MainOnlineCustomer.class.getResource("/style.css").toExternalForm();
scene.getStylesheets().clear();
scene.getStylesheets().add(css);
stage.setScene(scene);
stage.show();
} catch (IOException e) {
logger.error(e);
}
}
/**
* closes the "second"-Window
* #param event
*/
#FXML
protected void cancel(ActionEvent event) {
final Node source = (Node) event.getSource();
final Stage stage = (Stage) source.getScene().getWindow();
stage.close();
}
#FXML
protected void applyFor(ActionEvent event) {
// get values from TextField in second.fxml here!!!
}
It's not good to share controllers between fxmls unless they serve the same purpose. Here both fxml seem to serve a different purpose (account management, login or something similar for one of them and creating a new account for the other). What is even worse is that those classes do not share the same controller instance, which means the small (and probably only) benefit you could get from using the same controller, is not used here. You should better use different controllers.
Since you use Modality.APPLICATION_MODAL as modality, I'd recommend using showAndWait instead of show to open the new stage. This will enter a nested event loop, which allows the UI to remain responsive and continues after the invocation of showAndWait once the stage is closed.
Furthermore add a method to the controller of second.fxml that allows you to retrieve the result.
Example
This creates a Person object with given name and family name.
"primary window (opening the "inner" stage)
FXMLLoader loader = new FXMLLoader(getClass().getResource("second.fxml"));
Stage subStage = new Stage();
subStage.initModality(Modality.APPLICATION_MODAL);
subStage.setTitle("Second Window");
Scene scene = new Scene(loader.load());
subStage.setScene(scene);
subStage.showAndWait();
Optional<Person> result = loader.<Supplier<Optional<Person>>>getController().get();
if (result.isPresent()) {
// do something with the result
}
controller for "inner" content
public class SecondController implements Supplier<Optional<Person>> {
#FXML
private TextField givenName;
#FXML
private TextField familyName;
private boolean submitted = false;
// handler for submit action
#FXML
private void submit() {
submitted = true;
givenName.getScene().getWindow().hide();
}
// handler for cancel action
#FXML
private void cancel() {
givenName.getScene().getWindow().hide();
}
#Override
public Optional<Person> get() {
return submitted ? Optional.of(new Person(givenName.getText(), familyName.getText())) : Optional.empty();
}
}
Note that you can gain access to any data available to the controller this way. I wouldn't recommend accessing any nodes (like TextFields) directly though, since this makes changing the UI harder.
Using the Supplier interface here is not necessary, but I chose to do this to achieve a loose coupling between SecondController and the main window.

WebEngine not loading URL on button click

I am coding a Tabbed web browser in JAVAFx. The problem i am facing is :-
When I click on Home Button (HomeB) it is not loading the DEFAULT_URL in the current tab. Here is some useful part of my code. Some body please fix it. Thanks
class Browser extends Region{
final BorderPane borderPane;
final TabPane tabPane;
private final HBox toolbarMain;
WebView browser = new WebView();
final WebEngine webEngine = browser.getEngine();
private String DEFAULT_URL= "http://www.google.com";
final TextField urlField = new TextField(DEFAULT_URL);
//Custom function for creation of New Tabs.
private Tab createAndSelectNewTab(final TabPane tabPane, final String title) {
Tab tab = new Tab(title);
webEngine.locationProperty().addListener(new ChangeListener<String>() {
#Override public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
urlField.setText(newValue);
}
});
final ObservableList<Tab> tabs = tabPane.getTabs();
tab.closableProperty().bind(Bindings.size(tabs).greaterThan(2));
tabs.add(tabs.size() - 1, tab);
tabPane.getSelectionModel().select(tab);
return tab;
}
//Initialization function of the program.
public Browser() {
borderPane = new BorderPane();
tabPane = new TabPane();
toolbarMain = new HBox();
Button HomeB = new Button();
HomeB.setText("HOME");
tabPane.setSide(Side.TOP);
final Tab newtab = new Tab();
newtab.setText("+");
newtab.setClosable(false); // this will not let the New Tab button(TAB) close
tabPane.getTabs().addAll(newtab); //Addition of New Tab to the tabpane.
createAndSelectNewTab(tabPane, " ");
//Function to add and display new tabs with default URL display.
tabPane.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>() {
#Override
public void changed(ObservableValue<? extends Tab> observable,
Tab oldSelectedTab, Tab newSelectedTab) {
if (newSelectedTab == newtab) {
Tab tab = new Tab();
//WebView - to display, browse web pages.
WebView browser = new WebView();
final WebEngine webEngine = browser.getEngine();
webEngine.load(DEFAULT_URL);
EventHandler<ActionEvent> goAction = new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
webEngine.load(urlField.getText().startsWith("http://")
? urlField.getText()
: "http://" + urlField.getText());
}
};
urlField.setOnAction(goAction);
final VBox vBox = new VBox(5);
vBox.getChildren().setAll(browser);
VBox.setVgrow(browser, Priority.ALWAYS);
tab.setContent(vBox);
final ObservableList<Tab> tabs = tabPane.getTabs();
tab.closableProperty().bind(Bindings.size(tabs).greaterThan(2));
tabs.add(tabs.size() - 1, tab);
tabPane.getSelectionModel().select(tab);
}
}
});
//OnClick handling HomeB
HomeB.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent event){
webEngine.load(DEFAULT_URL);
}
});
toolbarMain.getChildren().addAll(HomeB,urlField);
//Placement of elements in borderpane
borderPane.setCenter(tabPane);
borderPane.setTop(toolbarMain);
getChildren().add(borderPane);
}
}
When you click on the HomeB the default URL is loaded into the browser, a global WebView. That works, but you don't see the URL loaded, because you haven't added this browser to any of your tabs.
Assuming you create the first tab for the home button:
tabPane.getTabs().addAll(newtab); // tab 0, then moves to 1
// Here you create a new tab, but put it on the 0 index:
createAndSelectNewTab(tabPane, " ");
// You can add now your global browser to the first tab:
final VBox vBoxIni = new VBox(5);
vBoxIni.getChildren().setAll(browser);
VBox.setVgrow(browser, Priority.ALWAYS);
tabPane.getTabs().get(0).setContent(vBoxIni);
Other option will be using the local webView you have created for each tab, and load the default URL on the active tab:
HomeB.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent event){
VBox vBox=(VBox)tabPane.getSelectionModel().getSelectedItem().getContent();
if(vBox!=null){
WebView webView=(WebView)vBox.getChildren().get(0);
webView.getEngine().load(DEFAULT_URL);
}
}
});
Note this won't work on the first tab, since you haven't set any content there.

JavaFX TreeTableView Remove Item ContextMenu

I have the following in my FXMLController:
#FXML
TreeTableView<FileModel> treeTblViewFiles;
//...
#Override
public void initialize(URL url, ResourceBundle rb) {
//...
final ObservableList<Song> data = FXCollections.observableArrayList(
new Song("Song#1", "/home/pm/songs/song1.mp3","12MB"),
new Song("Song#2", "/home/pm/songs/song2.mp3","12MB"),
new Song("Song#3", "/home/pm/songs/song3.mp3","12MB"),
new Song("Song#4", "/home/pm/songs/song4.mp3","12MB"),
new Song("Song#5", "/home/pm/songs/song5.mp3","12MB"),
new Song("Song#6", "/home/pm/songs/song6.mp3","12MB"),
new Song("Song#7", "/home/pm/songs/song7.mp3","12MB"),
new Song("Song#8", "/home/pm/songs/song8.mp3","12MB"),
new Song("Song#9", "/home/pm/songs/song9.mp3","12MB"),
new Song("Song#10", "/home/pm/songs/song10.mp3","12MB")
);
treeTblViewFiles.setRowFactory(new Callback<TreeTableView<FileModel>, TreeTableRow<FileModel>>(){
#Override
public TreeTableRow<FileModel> call(TreeTableView<FileModel> treeTableView) {
final TreeTableRow<FileModel> row = new TreeTableRow<>();
final ContextMenu rowMenu = new ContextMenu();
MenuItem removeItem = new MenuItem("Remove");
removeItem.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent t) {
data.remove(row.getItem());
treeTblViewFiles.getSelectionModel().clearSelection();
System.out.println("Context Menu -> ActionEvent");
}
});
rowMenu.getItems().add(removeItem);
row.contextMenuProperty().bind(Bindings.when(Bindings.isNotNull(row.itemProperty()))
.then(rowMenu)
.otherwise((ContextMenu)null));
return row;
}
});
//...
}
Song is a class that inherits from FileModel.
Basically what I do is create my custom row factory where I delete the selected item, but nothing happens. No item is deleted from treeTableView control, although it is removed from the ObservableList.
What am I missing or misunderstood?
Thanks in advance.
I haven't worked with TreeTableView, so this is a bit of a shot in the dark: but TreeTableViews (and TreeViews) aren't wired to the data quite as cleanly as TableViews. Each data item is wrapped in a TreeItem to give it the hierarchical structure. So I think you need something like
#Override
public void handle(ActionEvent t) {
data.remove(row.getItem());
TreeItem<FileModel> treeItem = row.getTreeItem();
// may need to check treeItem.getParent() is not null:
treeItem.getParent().getChildren().remove(treeItem);
treeTblViewFiles.getSelectionModel().clearSelection();
System.out.println("Context Menu -> ActionEvent");
}

Resources