Add a MenuItem to multiple Menus - java

I'm currently working on a MenuBar for a library(for books) in JavaFX8. I would like to add a MenuItem to several menus. If I do that, the output is a warning saying that this MenuItem has already been added and in the Application the Book Menu is not shown.
Code:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(Stage stage) {
//Layout: BorderPane
BorderPane layout = new BorderPane();
//Define what is where
layout.setTop(addMenuBar());
//make it visible
Scene scene = new Scene(layout, 900, 600);
stage.setScene(scene);
stage.setTitle("Library");
stage.show();
}
public MenuBar addMenuBar() {
//create the menubar
MenuBar menu = new MenuBar();
//create the menus
Menu fileMenu = new Menu("File");
Menu bookMenu = new Menu("Book");
Menu manageMenu = new Menu("Manage");
Menu sortMenu = new Menu("Sort");
//create the menu items
MenuItem exitItem = new MenuItem("Exit");
MenuItem booksAlphabetical = new MenuItem("Books alphabetical");
MenuItem encAlphabetical = new MenuItem("Encyclopedias alphabetical");
MenuItem addBook = new MenuItem("Add book");
MenuItem addCategory = new MenuItem("Add category");
MenuItem addPublisher = new MenuItem("Add Publisher");
MenuItem booksReview = new MenuItem("Books sorted by review");
//make the menus ready
//file menu
fileMenu.getItems().add(exitItem);
//bookMenu
bookMenu.getItems().addAll(addBook, booksAlphabetical,
encAlphabetical, booksReview);
//manageMenu
manageMenu.getItems().addAll(addBook, addCategory, addPublisher);
//sortMenu
sortMenu.getItems().addAll(booksAlphabetical, encAlphabetical, booksReview);
//add menus to the menubar
menu.getMenus().addAll(fileMenu, bookMenu, manageMenu, sortMenu);
//return the menubar
return menu;
}
}
Thanks in advance!

Simply said, it happens because you put a node to the two different parents (see the booksAlphabetical used twice):
bookMenu.getItems().addAll(addBook, booksAlphabetical, encAlphabetical, booksReview);
sortMenu.getItems().addAll(booksAlphabetical, encAlphabetical, booksReview);
It's not known where the MenuItems booksAlphabetical, encAlphabetical, booksReview should appear, so they will be added only to the last one sortMenu.
Why does it happen? The JavaFX API is built that each Node has a collection of properties, including a parent property, that is only and only one.
The solution is to create them for the second time to make them unique since you want to use them twice.
MenuItem booksAlphabeticalSort = new MenuItem("Books alphabetical");
MenuItem encAlphabeticalSort = new MenuItem("Encyclopedias alphabetical");
MenuItem booksReviewSort = new MenuItem("Books sorted by review");
sortMenu.getItems().addAll(booksAlphabeticalSort, encAlphabeticalSort, booksReviewSort);

Related

I have a class that extends a javafx stackpane and within that class would like to create a menubar containing a menu with items

here's the code:
import javafx.scene.layout.StackPane;
import javafx.scene.control.*;
import csc2a.desc.model.*;
public class CrisisPane extends StackPane{
//create menu
Menu fileMenu = new Menu("File");
//create menu items
MenuItem openFileItem = new MenuItem("Open file");
//add menu item to menu
fileMenu.getItems().add(openFileItem); //syntax error here
//create menu bar
MenuBar menuBar = new MenuBar();
//add menu to menubar
menubar.getMenus().add(fileMenu); //and syntax error here
}
every time i try adding a new menu item and adding the menu to the menubar i get the error
(Syntax error on token "getItems", Identifier expected after this token)
this is how my lecturer explained it to us and represented it in code
I'm really new to javafx and have some basic java concepts down but have experience in c++ already and i'm using eclipse as an IDE

Can't access button/textarea in the handle event

