JavaFX TabPane width and Button width don´t match - button

While I was trying to use the TabPane container in JavaFX I noticed, that if I give the Tabs in the TabPane a specific width and another element e.g. a Button the exact same width, they show up on the screen with different sizes.
Here is an example: As you can see in this image, the Button is smaller than the width of the tap
Here is the Code I for this specific image:
package stackOverflow;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TabPane.TabClosingPolicy;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class TabPaneMystery extends Application {
public static void main(String[] args){
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
StackPane stackPane = new StackPane();
Scene scene = new Scene(stackPane, 600, 400);
stage.setScene(scene);
stage.show();
TabPane tabPane = new TabPane();
stackPane.getChildren().add(tabPane);
Tab tab1 = new Tab();
tabPane.setTabMaxWidth(160); //The width of the tab is '160'
tabPane.setTabMinWidth(160);
tabPane.setTabClosingPolicy(TabClosingPolicy.UNAVAILABLE);
tab1.setText("Tab");
tabPane.getTabs().add(tab1);
Button b = new Button();
b.setText("Button");
b.setPrefWidth(160); //The width of the button is '160'
b.setTranslateX(6);
tab1.setContent(b);
}
}
in Line 33 and 34 (where the first comment is) I set the width of the tapPane to be 160 and in Line 42 (where the second comment is) I set the exact same width
This results in the shown image.
My question is:
Have I made an obvious mistake or is it some kind of bug or does the compiler interpret the width for every node somewhat different?

I suspect you're seeing some padding in the Tab. The actual width of the Tab comes out to 170. You can confirm this by changing the width of the Tab to 150; it will then be the exact same size as the Button:
You could also use CSS to remove the padding:
tab1.setStyle("-fx-padding: 0");
Although, as you can see below, it isn't an exact match and there may be other CSS properties to look into. Hope this gets you closer to your goal, though:

Related

when i add a button the scene color disappear (javaFx) [duplicate]

Why MenuBar changes the background color of the scene in this code sample? It should be blue but it is white.
package application;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.MenuBar;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
Scene scene = new Scene(root,400,400);
scene.setFill(Color.rgb(0, 0, 255));
primaryStage.setScene(scene);
primaryStage.show();
MenuBar menuBar = new MenuBar();
}
public static void main(String[] args) {
launch(args);
}
}
The white background you are seeing is the background of the BorderPane. This background color is set when the default stylesheet is loaded.
The reason that you only see this when the MenuBar is created is that CSS is only applied (unless you force it) when the first control is created. This is by design, to prevent the overhead of loading stylesheets and applying CSS for applications that don't need them (e.g. for games or simulations that manage all their own graphics). Since all controls are styled by CSS, just instantiating a control forces CSS to be applied.
The fix is to make the background of the BorderPane transparent.
Either
root.setStyle("-fx-background-color: transparent;");
or
root.setBackground(Background.EMPTY);
Of course, since you have to set the background of the root pane, you may as well set that to blue instead of setting the fill of the Scene:
BorderPane root = new BorderPane();
root.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
Scene scene = new Scene(root,400,400);
Or, you can use an external style sheet:
.root {
-fx-background-color: blue ;
}
Also see this related post and this OTN discussion.

How do I fit a JavaFX Pane to the size of its contents?

