Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a javafx button with circle shape of 3xp diameter?

I want to make a VERY small round button with no text on it. Here is how I tried.

Button bt = new Button();
bt.setShape(new Circle(1.5));
bt.setMaxSize(3,3);


However,there are two problems:
1.The shape of the button is not perfectly round, but more like an oval.
2. The bt.setMaxSize(1.5,1.5); does not take effect. As i reckon, its diameter is more than 3...
How could I make a smaller rounder Button? Help Appreciated.

like image 568
Yvainovski Avatar asked Nov 10 '14 18:11

Yvainovski


1 Answers

Update: on close review of the resultant button, setting the shape like in José's answer seems to work better on very small buttons than setting the -fx-background-radius as used in this answer, (the resultant button looks a bit more circular when the shape is set). So the solution here is probably best for larger buttons (e.g. 10px or more), while setting the shape is probably best for an extremely small button of 3px (it's a pretty subtle difference though).


3px is a very small button. I'm not sure how you expect people to click on it.

You can make it using CSS.

Here is a round button of 30px size:

30px

And your requested 3px size button:

3px

The rounding is achieved by setting a large value to -fx-background-radius.

Screenshots were taken on a retina mac, so they are twice the size of the original.

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class Rounding extends Application {

    @Override 
    public void start(Stage stage) throws Exception {
        Button roundButton = new Button();

        roundButton.setStyle(
                "-fx-background-radius: 5em; " +
                "-fx-min-width: 3px; " +
                "-fx-min-height: 3px; " +
                "-fx-max-width: 3px; " +
                "-fx-max-height: 3px;"
        );

        StackPane layout = new StackPane(
                roundButton
        );
        layout.setPadding(new Insets(10));
        stage.setScene(new Scene(layout));

        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Note that a button is rendered with layers of backgrounds. The inner layer is the actual button and outside of that there is a focus ring and a slight glow. So together it may actually be slightly larger than 3px. If you want to get 3px exactly, you would need to get rid of the focus background insets. Something like below:

really small no focus

roundButton.setStyle(
        "-fx-background-radius: 5em; " +
        "-fx-min-width: 3px; " +
        "-fx-min-height: 3px; " +
        "-fx-max-width: 3px; " +
        "-fx-max-height: 3px; " +
        "-fx-background-color: -fx-body-color;" +
        "-fx-background-insets: 0px; " +
        "-fx-padding: 0px;"
);

The inline styles are just used here to allow the sample to be small and self-contained. In a real application, you would put the styles in a stylesheet.

The idea of using a -fx-background-radius to round the button came from the implementation of the rounded radio buttons in the default JavaFX modena.css stylesheet. You can find the stylesheet by looking inside the jfxrt.jar file which includes JavaFX code and resources.

By comparison, here is an image of a button created using the Circle shape solution as in José's answer:

circle button

why still need to setup minSize().....

Because JavaFX is trying to provide reasonable defaults. If there was no defaulted minimum size for an empty button, when you resized your scene smaller, some of the buttons would just disappear and the user would not be able to click on them - which would be a very bad user experience. So the minimum size defaults to about 1em, plus some padding (e.g. just larger than a character), even though no text is set on the button. However, it is just a default set by the Java system as it can't really know exactly what your app wants. When the defaults don't work for your situation, override them or provide additional hints such as explicitly setting the minimum size of the control.

What does "5em" stand for?

See the JavaFX 8 css reference guide:

em: the 'font-size' of the relevant font

So 5em means 5 times the font size. Most of the sizes for controls in the default JavaFX stylesheet are specified using em units. That way when you change the font or font size, then the UI scales gracefully to accommodate the larger or smaller font. In this particular case the choice of 5em was pretty arbitrary, I just wanted a large value so that the button would be completely round, otherwise the -fx-background-radius would create a rectangle with rounded corners, rather than a complete circle. By ensuring that the radius dimensions passed to -fx-background-radius are greater than half the size of the control, then the control takes on a round circle appearance.

I know this is somewhat confusing and non-intuitive. I just copied the concept from the default JavaFX stylesheet with the idea that, no matter how confusing it may be, it is probably the best practice for achieving these kinds of effects or it would not be used in the default stylesheet.

Mainly the advantage I can see of such an approach is that no code is required, all styling can be done directly in CSS (so you can change the look without modifying your Java code) and if you want, you can specify co-ordinates in em units, so that the control scales with your font size. So there is some reason behind the apparent madness.

like image 144
jewelsea Avatar answered Sep 18 '22 20:09

jewelsea