I've just started using JavaFX and have been trying to add an event that will add text to a textarea and clear a text field when you press the 'send' button. However, I can't seem to check the source of the event in the handle method.
I've tried to search for a solution, but others don't seem to face the same issue - either that or I'm missing something obvious.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ApplicationMain extends Application implements EventHandler<ActionEvent>{
Stage window;
// Main Method
public static void main(String[] args) {
launch(args);
}
// Scene Method
#SuppressWarnings("static-access")
#Override
public void start(Stage primaryStage) {
// Window Stuff
window = primaryStage;
window.setTitle("Chat Application");
// Setup Grid Layout
GridPane grid = new GridPane();
grid.setAlignment(Pos.TOP_LEFT);
grid.setHgap(10);
grid.setStyle("-fx-background-color: #272828;");
// MenuBar
MenuBar menu = new MenuBar();
menu.setPrefWidth(1000);
menu.setPrefHeight(20);
// Creation of File + Help
Menu file = new Menu("File");
Menu help = new Menu("Help");
// Add the Menus to the MenuBar
menu.getMenus().add(file);
menu.getMenus().add(help);
// Add MenuBar to Scene
menu.setVisible(true);
grid.add(menu, 0, 0);
// Text Area Stuff
TextArea area = new TextArea();
area.setPrefWidth(1000);
area.setPrefHeight(700);
area.setEditable(false);
area.setStyle("-fx-control-inner-background: #313233;");
// Add Text Area to Grid
grid.add(area, 0, 1);
// Text Field
TextField enter = new TextField();
enter.setPromptText("Type here...");
enter.setMaxWidth(920);
enter.setMaxHeight(30);
enter.setStyle("-fx-padding: 5px;");
// Button
Button send = new Button("Send!");
// Set the Handler for the Send Button Event
send.setOnAction(this);
// Use of HBox to Space out Text Field & Send Button
HBox row = new HBox();
row.setSpacing(10);
row.setHgrow(enter, Priority.ALWAYS);
row.getChildren().addAll(enter, send);
// Use of VBox to Space out Text Field
VBox box = new VBox();
box.setSpacing(10);
box.setPadding(new Insets(10));
box.getChildren().add(row);
// Add HBox in VBox to Grid
grid.add(box, 0, 2);
// Scene Stuff
Scene scene = new Scene(grid, 1000, 750);
window.setScene(scene);
// Display the Window
window.show();
}
// Event Handler
#Override
public void handle(ActionEvent event) {
if (event.getSource() == send) {
}
}
}
Whenever I try to check if the source was the button 'send', it doesn't show up - as if it's not accessible by the method. I'm unsure of how to fix this.
There is a few things wrong with this code but we can fix it no problemo.
First learn naming conventions and stick to them as #kleopatra says if you google java naming conventions you will be overloaded with many results read a few
Next you shouldn't call a Stage a window there is already another object that has that name so it may confuse others but if its only for you its ok I guess
I wouldn't #SuppressWarnings("static-access") as you have done if you have an error fix it don't ignore it
The send.setOnAction(this); is not the way to handle events remove your implements EventHandler<ActionEvent> you can use the event handler by setting it like this
send.setOnAction(event -> sendToTextArea(enter.getText(), area));
And this is what the method you are calling should look like
private void sendToTextArea(String string, TextArea textArea){
//textArea.setText(string);Use setText if you want to set the whole area to something
textArea.appendText(string+"\n");//Use appendText to append add new line because chat app
}
Eveything else looks good here is what your final product should look like
public class Main extends Application {
private Stage stage;
#Override
public void start(Stage primaryStage) {
// stage Stuff
stage = primaryStage;
stage.setTitle("Chat Application");
// Setup Grid Layout
GridPane grid = new GridPane();
grid.setAlignment(Pos.TOP_LEFT);
grid.setHgap(10);
grid.setStyle("-fx-background-color: #272828;");
// MenuBar
MenuBar menu = new MenuBar();
menu.setPrefWidth(1000);
menu.setPrefHeight(20);
// Creation of File + Help
Menu file = new Menu("File");
Menu help = new Menu("Help");
// Add the Menus to the MenuBar
menu.getMenus().add(file);
menu.getMenus().add(help);
// Add MenuBar to Scene
menu.setVisible(true);
grid.add(menu, 0, 0);
// Text Area Stuff
TextArea area = new TextArea();
area.setPrefWidth(1000);
area.setPrefHeight(700);
area.setEditable(false);
area.setStyle("-fx-control-inner-background: #313233;");
// Add Text Area to Grid
grid.add(area, 0, 1);
// Text Field
TextField enter = new TextField();
enter.setPromptText("Type here...");
enter.setMaxWidth(920);
enter.setMaxHeight(30);
enter.setStyle("-fx-padding: 5px;");
// Button
Button send = new Button("Send!");
// Set the Handler for the Send Button Event
send.setOnAction(event -> sendToTextArea(enter, area));
// Use of HBox to Space out Text Field & Send Button
HBox row = new HBox();
row.setSpacing(10);
row.setHgrow(enter, Priority.ALWAYS);
row.getChildren().addAll(enter, send);
// Use of VBox to Space out Text Field
VBox box = new VBox();
box.setSpacing(10);
box.setPadding(new Insets(10));
box.getChildren().add(row);
// Add HBox in VBox to Grid
grid.add(box, 0, 2);
// Scene Stuff
Scene scene = new Scene(grid, 1000, 750);
stage.setScene(scene);
// Display the stage
stage.show();
}
private void sendToTextArea(TextField textField, TextArea textArea){
//textArea.setText(string);Use setText if you want to set the whole area to something
//textArea.clear();and .clear to clear all text from the TextArea
textArea.appendText(textField.getText()+"\n");//Use appendText to append add new line because chat app
textField.clear();
}
public static void main(String[] args) { launch(args); }
}
Make your TextArea and TextField class variables:
private TextArea area;
private TextField enter;
Change their initialization:
// Text Area Stuff
area = new TextArea();
// Text Field
enter = new TextField();
And your event handler :
// Event Handler
#Override
public void handle(ActionEvent event) {
area.setText(enter.getText());
}
If any of these changes is not clear, do not hesitate to ask.

