When I set a new Background to a Button, the Background has 1px more to the right, with the color that has it's opacity <1.
Is there a way to remove that 1px, or to fill it (opacity 1)? 1px isn't much, but if you place them next to each other, that 1px turn into a visible white space. The problem I saw it when the button is added into a Pane or Group, when a HBox or VBox is used that 1px gets filled. Unfortunately I need to use Pane or Group. I tried using custom Insets, but the problem still persists.
Code example:
Background background = new Background(new BackgroundFill(Color.GREEN, CornerRadii.EMPTY, Insets.EMPTY));
Font font = new Font("Times New Roman", 16);
Button a = new Button("A");
a.setFont(font);
a.setBackground(background);
a.setLayoutX(10);
a.setLayoutY(10);
pane.getChildren().add(a);
Button aa = new Button("AA");
aa.setFont(font);
aa.setBackground(background);
aa.setLayoutX(10);
aa.setLayoutY(45);
pane.getChildren().add(aa);
Button aaa = new Button("AAA");
aaa.setFont(font);
aaa.setBackground(background);
aaa.setLayoutX(10);
aaa.setLayoutY(80);
pane.getChildren().add(aaa);
Result (the image was zoomed in so that 1px is visible better):
How that 1px looks like (that 1px above the red lines):
How that 1px looks like
How it looks like next to each other (you can see that space isn't white, nor green, but a light green:
How it looks like next to each other
The effect observed is the result of the button width not being integral. This results in those parts not covering a pixel completely being rendered half-transparent.
Pane unfortunately does not consider the snapToPixel property and simply resizes the children to the sizes computed from it's properties.
To fix this, use a type of Pane that does snap coordinates to pixels, e.g. VBox or in this case a AnchorPane without any anchors set.
Pane pane = new AnchorPane();
Related
I have these buttons with different size:
Image
How I can make all buttons with same with size?
It depends on layout where the button is located. For example, if you add all the buttons into GridPane or BorderPane, you have to specify each button width to correspond to certain variable. In the following example I wrap all buttons inside VBox, set VBox preference width and tie up all buttons minimum width to it:
VBox vBox = new VBox();
vBox.setPrefWidth(100);
Button btn1 = new Button("Short");
Button btn2 = new Button("Super Long Button");
btn1.setMinWidth(vBox.getPrefWidth());
btn2.setMinWidth(vBox.getPrefWidth());
vBox.getChildren().addAll(btn1, btn2);
It is also worth to mention that there are two ways to specify the button size. You can do it in the java code or specify it in javafx .fxml file. The above method is an example for java code implementation.
You can also unclamp a button's maximum dimensions so it will grow to fill the available space (unlike most nodes, by default a button node has it's max size clamped to it's preferred size so it doesn't usually grow to fill available space). An Oracle tutorial on Tips for Sizing and Aligning Nodes explains this in more detail.
VBox vBox = new VBox();
Button btn1 = new Button("Short");
Button btn2 = new Button("Super Long Button");
btn1.setMaxWidth(Double.MAX_VALUE);
btn2.setMaxWidth(Double.MAX_VALUE);
vBox.getChildren().addAll(btn1, btn2);
using css you can override the preferred width of all buttons like
.button {
-fx-pref-width: 200px;
}
or create your own style class for certain button groups and add the style to the button like:
css:
.my-special-button {
-fx-pref-height: 28px;
-fx-pref-width: 200px;
}
and then set the style to your button with either
fxml:
styleClass="my-special-button"
or in java
myButton.getStyleClass().add("my-special-button");
I require a tabbed pane with tabs on the left side, the tab text/graphic needs to be horizontal
I did this on Scenebuilder few months back.
However when I add additional tabs via Java code, the tabs is on the left side but the graphic text is vertical unlike the tabs created using Scene builder.
In the attached image first two tabs are created through Scenebuilder and they are in the correct orientation, the third one was dynamically added using Java code.
Tab studentAdmission = new Tab();
studentAdmission.setContent((Parent)new FXMLLoader(getClass().getResource("Customer_View.fxml")).load());
studentAdmission.setGraphic(new Label("Student Admission"));
mainTab.getTabs().add(studentAdmission);
Could some one advise why this tab doesn't rotate as the other one.
Just figured out after posting the question that you need to add a StackPane containing a group containing a label to achieve this.
Tab studentAdmission = new Tab();
studentAdmission.setContent((Parent)new FXMLLoader(getClass().getResource("Customer_View.fxml")).load());
Label l = new Label("Student Admission");
l.setRotate(90);
StackPane stp = new StackPane(new Group(l));
studentAdmission.setGraphic(stp);
mainTab.getTabs().add(studentAdmission);
// Firstly
tabPane.setSide(Side.LEFT);
tabPane.setRotateGraphic(true);
Label l = new Label("Titel Tab1");
l.setRotate(90);
StackPane stp = new StackPane(new Group(l));
stp.setRotate(90);
tab1.setGraphic(stp);
l = new Label("Titel Tab2");
l.setRotate(90);
stp = new StackPane(new Group(l));
stp.setRotate(90);
tab2.setGraphic(stp);
tabPane.setTabMinHeight(100);
tabPane.setTabMaxHeight(100);
I needed to get something similar to this, but with left-aligned titles. I ended up with this solution.
TabPane setup:
TabPane tabPane = new TabPane();
tabPane.setSide(Side.LEFT);
tabPane.setRotateGraphic(true);
tabPane.setTabMinHeight(200); // Determines tab width. I know, its odd.
tabPane.setTabMaxHeight(200);
tabPane.getStyleClass().add("horizontal-tab-pane");
Tab setup:
Tab tab = new Tab(title, content);
tab.setClosable(false);
tab.setGraphic(graphic); // Graphic required. If you don't want one, use an empty label.
Platform.runLater(() -> {
// Get the "tab-container" node. This is what we want to rotate/shift for easy left-alignment.
// You can omit the last "getParent()" with a few tweaks for centered labels
Parent tabContainer = tab.getGraphic().getParent().getParent();
tabContainer.setRotate(90);
// By default the display will originate from the center.
// Applying a negative Y transformation will move it left.
// Should be the 'TabMinHeight/2'
tabContainer.setTranslateY(-100);
});
And the css:
.horizontal-tab-pane *.tab {
/* Determines the tab height */
-fx-pref-width: 60px;
/* Everything else is just aesthetics */
-fx-padding: 20px;
-fx-background-insets: 2 -1 -1 -1;
-fx-border-width: 1 0 1 1;
-fx-border-color: rgb(55, 55, 56) black black black;
}
.horizontal-tab-pane *.tab:selected {
-fx-background-color: rgb(45, 45, 46);
-fx-border-color: rgb(75, 125, 200) black rgb(45, 45, 46) black;
}
I want to create buttons like this in JavaFX (not html).
http://jsfiddle.net/x7dRU/3/
(hover on them to see the effect)
[Stupid Stackoverflow insists on me posting jsfiddle code here which isn't relevant]
<li>Button 1</li>
So with a rounded border and a transparent background. Unfortunately the background/insets technique seems to overwrite the content from outside to in. So if you draw a bright border, then you can't undo the brightness to create a dark&transparent background without hardcoding the colour. I.e. it's not write once, run everywhere, on different coloured panels.
-fx-border-color doesn't seem to support rounding or at least isn't recommended here Set border size . I imagine the rounding of the border doesn't sync with the rounding of the background.
Seems HTML5 has the edge on this one then. Tell me I'm wrong :-) ...although I suspect my question can't be done without specifying the colour for each and every button context.
Browny points.
Note, I realise I've coloured the white border greenish (context sensitive), I'm happy with a border of semi-transparent white as a solution. First prize would be a burn/dodge/etc(background-colour) function ala photoshop.
Plan B.
It doesn't look so bad without rounded edges, so maybe I should just resort to -fx-border-color
Background info
Have a look at the information in the css documentation on "looked-up colors"(scroll down a little, beyond the named color section).
The way these basically work, is that you can define a "looked up color" (i.e. a color-valued variable) and apply it to a node in the scene graph. The value is inherited by any node descended from that node in the scene graph.
Now have a browse through the default style sheet, modena.css. The way this works is that almost everything is defined in terms of a very short list of looked-up colors. The consequence is that you can readily "theme" your applications just by redefining those colors on the root of the scene. Try adding this stylesheet to your favorite JavaFX application:
.root {
-fx-base: #c7dec7;
-fx-accent: #00c996 ;
-fx-default-button: #abedd8 ;
-fx-focus-color: #03d39e;
-fx-faint-focus-color: #03d39e22;
}
As you've observed, -fx-border is not used at all in the default stylesheet; instead borders are implemented by defining "nested" background colors which are essentially rectangular fills laid on top of each other. This is apparently more efficient (quite considerably so, by my understanding). So you are correct that making the inner of two backgrounds transparent will simply reveal the "outer" border color, not the color of the background.
How to achieve what you're looking for
The background of a pane defaults to the looked-up color -fx-background, which in turn defaults to a lighter version of -fx-base. So if you stick to changing the color of the pane containing the buttons by changing -fx-background or -fx-base, then you can make the button appear transparent by setting its background to
-fx-background-color: (some-border-color), -fx-background ;
The default borders for buttons contain three values; -fx-shadow-highlight, -fx-outer-border, and -fx-inner-border. You could override the values for these individually, or just redefine the background color as you need.
An approximation to what you want is in this example: you can mess with the exact values for the thickness of the border (from the second -fx-background-insets value) and the radius of the corners to get it as you need. If you want to get fancy with it, play with combinations of ladders and gradients.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class StyledButtonExample extends Application {
private int currentColorIndex = 0 ;
private final String[] baseColors = new String[] {"#8ec919", "#bfe7ff", "#e6e6fa",
"#ffcfaf", "#fff7f7", "#3f474f"};
private StackPane root ;
#Override
public void start(Stage primaryStage) {
root = new StackPane();
Button button = new Button("Change colors");
button.setOnAction(event -> changeColors());
root.getChildren().add(button);
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("transparent-button.css").toExternalForm());
root.setStyle("-fx-base: "+baseColors[0]+";");
primaryStage.setScene(scene);
primaryStage.show();
}
private void changeColors() {
currentColorIndex = (currentColorIndex + 1) % baseColors.length ;
root.setStyle("-fx-base: "+baseColors[currentColorIndex]+";");
}
public static void main(String[] args) {
launch(args);
}
}
transparent-button.css:
.button {
-fx-background-color: derive(-fx-base, 60%), -fx-background ;
-fx-background-insets: 0, 1px ;
-fx-background-radius: 4px, 0 ;
}
.button:hover {
-fx-background-color: #fff, derive(-fx-background, -5%) ;
}
I have a variety of ToggleButtons that are loaded with an image. The buttons size is determinated by the image size and the button itself is created by JavaCode. A few buttons have icons (the icon is just part of the loaded image) on either the left or right side.
How can I move the text by a certain value to the left or right so I can center the text again but with the offset of the icon? I don't mind passing the width of the icon as parameter, but I cant find anything to move the text for a certain amount.
The button is created from the green image, the right icon is part of it; total width is 300, icon is taking 100; the text should be centered to the leftover 200. For language setting reason the text itself cant be part of the picture.
you can set the style of the button as followed:
// top right bottom left
btn.setStyle("-fx-padding: 5px 5px 5px 5px;");
EDIT:
You can use an HBox:
HBox hbox = new HBox();
// the text of the "button"
Label lbl_txt = new Label("Text");
// the icon of the "button", i am using Labels for icon(with css)
Label lbl_ico = new Label("ico");
hbox.getChildren().addAll(lbl_txt, lbl_ico);
hbox.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
// alternative to Button click
}
});
Everything else is styling with css. ;-)
How can I make an image button with transparent background?
The default background is grey color, I created the button with empty text and setIcon, something like this:
backButton = new Button(); //"Back");
backButton.setIcon(backIcon);
iface.createRoot(AxisLayout.vertical(), ROOT, modeLayer).
setStyles(make(VALIGN.top, HALIGN.right)).
setBounds(0, 0, width, height).
add(backButton);
But could not figure out how to make the button to be transparent from the API / source code.
Any help / hint greatly appreciated.
You want to use Style.BACKGROUND.
If you want all buttons in your entire UI to have a blank background, then configure your root stylesheet like so:
Stylesheet ROOT = SimpleStyles.newSheetBuilder().
add(Button.class, Styles.none().
add(Style.BACKGROUND.is(new NullBackground())).
addSelected(Style.BACKGROUND.is(new NullBackground()))).
create();
Root root = iface.createRoot(AxisLayout.vertical(), ROOT, modeLayer).etc().
If you just want a particular button to have a blank background,
configure it on the button:
Styles blankBg = Styles.none().
add(Style.BACKGROUND.is(new NullBackground()))
addSelected(Style.BACKGROUND.is(new NullBackground());
Button backButton = new Button().addStyles(blankBg).setIcon(backIcon);
Note also that SimpleStyles defines the backgrounds for buttons. If you start with a completely blank stylesheet, you can omit background definitions for your buttons and they will be blank.