JavaFX how to get menubar on the bottom - layout

I'm trying to put the menu bar on the bottom of a windows, here are a example made in paint
but I don't have enough reputation so isn't like this
________________________________________
| _ x|
| |
| |
| |
| |
| |
| |
|file | Edit | view| |
|______________________________________|

To create menu you should use MenuBar component, which you can add using any layout.
For your use case you can use BorderPane and set MenuBar to the bottom
Example code:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
Menu menu1 = new Menu("File");
Menu menu2 = new Menu("Edit");
Menu menu3 = new Menu("View");
MenuBar menuBar = new MenuBar();
menuBar.getMenus().addAll(menu1, menu2, menu3);
root.setBottom(menuBar);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}

Related

JavaFX resizing root stackpane

i'd like to have a StackPane as the root node, it makes overlay effects easy.
But by using a stackpane as the root, inner controls can move out of the window.
In the following example you can see the controls moving out of the window ,
if you shrink the window small enough, e.g. both the menubar and the listview go out to the left. I want to prevent this, how can i do that?
package test;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class App extends Application {
#Override
public void start(Stage stage) throws Exception {
stage.setTitle("controls move out of window :(");
Menu menu = new Menu("Menu");
MenuBar menubar = new MenuBar(menu);
ListView<String> listView = new ListView<>(FXCollections.observableArrayList("Args, it moves away."));
BorderPane borderPane = new BorderPane();
borderPane.setTop(menubar);
borderPane.setLeft(listView);
StackPane rootStackPane = new StackPane(borderPane);
Scene scene = new Scene(rootStackPane);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Update:
setting the alignment for the BorderPane inside the StackPane seems to help:
public void start(Stage stage) throws Exception {
stage.setTitle("controls stay in window :)");
Menu menu = new Menu("Menu");
MenuBar menubar = new MenuBar(menu);
ListView<String> listView = new ListView<>(FXCollections.observableArrayList("it stays!"));
BorderPane borderPane = new BorderPane();
borderPane.setTop(menubar);
borderPane.setLeft(listView);
StackPane rootStackPane = new StackPane(borderPane);
StackPane.setAlignment(borderPane, Pos.TOP_LEFT);
Scene scene = new Scene(rootStackPane);
stage.setScene(scene);
stage.show();
}
Place your stack in a Group and bind the stack's preferred size to the scene's preferred size.
As you can see from the second image, the overlay is not centered on the visible screen, it is centered on the StackPane. The StackPane's minimum size will be the minimum size of it's largest component (even if it overflows the screen), so the overlay is centered on that. To find out minimum sizes of things, you could use either design the UI in SceneBuilder or debug the UI using ScenicView.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class App extends Application {
#Override
public void start(Stage stage) throws Exception {
stage.setTitle("controls stay in window :)");
Menu menu = new Menu("Menu");
MenuBar menubar = new MenuBar();
menubar.getMenus().add(menu);
ListView<String> listView = new ListView<>(FXCollections.observableArrayList("Args, it moves away."));
BorderPane borderPane = new BorderPane();
borderPane.setTop(menubar);
borderPane.setLeft(listView);
borderPane.setStyle("-fx-background-color: palegreen;");
Node overlayContent = new Label("centered");
StackPane stack = new StackPane(borderPane, overlayContent);
Scene scene = new Scene(new Group(stack));
stage.setScene(scene);
stage.show();
stack.prefWidthProperty().bind(scene.widthProperty());
stack.prefHeightProperty().bind(scene.heightProperty());
}
public static void main(String[] args) {
launch(args);
}
}

JavaFX2: MODAL capability to a context menu

Is there a way to add MODAL capability to a context menu?
My code is below:
package snippet;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ColorPicker;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
public class ContextMenuSample extends Application
{
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(Stage stage)
{
stage.setTitle("ContextMenuSample");
Scene scene = new Scene(new Group(), 450, 250);
Label toLabel = new Label("To: ");
TextField notification = new TextField();
final ContextMenu contextMenu = new ContextMenu();
contextMenu.setAutoHide(false);
contextMenu.setOnShowing(new EventHandler<WindowEvent>()
{
public void handle(WindowEvent e)
{
System.out.println("showing the context menu");
}
});
contextMenu.setOnShown(new EventHandler<WindowEvent>()
{
public void handle(WindowEvent e)
{
System.out.println("context menu has been shown");
}
});
MenuItem closeItem = new MenuItem("Close");
closeItem.setOnAction(new EventHandler<ActionEvent>()
{
public void handle(ActionEvent e)
{
contextMenu.hide();
}
});
MenuItem colorItem = new MenuItem("Choose", new ColorPicker());
colorItem.setOnAction(new EventHandler<ActionEvent>()
{
public void handle(ActionEvent e)
{
System.out.println("Preferences");
}
});
GridPane contextGridPane = new GridPane();
Pane pane = new Pane();
pane.getChildren().add(contextGridPane);
contextMenu.getItems().addAll(colorItem, deleteItem// , subsystem1,
// radioItem
);
toLabel.setContextMenu(contextMenu);
GridPane grid = new GridPane();
grid.setVgap(4);
grid.setHgap(10);
grid.setPadding(new Insets(5, 5, 5, 5));
grid.add(toLabel, 0, 0);
grid.add(notification, 1, 0);
grid.add(new ColorPicker(), 2, 0);
Group root = (Group) scene.getRoot();
root.getChildren().add(grid);
stage.setScene(scene);
stage.show();
}
}
When the user clicks on the label "To", a context menu appears. I wish to have modal capability for this context menu such that the user is not able to do anything else on the application unless some operation is performed on the context menu. Also, when the context menu is active, the user should not be able to click anywhere else on the application.
Regards,
The easiest solution would be to call another Stage and set its modality with initModality before you show the stage. You probably want to use Modality.APPLICATION_MODEL as far as I understood you.
Here is a small example derived from yours (btw your code was not even runnable, it had errors)
public class ContextMenuSample extends Application
{
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(final Stage stageOne)
{
final Stage stageTwo = new Stage();
stageTwo.initModality(Modality.APPLICATION_MODAL);
final Pane layoutOne = new HBox(10);
Pane layoutTwo = new HBox(10);
Label labelOne = new Label("click");
Label labelTwo = new Label("other click");
labelOne.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
stageTwo.show();
}
});
labelTwo.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
stageTwo.close();
}
});
Scene sceneOne = new Scene(layoutOne);
Scene sceneTwo = new Scene(layoutTwo);
layoutOne.getChildren().add(labelOne);
layoutTwo.getChildren().add(labelTwo);
stageOne.setScene(sceneOne);
stageTwo.setScene(sceneTwo);
stageOne.show();
}
}