Set Action on button to do two action in one click

Here is the scenario, I have a main window and I click on one button it opens a pop up window. In this pop window I have table view that have some data display in it, and it have a one button called select. After select the data from table view, so when I push the select button I want this pop window to close and the data I selected from that to appear in my main window.
So far only thing I can do is extract the data from pop up window, I want it to close aswell with just one click
private void venueDisplay(String title, String message) {
Stage window = new Stage();
//Block events to other windows
window.initModality(Modality.APPLICATION_MODAL);
window.setTitle(title);
window.setMinWidth(400);
HBox hBox = new HBox();
hBox.setPadding(new Insets(10,10,10,10));
hBox.setSpacing(10);
hBox.setMaxHeight(20);
hBox.setAlignment(Pos.BOTTOM_CENTER);
hBox.getChildren().add(selectVenueButton);
//Display all the available venues to choose for allocation
VBox layout = new VBox(10);
venueList = new ListView<>();
ObservableList<Venue> observableVenue = FXCollections.observableArrayList(model.getVenues());
venueList.setItems(observableVenue);
layout.getChildren().addAll(venueList, hBox);
//Display window and wait for it to be closed before returning
Scene scene1 = new Scene(layout,300,500);
window.setScene(scene1);
window.showAndWait();
}
public void selectButtonHandler(EventHandler<ActionEvent> handler) {
selectVenueButton.setOnAction(handler);
}
Please consider this Example, you may take the idea and apply it to your program (Explanation in Comments).
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TextArea;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class GetInfoFromPopUpWindow extends Application{
static TextArea textArea = new TextArea(); // to be filled from the pop-up window
#Override
public void start(Stage primaryStage) throws Exception {
// create the main Window and some simple components
// Suppose it contains a TextArea only for simplicity sake
Button open = new Button("Open Popup Window");
//simple container as a root for testing
HBox root = new HBox();
root.getChildren().addAll(textArea, open);
Scene scene = new Scene(root,610,400);
primaryStage.setScene(scene);
primaryStage.setTitle("Main Window");
primaryStage.show();
//Add Action Listener to the open Button
open.setOnAction(e->{ // lambda expression, read more about it in the Documentation
popUpWindow(); // call the method to open a pop-up wondow(see later)
});
}
public static void popUpWindow(){
VBox root = new VBox();
Button fetchInfo = new Button("Finish");
//create a listView and populate it with some info for testing purpose
// suppose the info you get from some database
ListView<String> listView = new ListView<String>();
ObservableList<String> items = FXCollections.observableArrayList (
"First Item", "Second Item", "Third Item", "Fourth Item");
listView.setItems(items);
//to select more than one item
listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
//decoration and size are up to your preference
listView.setPrefWidth(100);
listView.setPrefHeight(100);
root.getChildren().addAll(listView, fetchInfo);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 250,150);
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.setScene(scene);
stage.setTitle("Popup Window");
stage.show();
// Add action listener to fetchInfo Button in this Window
fetchInfo.setOnAction(e->{
// take the info from listView and fill it in the TextArea in the main Window
// just for testing purposes
for (String selectedItem : listView.getSelectionModel().getSelectedItems()){
textArea.appendText(selectedItem + " \n");
}
// when it finishes -> close the window and back to the first one
stage.close();
});
}
public static void main(String[] args) {
launch();
}
}
Test
Main Window Before Clicking Any Button
The Pop-Up Window After Clicking On The Button And Selecting Some Items
After Clicking on Finish Button, It Closes The Pop-Up Window and Then Goes Back To Main Menu With The Information (Selected Items)
I think you can just do:
private Venue venueDisplay(String title, String message) {
// existing code..
window.showAndWait();
return venueList.getSelectionModel().getSelectedItem();
}
and then your selectVenueButton just needs to close the window:
selectVenueButton.setOnAction(e -> window.hide());
you want to perform two operation on click select button
Close popup window :
To achieve this set Event Handler on button as below
selectVenueButton.setOnAction(handler);
In handler you can write logic to close popup window as below :
private EventHandler<ActionEvent> handler = new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
Object source = event.getSource();
if (source instanceof Button) {
Button btn = (Button) source;
Stage stage = (Stage) btn.getScene().getWindow();
stage.close();
}
}
};
After click on button you want selected data on main window :
To achieve this declare venue list on Class Level Scope (Member Variables), so you can access outside a class.
in Dialog class :
ListView<Venue> venueList;
Access data in main Window :
CustomDialog dialog = new CustomDialog(); //popup class
dialog.showDialog;
Venue selectedItem = dialog.venueList.getSelectionModel().getSelectedItems();