In JavaFX, I see lots of examples of how to make a child component extend its size to fit the parent pane. But I can't see how to shrink the parent pane to fit the size of its child contents.
In the following example, I create a Stage with a Scene of size 500x500 pixels. Inside that Scene is a VBox that has one child, a single Label.
I'd like the VBox Pane to be the size of the Label, not the size of the whole Stage. (In a more complex application, I'm making the VBox a draggable Pane, so I want it to be just big enough to fit its contents).
How can I do that?
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Sample extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
VBox vbox = new VBox();
vbox.setStyle("-fx-background-color: #efecc2");
vbox.setPrefSize(100, 100);
Label label = new Label("Label");
label.setStyle("-fx-background-color: lightcyan");
vbox.getChildren().add(label);
Scene scene = new Scene(vbox, 500, 300);
primaryStage.setScene(scene);
primaryStage.show();
}
}
As you can see in the picture below, the label (with a blue background) is small, but the VBox (with a yellow background) fills the whole window. It doesn't seem to matter that I set the preferred size of the VBox to 100,100: it still fills up the whole 500 x 300 pixel Scene.
How can I tell the VBox to be only as big as the Label that is inside of it? (Or, when I add, say, 3 things inside it, to be as big as those?)
First problem here is a scene's root object. It will always be the same size as the scene. So you need to add the parent Pane as root element and then add VBox into it.
Second problem is a type of Pane. Some elements affect the size of children(BorderPane, StackPane), some not (Pane, AnchorPane). So you need to choose the right parent.
Here is a simple example:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Sample extends Application {
#Override
public void start(Stage primaryStage) {
Label label = new Label("Label");
label.setStyle("-fx-background-color: lightcyan");
VBox vBox = new VBox();
vBox.setStyle("-fx-background-color: #efecc2");
vBox.getChildren().add(label);
AnchorPane root = new AnchorPane();
root.getChildren().add(vBox);
Scene scene = new Scene(root, 500, 300);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Can I only target bottom border at JavaFX Styling?

can I somehow only style the bottom border of an textfield?
I already tried
textfield.setStyle("-fx-border-bottom-color: #FF0000");
but it hasn't worked.
Is there an possibility to color the bottom border??
Greetings
MatsG23
Here is a quick and dirty example of how that can be done.
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TextFieldStyleTest extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = new BorderPane();
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
root.setCenter(vBox);
HBox hBox = new HBox();
hBox.setAlignment(Pos.CENTER);
vBox.getChildren().add(hBox);
TextField textField = new TextField("Hello World");
textField.setAlignment(Pos.BASELINE_CENTER);
hBox.getChildren().add(textField);
textField.setStyle("-fx-border-color: red; -fx-border-width: 0 0 10 0;");
Scene scene = new Scene(root, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
class TextFieldStyleTestLauncher {public static void main(String[] args) {TextFieldStyleTest.main(args);}}
Yes, it is possible to give each side a different color. From the JavaFX CSS Reference Guide, for Region:
CSS Property: -fx-border-color
Values: <paint> | <paint> <paint> <paint> <paint> [ , [<paint> | <paint> <paint> <paint> <paint>] ]*
Default: null
Comments: A series of paint values or sets of four paint values, separated by commas. For each item in the series, if a single paint value is specified, then that paint is used as the border for all sides of the region; and if a set of four paints is specified, they are used for the top, right, bottom, and left borders of the region, in that order. If the border is not rectangular, only the first paint value in the set is used.
Note: The above is actually from one row of a table, but Stack Overflow doesn't give a way of formatting things in a table.
Meaning you can target the bottom border only by using:
.text-field {
-fx-border-color: transparent transparent red transparent;
}
The -fx-border-width CSS property (and really all the CSS properties dealing with the Region#background and Region#border properties) behaves the same way. This means you can accomplish the same thing by setting the width of every side but the bottom to zero, just like in mipa's answer.
Here's an exaple using inline CSS (i.e. setStyle):
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class App extends Application {
#Override
public void start(Stage primaryStage) {
TextField field = new TextField("Hello, World!");
field.setStyle("-fx-border-color: transparent transparent red transparent;");
field.setMaxWidth(Region.USE_PREF_SIZE);
primaryStage.setScene(new Scene(new StackPane(field), 300, 150));
primaryStage.show();
// Remove blue outline from when TextField is focused. This
// makes it easier to see the red border.
primaryStage.getScene().getRoot().requestFocus();
}
}
Which gives the following output:
Note that most of the "borders" added by modena.css (the default user-agent style sheet in JavaFX 8+) are not actually borders. Instead, they're multiple backgrounds with different insets.

how to fix javafx - tableview size to current window size

I'm totally new to standalone applications. Please any one help me on this.
I have TableView with 6 columns which is half showing in the window as shown below.
I want to fix its current window size, even when the window is expanded, the tableview should auto resize. Is there any way to do this?
This Is The Code Snippet
GridPane tableGrid= new GridPane();
tableGrid.setVgap(10);
tableGrid.setHgap(10);
Label schoolnameL= new Label(SCHOOL+school_id);
schoolnameL.setId("schoolLabel");
Button exportDataSheetBtn= new Button("Export In File");
tableView.setMaxWidth(Region.USE_PREF_SIZE);
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
tableGrid.getChildren().addAll(schoolnameL,exportDataSheetBtn,tableView);
This can be done by binding the preferred height and width to the height and width of the primary stage. Here's an MCVE:
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
public class MCVE extends Application {
#Override
public void start(Stage stage) {
TableView<ObservableList<String>> table = new TableView<ObservableList<String>>();
// We bind the prefHeight- and prefWidthProperty to the height and width of the stage.
table.prefHeightProperty().bind(stage.heightProperty());
table.prefWidthProperty().bind(stage.widthProperty());
stage.setScene(new Scene(table, 400, 400));
stage.show();
}
public static void main(String[] args) {
launch();
}
}
Create Tabel inside GridPane and Use GridePane inside AnchorPane.Click on GridPane(capture1).
Click on Ancho Pane Constraint inside the GridPane Layout (captur2).
In table view Layout select Hgrow and Vgrow as 'Always'(capture3)
VBox.setVgrow(tableView, Priority.ALWAYS);
OR for your parent layouts:
VBox.setVgrow({{PARENT}}, Priority.ALWAYS);
It fixed for me:
You could use a ScrollPane as the root of the scene and put everything else inside it. Then set the property setFitToWidth and setFitToHeight to true and all the content inside the ScrollPane will be stretched to fit the ScrollPane size and the ScrollPane will fit the Scene since its a Layout Pane. It will also show ScrollBars if the user resizes the window to be smaller than the contents minWidth, so the content doesnt get cut off!
#Override
public void start(Stage stage) {
TableView<ObservableList<String>> table = new TableView<ObservableList<String>>();
table.setMinWidth(400);
ScrollPane sp = new ScrollPane(table);
sp.setFitToHeight(true);
sp.setFitToWidth(true);
stage.setScene(new Scene(table, 800, 600));
stage.show();
}
public static void main(String[] args) {
launch();
}
I copied parts of the MCVE From Jonathan's answer, hope you dont mind Jonathan :)
For more general tips for making resizable GUIs check this post!

JavaFX TabPane fails to render when inside ScrollPane and zoomed Group

I need a bunch of widgets, including a TabPane, inside a scrollable and zoomable view, basically this:
ScrollPane[ Group[ widgets .. including TabPane ] ]
The ScrollPane is obviously needed for scrolling, and the Group holds all the widgets and supports zooming.
The initial problem with that approach is that the ScrollPane shows scroll bars based on the original size of the widgets, not based on the actual size.
In the screenshot, note how scrollbars are shown even though the tab pane is much smaller than the viewport, so no scrollbars are needed.
The web site https://pixelduke.wordpress.com/2012/09/16/zooming-inside-a-scrollpane explains how to solve that by adding another nested Group:
ScrollPane[ Group[ Group[ widgets .. including TabPane ] ] ]
The inner Group, as before, holds all the widgets and supports zooming.
The outer Group automatically gets the layout bounds of the zoomed
widgets in the inner group, allowing the ScrollPane to correctly configure the scroll bars.
.. but now the TabPane will fail to properly draw itself.
All you see is the red background of the TabPane:
The complete tab pane only shows up once it's somehow forced to refresh.
The example code toggles the 'side' property of the tab pane when you press 'SPACE'.
Now I have it all: Tab Pane draws OK, inner group can be zoomed, scroll bars appear as soon as the zoomed content no longer fits the viewport. But having to force the Tab Pane refresh is certainly a hack.
Is there a fault in my scene graph?
Is this a bug in the TabPane rendering?
The problem certainly seems limited to the TabPane. When I add other groups, rectangles, buttons, text nodes to the 'widgets' in the inner group, they all render fine. Only the TabPane refuses to show its tabs.
Tried this with both JDK 1.8.0_51 and 1.8.0_73, also tried on Windows, Linux and Mac OS X.
import javafx.application.Application;
import javafx.geometry.Side;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class TabDemo extends Application
{
#Override
public void start(final Stage stage)
{
// TabPane with some tabs
final TabPane tabs = new TabPane();
tabs.setStyle("-fx-background-color: red;");
for (int i=0; i<3; ++i)
{
final Rectangle rect = new Rectangle(i*100, 100, 10+i*100, 20+i*80);
rect.setFill(Color.BLUE);
final Pane content = new Pane(rect);
final Tab tab = new Tab("Tab " + (i+1), content);
tab.setClosable(false);
tabs.getTabs().add(tab);
}
tabs.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
tabs.setPrefSize(400, 300);
final Group widgets = new Group(tabs);
widgets.setScaleX(0.5);
widgets.setScaleY(0.5);
final Group scroll_content = new Group(widgets);
final ScrollPane scroll = new ScrollPane(scroll_content);
final Scene scene = new Scene(scroll);
stage.setTitle("Tab Demo");
stage.setScene(scene);
stage.show();
// Unfortunately, the setup of ScrollPane -> Group -> Group -> TabPane
// breaks the rendering of the TabPane.
// While the red background shows the area occupied by TabPane,
// the actual Tabs are missing..
System.out.println("See anything?");
scene.addEventFilter(KeyEvent.KEY_PRESSED, (KeyEvent event) ->
{
if (event.getCode() == KeyCode.SPACE)
{ // .. until 'side' or 'tabMinWidth' or .. are twiddled to force a refresh
tabs.setSide(Side.BOTTOM);
tabs.setSide(Side.TOP);
System.out.println("See it now?");
}
});
}
public static void main(String[] args)
{
launch(args);
}
}

Resources