How to switch work spaces in JavaFX

I want to create several work spaces which can be switched with toggle buttons. I created this example
package menunavigation;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class MenuNavigation extends Application
{
#Override
public void start(Stage primaryStage)
{
final VBox vbox = new VBox();
MenuBar menuBar = new MenuBar();
// --- Menu File
Menu menuFile = new Menu("File");
// --- Menu Edit
Menu menuEdit = new Menu("Edit");
// --- Menu View
Menu menuView = new Menu("View");
menuBar.getMenus().addAll(menuFile, menuEdit, menuView);
// buttons
String pillButtonCss = MenuNavigation.class.getResource("PillButton.css").toExternalForm();
// create 3 toggle buttons and a toogle group for them
ToggleButton tb1 = new ToggleButton("Left Button");
tb1.setId("pill-left");
ToggleButton tb2 = new ToggleButton("Center Button");
tb2.setId("pill-center");
ToggleButton tb3 = new ToggleButton("Right Button");
tb3.setId("pill-right");
final ToggleGroup group = new ToggleGroup();
tb1.setToggleGroup(group);
tb2.setToggleGroup(group);
tb3.setToggleGroup(group);
// select the first button to start with
group.selectToggle(tb1);
final Rectangle rect1 = new Rectangle(300, 300);
rect1.setFill(Color.ALICEBLUE);
final Rectangle rect2 = new Rectangle(300, 300);
rect2.setFill(Color.AQUA);
final Rectangle rect3 = new Rectangle(300, 300);
rect3.setFill(Color.AZURE);
tb1.setUserData(rect1);
tb2.setUserData(rect2);
tb3.setUserData(rect3);
group.selectedToggleProperty().addListener(new ChangeListener<Toggle>()
{
#Override
public void changed(ObservableValue<? extends Toggle> ov, Toggle toggle, Toggle new_toggle)
{
if (new_toggle == null)
{
//rect.setFill(Color.WHITE);
}
else
{
//rect.setFill((Color) group.getSelectedToggle().getUserData());
vbox.getChildren().setAll((Node) group.getSelectedToggle().getUserData());
}
}
});
HBox hBox = new HBox();
hBox.getChildren().addAll(tb1, tb2, tb3);
hBox.setPadding(new Insets(10, 10, 10, 10));
hBox.getStylesheets().add(pillButtonCss);
// end buttons
vbox.getChildren().addAll(menuBar, hBox, new Text("Test Space"));
StackPane root = new StackPane();
root.getChildren().add(vbox);
Scene scene = new Scene(root, 800, 850);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
This is the visual result:
When I press the second button I get this:
I want to use the toggle buttons to create different work spaces on which I want to place one main BorderPane or GridPane in which I want to insert many other components. Can you help me to get this result.
Is there a reason to not use a TabPane?
Edit:
Replace:
vbox.getChildren().setAll((Node) group.getSelectedToggle().getUserData());
With:
vbox.getChildren().set(2,(Node) group.getSelectedToggle().getUserData());
to show the rectangle instead of the Text.
This replaces the node with index 2 (the text) of your vbox with the node from ToggleButtons UserData (instead of replacing all elements in your current code).

JavaFX MenuItem.setAccelerator( ) not working

I want my JavaFX program to be able to dynamically change the accelerator for menu items. However, I can't seem to get it to work in JavaFX 2.2. In the code below, the first menu item has an accelerator "Ctrl+M" and it works fine. "Ctrl+M" is printed every time the menu item is selected using a mouse or with the keyboard accelerator Ctrl+M. The second menu item attempts to change the first men item's accelerator to "Ctrl+L". After choosing the second menu item, I can click on the first menu item again and it shows that its new accelerator is "Ctrl+L", but I cannot use the keyboard accelerator Ctrl+L to activate the first menu item. Instead, I still need to use Ctrl+M to activate the first menu item. Any suggestions on what is going wrong here?
/*
* from code at <http://java-buddy.blogspot.com/2012/02/javafx-20-set-accelerator.html>
*/
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.KeyCombination;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class AcceleratorExample extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Accelerator example");
Group root = new Group();
Scene scene = new Scene(root, 400, 300, Color.WHITE);
MenuBar menuBar = new MenuBar();
Menu FileMenu = new Menu("File");
final MenuItem item1 = new MenuItem("Select me");
item1.setAccelerator(KeyCombination.keyCombination("Ctrl+M"));
item1.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
System.out.println(item1.getAccelerator());
}
});
final MenuItem item2 = new MenuItem("New accel");
item2.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
item1.setAccelerator(KeyCombination.keyCombination("Ctrl+L"));
}
});
FileMenu.getItems().add(item1);
FileMenu.getItems().add(item2);
menuBar.getMenus().add(FileMenu);
menuBar.prefWidthProperty().bind(primaryStage.widthProperty());
root.getChildren().add(menuBar);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Dynamically changing the accelerator has iffy behaviour at present, but this is a bug which has been fixed for 8u20:
https://javafx-jira.kenai.com/browse/RT-35182