JavaFX: MenuBar showing "..."

So: i have here a piece of code that I am using to add a menu to my application.
Stage window;
private void buildWindow() {
window = new Stage();
window.setTitle("FACE");
//MENU
MenuBar mBLaunch = new MenuBar();
Menu fileLaunch = new Menu("File");
MenuItem saveLaunch = new MenuItem("Save");
MenuItem exitLaunch = new MenuItem("Exit");
fileLaunch.getItems().addAll(saveLaunch, new SeparatorMenuItem(), exitLaunch);
mBLaunch.getMenus().add(fileLaunch);
//HouseKeeping
BorderPane bPLaunch = new BorderPane();
bPLaunch.getChildren().addAll(mBLaunch);
Scene launch = new Scene(bPLaunch);
window.setScene(launch);
window.setMinHeight(500);
window.setMinWidth(500);
window.show();
}
However: when I run this code it produces:
So, my question being, how can I make it display something else than ...?
Thanks for the help in advance.
BorderPane places each child at a specific location: center, top, bottom, left, right. If you just add nodes to its list of children, it doesn’t know where to place them.
Replace this:
bPLaunch.getChildren().addAll(mBLaunch);
with this:
bPLaunch.setTop(mBLaunch);

Drop down menu behaving strange

I am trying to make a drop down menu in javaFX. I get the menu to display but they show as "..." instead of the name of the menu. The other problem is when i click the drop down menu it drops the option inside it and then right after pops it up again. The content of the drop down menu shows correctly.
This is where javaFX inits and shows the scene with it's content (Only the drop down menues).
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Memory");
BorderPane root = new BorderPane();
Scene scene = new Scene(root , HEIGHT, LENGHT);
canvas = new Canvas(HEIGHT, LENGHT);
menuBar = new GameMenu();
root.getChildren().add(menuBar.createMenu());
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.show();
}
This is Where I create the menu bar.
public class GameMenu {
MenuBar menuBar;
public GameMenu(){
menuBar = new MenuBar();
Menu menuFile = new Menu("File");
MenuItem optionStartGame = new MenuItem("New game");
MenuItem optionLoadGame = new MenuItem("Load Game");
menuFile.getItems().addAll(optionStartGame, optionLoadGame);
Menu menuEdit = new Menu("Edit");
Menu menuView = new Menu("View");
menuBar.getMenus().addAll(menuFile, menuEdit, menuView);
}
public MenuBar createMenu() {
return menuBar;
}
}
The only problem with your code is that you are using getChildren method on your root BorderPane to populate it.
You can add the MenuBar to the top of the BorderPane like:
root.setTop(menuBar.createMenu());

Categories

Resources