I am creating an app that has a main BorderPane with a menubar in the TOP. I want to change the CENTER content when a specific menu option is selected. However, when I do this, the AnchorPane that I load into the CENTER pane is not resizing to fill the CENTER pane. It keeps it's preferred size. I have tried setting it to USE_COMPUTED_SIZE, but that does not resize it to fill the CENTER pane. I also tried to add an HBOX as a wrapper around the AnchorPane (I am fairly new to JavaFX UI design) which also did not work.
<BorderPane id="BorderPane" prefHeight="650.0" prefWidth="980.0"
xmlns="http://javafx.com/javafx/8.0.60"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="fileinventory.ApplicationFrameController">
<top><MenuBar BorderPane.alignment="CENTER">...</MenuBar></top>
<center><AnchorPane BorderPane.alignment="CENTER" /></center>
</BorderPane>
I load the pane to set in the CENTER using the following call from the main class:
public void viewClients() {
ViewClientsController dlg =
new ViewClientsController(this.bundle, this.rootLayout);
}
And the actual controller for the AnchorPane being loaded to the CENTER pane.
public class ViewClientsController {
public ViewClientsController(ResourceBundle bundle, BorderPane layout) {
FXMLLoader fxmlLoader =
new FXMLLoader(getClass().getResource("ViewClients.fxml"));
fxmlLoader.setController(this);
fxmlLoader.setResources(bundle);
try {
layout.setCenter(new AnchorPane((Parent) fxmlLoader.load()));
} catch (Exception ignore) {}
I do not know a lot about JavaFX layouts. I am more of a backend guy, so I am at a bit of a loss here.
I'm new to and trying to learning JavaFX and FXML. Most of my application logic is in the FXMLController class and the base class is pretty much empty except the basic code that was generated by NetBeans IDE such as below
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
I have an element with ID input1 that is of type TextField. How can i access this (or any
other) control by its ID? (keeping in mind that I am in the controller class and not the main class).
I found this question below which is exactly what I'm looking for but that situation is different because they are in the main class where scene is defined. How can i access scene from the controller class and use the code in the question below.
How to find an element with an ID in JavaFX?
This is my first time answering a question on Stack Overflow so please go easy on me.
I am new to JavaFX as well and I too had a problem with this.
This is what if found.
Your TextField in your FXMLDocument.fxml must have a fx:id assigned to it, as in:
<TextField fx:id="input1" layoutX="0.5" layoutX="0.5" />
If you are using the JavaFX SceneBuilder then you can find the fx:id under "Code: TextField" on the right side.
Then in your controller class you can access it but using.
#FXML public TextField input1;
You can use an ArrayList to loop through all of your TextFields.
Here is an example.
#FXML public TextField input1;
#FXML public TextField input2;
#FXML public TextField input3;
#FXML public TextField input4;
#FXML public TextField input5;
#FXML public TextField input6;
#FXML public TextField input7;
#FXML public Button button;
List<TextField> inputs = new ArrayList<TextField>();
public void displayText(ActionEvent event) {
inputs.add(input1);
inputs.add(input2);
inputs.add(input3);
inputs.add(input4);
inputs.add(input5);
inputs.add(input6);
inputs.add(input7);
for (int x = 0; x < 7; x++) {
System.out.println(inputs.get(x).getText());
}
}
There might be a simpler way, but this way works for me.
When user presses a button in my JavaFX2.2 UI, a dark blue halo appears to show it was clicked. During the course of events, my program may want to 'unclick' it to show it is no longer selected.
I expected a button.setSelected(false); I remember Swing used to have this, but there isn't such a call in JavaFx.
This article discusses drop shadows but I want to simply use the same appearance used when a button is clicked which isn't really a drop shadow. setEffect(new DropShadow())
Using setStyle() is ok, but what values to use?
I think for your description, that you actually want a ToggleButton rather than a standard Button.
There is a nice Oracle tutorial on ToggleButtons.
Addressing Items from the Question
dark blue halo appears to show it was clicked
The blue halo is actually a focus ring indicating that a control has focus.
To focus a control, you can invoke the requestFocus method.
During the course of events, my program may want to 'unclick' it to show it is no longer selected.
To remove focus from a control, you can call requestFocus on another control to focus on that control instead.
I expected a button.setSelected(false);
To have a button which can toggle between a selected and unselected state, use a ToggleButton. A ToggleButton has a setSelected method.
setEffect(new DropShadow()) Using setStyle() is ok, but what values to use
css style values for drop shadow effects are define in the JavaFX CSS Reference Guide.
It is visually equivalent to define the drop shadow effect in code via setEffect or via css with setStyle or applying a style class from a stylesheet. Of the three approaches, I would never recommend the setStyle approach, but only the css from stylesheet or the setEffect from code approach.
Related
Note there is an additional related property - armed:
Indicates that the button has been "armed" such that a mouse release will cause the button's action to be invoked. This is subtly different from pressed. Pressed indicates that the mouse has been pressed on a Node and has not yet been released. arm however also takes into account whether the mouse is actually over the button and pressed.
A button in an armed state has a slightly different look than one which is not in an armed state. Most programs never need to interact with the armed state of buttons.
Sample for styling the selected state
The standard way to differentiate a selected ToggleButton from one which is not Selected is to darken it to give it a depth style effect and make it appear further away when it has been pushed. Here is the standard toggle button css for JavaFX 2.2:
.toggle-button:selected {
-fx-background-color:
-fx-shadow-highlight-color,
linear-gradient(to bottom, derive(-fx-color,-90%) 0%, derive(-fx-color,-60%) 100%),
linear-gradient(to bottom, derive(-fx-color,-60%) 0%, derive(-fx-color,-35%) 50%, derive(-fx-color,-30%) 98%, derive(-fx-color,-50%) 100%),
linear-gradient(to right, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0) 10%, rgba(0,0,0,0) 90%, rgba(0,0,0,0.3) 100%);
-fx-background-insets: 0 0 -1 0, 0, 1, 1;
/* TODO: -fx-text-fill should be derived */
-fx-text-fill: -fx-light-text-color;
}
You can override this default behavior by defining your own stylesheet that provides an alternate definition for the selected state. The sample below will ensure that the selected state display is much more subtle than the standard, only darkening the selected state color a small fraction rather than a lot.
Unselected
Selected
Associated css:
/**
* file: colored-toggle.css
* Place in same directory as ColoredToggle.java.
* Have your build system copy this file to your build output directory.
**/
.root {
-fx-background-color: cornsilk;
-fx-padding: 10;
}
.toggle-button {
-fx-color: paleturquoise;
}
.toggle-button:selected {
-fx-background-color:
-fx-shadow-highlight-color,
linear-gradient(to bottom, derive(-fx-color,-22%) 0%, derive(-fx-color,-15%) 100%),
linear-gradient(to bottom, derive(-fx-color,-15%) 0%, derive(-fx-color,-10%) 50%, derive(-fx-color,-8%) 98%, derive(-fx-color,-12%) 100%);
}
.toggle-button:selected:focused {
-fx-background-color:
-fx-focus-color,
linear-gradient(to bottom, derive(-fx-color,-22%) 0%, derive(-fx-color,-15%) 100%),
linear-gradient(to bottom, derive(-fx-color,-15%) 0%, derive(-fx-color,-10%) 50%, derive(-fx-color,-8%) 98%, derive(-fx-color,-12%) 100%);
}
Source file:
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ColoredToggle extends Application {
public static void main(String[] args) { Application.launch(ColoredToggle.class, args); }
#Override public void start(Stage stage) {
ToggleButton visibilityControl = new ToggleButton("Winterfell");
VBox layout = new VBox(10);
layout.setAlignment(Pos.CENTER);
layout.getChildren().setAll(visibilityControl);
layout.getStylesheets().add(getClass().getResource("colored-toggle.css").toExternalForm());
stage.setScene(new Scene(layout));
stage.show();
}
}
From a css stylesheet this command also works. There is no need for a toggle button. Once you press a different button, focus changes to the new one.
.button:focused{
-fx-background-color: gray;
I'm using JavaFx13, I used css to achieve my active button state. Here is my code(Only some part).
Controller:
#FXML
private BorderPane bp;
#FXML
private Button mnu_list;
#FXML
private Button mnu_address;
private Button activeMenu;
// This is my Constructor
public DashboardController() {
this.activeMenu = null;
}
public void initialize() {
mnu_list.setOnMouseClicked(
actionEvent -> this.setActiveMenu(mnu_list, ListController.class)
);
mnu_address.setOnMouseClicked(
actionEvent -> this.setActiveMenu(mnu_address, AddressController.class)
);
}
private void setActiveMenu(Button s, Class c) {
if (c != null) {
// I'm using FXWeaver. Here I'm setting a new fxml to borderpane.
bp.setCenter(this.fxWeaver.loadView(c));
}
if (this.activeMenu != null) {
this.activeMenu.getStyleClass().removeAll("active");
}
s.getStyleClass().add("active");
this.activeMenu = s;
}
CSS:
.btn_menu{
-fx-background-radius: 0px;
-fx-cursor: hand;
-fx-alignment: center-left;
}
.btn_accent_color{
-fx-background-color: #7c4dff;
-fx-text-fill: #FFFFFF;
}
.btn_accent_color.active{
-fx-background-color: #aa3bfe;
-fx-text-fill: #FFFFFF;
}
Note: In .fxml file - I have set all menu button class as btn_menu, btn_accent_color.
Info: Here I'm toggleing (adding and removing) a css-class to a button. (Same as we do in Website using js)
Is there something like a GroupBox or TitledBorder available on JavaFX 2?
Thanks for any hint :-)
Unless you need the custom styling in this answer, I prefer the TitledPane with setCollapsible(false) solution by Andriy Kryvtsun. For use, see a TitledPane tutorial.
No such exact standard control, but it it is easy to create your own. Here is a sample implementation:
/** Places content in a bordered pane with a title. */
class BorderedTitledPane extends StackPane {
BorderedTitledPane(String titleString, Node content) {
Label title = new Label(" " + titleString + " ");
title.getStyleClass().add("bordered-titled-title");
StackPane.setAlignment(title, Pos.TOP_CENTER);
StackPane contentPane = new StackPane();
content.getStyleClass().add("bordered-titled-content");
contentPane.getChildren().add(content);
getStyleClass().add("bordered-titled-border");
getChildren().addAll(title, contentPane);
}
}
And the accompanying css for it:
.label {
-fx-font: 28px Vivaldi;
}
.bordered-titled-title {
-fx-background-color: white;
-fx-translate-y: -16;
}
.bordered-titled-border {
-fx-content-display: top;
-fx-border-insets: 20 15 15 15;
-fx-background-color: white;
-fx-border-color: black;
-fx-border-width: 2;
}
.bordered-titled-content {
-fx-padding: 26 10 10 10;
}
The code is from a example I created in response to an Oracle JavaFX forum thread post "Equivalent to BorderFactory.createTitledBorder".
The output of the example program is as shown below.
I used TitledPane with setCollapsible(false). It looks more consistent than using CSS styles. Here is result
FXML version of jewelsea's answer:
TitledBorder (I renamed the BorderedTitledPane to TitledBorder)
package com.example.controls;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
public class TitledBorder extends StackPane
{
private Label titleLabel = new Label();
private StackPane contentPane = new StackPane();
private Node content;
public void setContent(Node content)
{
content.getStyleClass().add("bordered-titled-content");
contentPane.getChildren().add(content);
}
public Node getContent()
{
return content;
}
public void setTitle(String title)
{
titleLabel.setText(" " + title + " ");
}
public String getTitle()
{
return titleLabel.getText();
}
public TitledBorder()
{
titleLabel.setText("default title");
titleLabel.getStyleClass().add("bordered-titled-title");
StackPane.setAlignment(titleLabel, Pos.TOP_CENTER);
getStyleClass().add("bordered-titled-border");
getChildren().addAll(titleLabel, contentPane);
}
}
FXML usage:
<?import com.example.controls.*?>
<TitledBorder title="title" >
<Label text="label with text" />
</TitledBorder>
Do no forget the Stylesheet!
Use this CSS for a normal font:
.bordered-titled-title {
-fx-background-color: white;
-fx-translate-y: -10; /* play around with this value when changing the title font to get a vertically centered title */
}
.bordered-titled-border {
-fx-content-display: top;
-fx-border-insets: 20 15 15 15;
-fx-background-color: white;
-fx-border-color: black;
-fx-border-width: 2;
}
.bordered-titled-content {
-fx-padding: 26 10 10 10;
}
Using this CSS it now looks like this:
Update:
Problems when title is longer then content:
Any hint to fix this problem?
Here is an FXML document that can be loaded into SceneBuilder which has similar functionality:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane style="-fx-border-insets: 8 0 0 0; -fx-background-color: #FFFFFF; -fx-border-color: black;">
<children>
<Label alignment="TOP_LEFT" layoutX="14.0" style="-fx-padding: 0 5; -fx-background-color: inherit;" text="Title" />
<AnchorPane prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="1.0" AnchorPane.leftAnchor="1.0" AnchorPane.rightAnchor="1.0" AnchorPane.topAnchor="10.0" />
</children>
</AnchorPane>
If you need to make the label text / border size larger you should only have to edit the CSS and the topAnchor of the child AnchorPane and the first argument of -fx-border-insets of the parent AnchorPane.
GroupBox - that is usual Group layout, as far as I see.
TitledBorder - looks like a TitledPane (which is usually a component of Accordion, but could be a separately existing control).
JavaFX-2 analogs looks different from yours (but not significantly), and as usual, you can use different ways of control appearance changing: css, control's skin replacing, etc
Here is a GroupBox implementation based on TitledPane. It provides three methods to set the title, content, and content padding of the GroupBox.
public final class GroupBox extends Parent {
private StackPane _stackPane;
private TitledPane _titledPane;
public GroupBox() {
_stackPane = new StackPane();
_titledPane = new TitledPane();
setContentPadding(new Insets(10));
_titledPane.setCollapsible(false);
_titledPane.setContent(_stackPane);
super.getChildren().add(_titledPane);
}
public GroupBox(String title, Node content) {
this();
setText(title);
setContent(content);
}
public GroupBox(String title, Node content, Insets contentPadding) {
this(title, content);
setContentPadding(contentPadding);
}
public void setText(String value) {
_titledPane.setText(value);
}
public void setContent(Node node) {
_stackPane.getChildren().add(node);
}
public void setContentPadding(Insets value) {
_stackPane.setPadding(value);
}
}
I am creating a simple Weather Application
Here goes the details of my question :-
I have a main Controller (GeoWeatherMain.java). When Appl is run, this class(GeoWeatherMain.class) gets loaded which loads an fxml file.
Below is code for it :-
Parent root = FXMLLoader.load(getClass().getResource("GeoWeatherMainUI.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
Now, GeoWeatherMainUI.fxml has BorderPane object implementation. It consists of a button(on the left pane) which onclick loads another fxml file inside center pane. The skeleton of GeoWeatherMainUI.fxml looks like below:-
<BorderPane fx:id="MainBody" prefHeight="736.0" prefWidth="1140.0" xmlns:fx="http://javafx.com/fxml" fx:controller="geoweather.GeoWeatherUIActionHandlers">
.
.
<Button layoutX="91.0" layoutY="67.0" mnemonicParsing="false" onAction="#getCurrAndForecastWeatherCond" text="Get Weather Details" />
.
.
<BorderPane>
Now GeoWeatherUIActionHandlers.java is another controller which takes care of different button action events.Below is its complete code
public class GeoWeatherUIActionHandlers implements Initializable{
#FXML
BorderPane MainBody;
#FXML
Label LocName;/*LocName is fx id for a label*/
#FXML
private void getCurrAndForecastWeatherCond(ActionEvent event){
try{
Pane centerPane = FXMLLoader.load(getClass().getResource("WeatherDetails.fxml"));
MainBody.setCenter(centerPane);
/*LocName.setText("xyz");*/
}catch (IOException ex){
TextArea excep = new TextArea(ex.toString());
MainBody.setCenter(excep);
}catch(Exception e){
TextArea excep = new TextArea("Inside Exception : \n" + e.toString());
MainBody.setCenter(excep);
}
}
#Override
public void initialize(URL url, ResourceBundle rb){}
}
Now, if I want to update the loaded WeatherDetails.fxml file with new values, how to do that? I tried as in the above commented code.(LocName.setText("xyz")). But, it didn't work (giving NullPointerException).
I went through complete documentation of javafx # docs.oracle.com. No luck. Here also I didn't get the answer. Please guide.
If the LocName is located inside WeatherDetails.fxml then it is excepted behavior that the LocName will be null. Because #FXML Label LocName; is defined in GeoWeatherUIActionHandlers.java which is a controller of GeoWeatherMainUI.fxml. Move LocName from WeatherDetails to GeoWeatherMainUI FXML file and see where you are still getting the error or not.
If your aim is to set the text of the label that is inside WeatherDetails.fxml, then do this work
in the controller of WeatherDetails similar to current GeoWeatherUIActionHandlers, or
in GeoWeatherUIActionHandlers, after loading the WeatherDetails.fxml
get the label by id (not fx:id) from centerPane with ((Label)centerPane.lookup("#myLabel")).setText("xyz"), or
get the controller of WeatherDetails and call getLocName().setText("xyz"). Assuming getter method exists in a controller class.