Background is not changed when I switch buttons

I want to implement this example: http://docs.oracle.com/javafx/2/ui_controls/toggle-button.htm#
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class test extends Application
{
private void init(Stage primaryStage)
{
Group root = new Group();
primaryStage.setScene(new Scene(root));
String pillButtonCss = DX57DC.class.getResource("PillButton.css").toExternalForm();
// create 3 toggle buttons and a toogle group for them
ToggleButton tb1 = new ToggleButton("Left Button");
tb1.setId("pill-left");
ToggleButton tb2 = new ToggleButton("Center Button");
tb2.setId("pill-center");
ToggleButton tb3 = new ToggleButton("Right Button");
tb3.setId("pill-right");
final ToggleGroup group = new ToggleGroup();
tb1.setToggleGroup(group);
tb2.setToggleGroup(group);
tb3.setToggleGroup(group);
// select the first button to start with
group.selectToggle(tb1);
//////////////////////////////////////////
tb1.setUserData(Color.LIGHTGREEN);
tb2.setUserData(Color.LIGHTBLUE);
tb3.setUserData(Color.SALMON);
final Rectangle rect = new Rectangle(300, 300);
group.selectedToggleProperty().addListener(new ChangeListener<Toggle>()
{
#Override
public void changed(ObservableValue<? extends Toggle> ov,
Toggle toggle, Toggle new_toggle)
{
if (new_toggle == null)
{
rect.setFill(Color.WHITE);
}
else
{
rect.setFill(
(Color) group.getSelectedToggle().getUserData());
}
}
});
///////////////////////////////////////////
rect.setArcHeight(10);
rect.setArcWidth(10);
HBox hBox = new HBox();
hBox.getChildren().addAll(tb1, tb2, tb3);
hBox.setPadding(new Insets(20, 20, 260, 20));
hBox.getStylesheets().add(pillButtonCss);
VBox vbox = new VBox();
vbox.getChildren().add(hBox);
vbox.getChildren().add(rect);
root.getChildren().add(vbox);
}
#Override
public void start(Stage primaryStage) throws Exception
{
init(primaryStage);
primaryStage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
But for some reason I can see the buttons but the rectangle is not displayed when I try to switch the buttons. Can you help me to find where is my mistake? And also how I can implement this example with several rectangles holding different content?
You have to add rect to your scene graph :
root.getChildren().addAll(hBox, rect);
Also, think of using an appropriate layout for your root, BorderPane instead of Group for example.

Resources