I am creating a board game in JavaFX using GridPane.
There are 7 different animations which could be placed in each grid (cell) of the grid.
Initially the grid looks like this
I tested adding a simple circle to it before programming my animation insertions. And it looks like this
The nodes added are SubScenes which include TimeLine animation. Each cell size is 40x40 and the SubScene size is also 40x40.
The subscenes when added, get on top of the gridpane border lines and it doesn't look good.
What can I do so that the nodes are added below the grid lines? i.e. the gridlines are on top of the nodes.
If it is not possible with GridPane, is there anything else I can use?
class which i execute for the game
class Game {
static GridPane grid;
public void start(final Stage stage) throws Exception {
int rows = 5;
int columns = 5;
stage.setTitle("Enjoy your game");
grid = new GridPane();
for(int i = 0; i < columns; i++) {
ColumnConstraints column = new ColumnConstraints(40);
grid.getColumnConstraints().add(column);
}
for(int i = 0; i < rows; i++) {
RowConstraints row = new RowConstraints(40);
grid.getRowConstraints().add(row);
}
grid.setOnMouseReleased(new EventHandler<MouseEvent> () {
public void handle(MouseEvent me) {
grid.add(Anims.getAnim(1), (int)((me.getSceneX() - (me.getSceneX() % 40)) / 40), (int)((me.getSceneY() - (me.getSceneY() % 40)) / 40)); //here the getAnim argument could be between 1-7
}
});
grid.setStyle("-fx-background-color: white; -fx-grid-lines-visible: true");
Scene scene = new Scene(grid, (columns * 40) + 100, (rows * 40) + 100, Color.WHITE);
stage.setScene(scene);
stage.show();
}
public static void main(final String[] arguments) {
Application.launch(arguments);
}
}
class which contains animations, here I am just creating a circle
public class Anims {
public static SubScene getAnim(final int number) throws Exception {
Circle circle = new Circle(20, 20f, 7);
circle.setFill(Color.RED);
Group group = new Group();
group.getChildren().add(circle);
SubScene scene = new SubScene(group, 40, 40);
scene.setFill(Color.WHITE);
return scene;
}
}
Don't use setGridLinesVisible(true): the documentation explicitly states this is for debug only.
Instead, place a pane in all the grid cells (even the empty ones), and style the pane so you see the borders. (This gives you the opportunity to control the borders very carefully, so you can avoid double borders, etc.) Then add the content to each pane. You can also register the mouse listeners with the pane, which means you don't have to do the ugly math to figure out which cell was clicked.
The recommended way to apply a border to any region is to use CSS and a "nested background" approach. In this approach, you draw two (or more) background fills on the region, with different insets, giving the appearance of a border. So for example:
-fx-background-fill: black, white ;
-fx-background-insets: 0, 1 ;
will first draw a black background with no insets, and then over that will draw a white background with insets of 1 pixel on all sides, giving the appearance of a black border of width 1 pixel. While this may seem counter-intuitive, the performance of this is (allegedly) better than specifying border directly. You can also specify a sequence of four values for the insets for each fill, which are interpreted as the insets on the top, right, bottom, and left, respectively. So
-fx-background-fill: black, white ;
-fx-background-insets: 0, 0 1 1 0 ;
has the effect of a black border on the right and bottom, etc.
I'm also not sure SubScene is what you really want, unless you are intending attaching different cameras to each cell. If you really need a subscene, make the fill transparent to avoid drawing over the edges of the cell. You could just add the Group directly to each cell (you could probably just add the circle, depending on exactly what you need...).
Something like:
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.RowConstraints;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class Game2 extends Application{
#Override
public void start(final Stage stage) throws Exception {
int rows = 5;
int columns = 5;
stage.setTitle("Enjoy your game");
GridPane grid = new GridPane();
grid.getStyleClass().add("game-grid");
for(int i = 0; i < columns; i++) {
ColumnConstraints column = new ColumnConstraints(40);
grid.getColumnConstraints().add(column);
}
for(int i = 0; i < rows; i++) {
RowConstraints row = new RowConstraints(40);
grid.getRowConstraints().add(row);
}
for (int i = 0; i < columns; i++) {
for (int j = 0; j < rows; j++) {
Pane pane = new Pane();
pane.setOnMouseReleased(e -> {
pane.getChildren().add(Anims.getAtoms(1));
});
pane.getStyleClass().add("game-grid-cell");
if (i == 0) {
pane.getStyleClass().add("first-column");
}
if (j == 0) {
pane.getStyleClass().add("first-row");
}
grid.add(pane, i, j);
}
}
Scene scene = new Scene(grid, (columns * 40) + 100, (rows * 40) + 100, Color.WHITE);
scene.getStylesheets().add("game.css");
stage.setScene(scene);
stage.show();
}
public static class Anims {
public static Node getAtoms(final int number) {
Circle circle = new Circle(20, 20f, 7);
circle.setFill(Color.RED);
Group group = new Group();
group.getChildren().add(circle);
// SubScene scene = new SubScene(group, 40, 40);
// scene.setFill(Color.TRANSPARENT);
return group;
}
}
public static void main(final String[] arguments) {
Application.launch(arguments);
}
}
and the css:
.game-grid {
-fx-background-color: white ;
-fx-padding: 10 ;
}
.game-grid-cell {
-fx-background-color: black, white ;
-fx-background-insets: 0, 0 1 1 0 ;
}
.game-grid-cell.first-row {
-fx-background-insets: 0, 1 1 1 0 ;
}
.game-grid-cell.first-column {
-fx-background-insets: 0, 0 1 1 1 ;
}
.game-grid-cell.first-row.first-column {
-fx-background-insets: 0, 1 ;
}
Simply add an H and V gap of one pixel width and let the grid pane's background color "shine" through:
.my-grid-pane {
-fx-background-color: lightgray;
-fx-vgap: 1;
-fx-hgap: 1;
-fx-padding: 1;
}
If the grid pane's background color spreads from outside more than one pixel (will happen if its parent is larger than itself), just wrap the grid in a Group!
I apologize for the response instead of the comment, not enough reputation.
Strangely, but #James_D 's response didn't help me; when the window was resized, the cell borders randomly changed their width, overlapping each other.
This answer helped solve the problem, so by slightly changing the code given by #James_D (only the .css file), we get:
.classes-grid {
-fx-background-color: white ;
-fx-padding: 10 ;
}
.classes-grid-cell {
-fx-border-color: dimgray;
-fx-border-width: 0 1 1 0;
-fx-background-color: transparent;
}
.classes-grid-cell.first-row {
-fx-border-width: 1 1 1 0 ;
}
.classes-grid-cell.first-column {
-fx-border-width: 0 1 1 1 ;
}
.classes-grid-cell.first-row.first-column {
-fx-border-width: 1 ;
}
Same idea with Mordechai's answer. But if you want to set these things by JavaFX code, not CSS stylesheet. Then you can do sth like this:
Set up the Hgap and Vgap: gridpane.setHgap(1) and gridpane.setVgap(1)
Set up the background color: gridpane.setBackground(new Background(new BackgroundFill(Color.rgb(0,0,0), new CornerRadii(2.5), new Insets(-1.0)))) (CornerRadii and Insets value depends on your choice, background color determined by rgb value)
Related
I try to align the vertical scroll position of two javafx.scene.control.ScrollPanes via
sp1.vvalueProperty().bindBidirectional(sp2.vvalueProperty());
The problem is that one of these ScrollPanes may have a horizontal scroll bar. So the more I scroll down the ScrollPanes, the more they get misaligned (see screenshot). How can I handle this?
It's impossible to do this with 2 ScrollPanes and contents of equal height unless you display the scrollbar in both ScrollPanes:
Consider the case where the content fits the viewport of the left ScrollPane exactly. The viewPort of the right ScrollPane can be scrolled by the ScrollBar height. Modifying the left ScrollPane is not possible.
Since the expected result seems to be some kind of scale, you could simply use a Pane with a child you apply transformY to and a clip. The formula to calculate the pixel to be placed at the top, use
top = vvalue * (contentHeight - viewportHeight)
Example
private static Label createLabel(int num, boolean mark) {
Label label = new Label(Integer.toString(num));
label.setPrefSize(50, 50);
label.setMaxSize(Double.MAX_VALUE, Region.USE_PREF_SIZE);
label.setStyle(mark ? "-fx-background-color: #FFFFFF" : "-fx-background-color: #BBBBBB;");
return label;
}
#Override
public void start(Stage primaryStage) throws Exception {
VBox scale = new VBox();
scale.setMinHeight(Region.USE_PREF_SIZE);
GridPane content = new GridPane();
for (int i = 0; i < 40; i++) {
boolean b = ((i % 2) == 0);
scale.getChildren().add(createLabel(i, !b));
for (int j = 0; j < 10; j++) {
content.add(createLabel(i * 10 + j, b), j, i);
}
}
AnchorPane scaleContainer = new AnchorPane(scale);
scaleContainer.setMinWidth(30);
scaleContainer.setMinHeight(0);
AnchorPane.setLeftAnchor(scale, 0d);
AnchorPane.setRightAnchor(scale, 0d);
Rectangle clip = new Rectangle();
scaleContainer.setClip(clip);
clip.widthProperty().bind(scaleContainer.widthProperty());
clip.heightProperty().bind(scaleContainer.heightProperty());
ScrollPane scroll = new ScrollPane(content);
scale.translateYProperty().bind(Bindings.createDoubleBinding(() -> {
double contentHeight = content.getHeight();
double viewportHeight = scroll.getViewportBounds().getHeight();
if (contentHeight <= viewportHeight) {
return 0d;
} else {
return -scroll.getVvalue() * (contentHeight - viewportHeight);
}
}, scroll.viewportBoundsProperty(), scroll.vvalueProperty(), content.heightProperty()));
HBox root = new HBox(scaleContainer, scroll);
root.setPadding(new Insets(10));
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
I have a VBox which contains Panes. Over the VBox, I want to show another element (currently I use a Pane). This element has to overlay multiple Panes in the VBox, so I put this element together with the VBox inside an AnchorPane. The complete structure looks like this:
HBox
VBox
Label <--- "Friday"
AnchorPane
VBox <--- the VBox with Panes
Pane
...
Pane <--- the Pane over the VBox (red in images)
The problem is that when I resize the window, the red Pane does not resize nor change its position.
Normal size:
Small size:
I want the red Pane to start at the same line (3rd) and be of the same relative size.
I tried binding the Pane's prefWidthProperty and prefHeightProperty to its parent (AnchorPane). This works for auto-resizing.
For auto-positioning, I have tried to bind the layoutX|Y properties, which didn't work, because these are set by the system and I get exception "Bound value cannot be set". So I tried to make the Pane unmanaged, which in turn broke the auto-resize, since in unmanaged nodes, changes in preferred properties have no effect. I thought of binding widthProperty and heightProperty to the parent's properties, but these are read-only.
Consider using a GridPane for functionality like this. You can add multiple nodes to the same cell(s) in the grid (the ones added last will appear on top in z-order). A GridPane allows maximum flexibility for layout. Here's an example: note that there's a lot of styling here that I just hard-coded for brevity, but in a real app you should move this to an external stylesheet (you can do the same with the max sizes, etc):
import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Region;
import javafx.scene.layout.RowConstraints;
import javafx.stage.Stage;
public class CalendarExample extends Application {
#Override
public void start(Stage primaryStage) {
GridPane calendar = new GridPane();
// headers:
for (DayOfWeek dayOfWeek = DayOfWeek.MONDAY ; dayOfWeek.getValue() <= DayOfWeek.FRIDAY.getValue();
dayOfWeek = DayOfWeek.of(dayOfWeek.getValue() + 1) ) {
Label label = new Label(dayOfWeek.toString());
label.setAlignment(Pos.CENTER);
label.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
label.setStyle("-fx-background-color: black, darkgray; -fx-background-insets: 0, 0 0 1 1 ;");
calendar.add(label, dayOfWeek.getValue(), 0);
}
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("hh:mm");
int rowCount = 0 ;
for (LocalTime time = LocalTime.of(8, 0); time.isBefore(LocalTime.of(17, 0)); time=time.plusMinutes(30)) {
rowCount++ ;
Label label = new Label(timeFormatter.format(time));
label.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
label.setAlignment(Pos.CENTER);
String color = rowCount % 2 == 0 ? "darkgray" : "lightgray" ;
label.setStyle("-fx-background-color: black, "+color+"; -fx-background-insets: 0, 0 0 1 1;");
calendar.add(label, 0, rowCount);
}
// cells:
for (int x = 1 ; x <= 5; x++) {
for (int y = 1 ; y <= rowCount; y++) {
Region region = new Region();
String color = y % 2 == 0 ? "darkgray" : "lightgray" ;
region.setStyle("-fx-background-color: black, "+color+"; -fx-background-insets: 0, 0 0 1 1 ;");
calendar.add(region, x, y);
}
}
// Column constraints:
for (int x = 0 ; x <= 5 ; x++) {
ColumnConstraints cc = new ColumnConstraints();
cc.setPercentWidth(100.0 / 6);
cc.setFillWidth(true);
calendar.getColumnConstraints().add(cc);
}
// row constraints:
for (int y = 0 ; y <= rowCount; y++) {
RowConstraints rc = new RowConstraints();
rc.setPercentHeight(100.0 / (rowCount+1));
rc.setFillHeight(true);
calendar.getRowConstraints().add(rc);
}
// Example appointment block:
DayOfWeek appointmentDay = DayOfWeek.FRIDAY ;
LocalTime startTime = LocalTime.of(10, 0);
LocalTime endTime = LocalTime.of(13, 0);
String appointmentText = "Fridays need really long coffee breaks";
Label appointment = new Label(appointmentText);
appointment.setTooltip(new Tooltip(appointmentText));
appointment.setWrapText(true);
appointment.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
appointment.setStyle("-fx-background: red; -fx-background-color: -fx-background; " );
GridPane.setMargin(appointment, new Insets(2, 5, 2, 2));
Scene scene = new Scene(calendar, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
This also behaves as needed when the window is resized:
width and height properties may be readonly, but you can assign the prefered sizes and use autosize.
Example
The following code makes the overlay start at 50% height and have a height of 1/3 of the VBox height:
#Override
public void start(Stage primaryStage) {
Region region1 = new Region();
VBox.setVgrow(region1, Priority.ALWAYS);
region1.setStyle("-fx-background-color: blue;");
Region region2 = new Region();
VBox.setVgrow(region2, Priority.ALWAYS);
region2.setStyle("-fx-background-color: lime;");
Region regionOverlay = new Region();
regionOverlay.setStyle("-fx-background-color: red;");
regionOverlay.setManaged(false);
VBox root = new VBox(region1, region2, regionOverlay);
root.layoutBoundsProperty().addListener((observable, oldValue, newValue) -> {
regionOverlay.setPrefSize(newValue.getWidth() - 20, newValue.getHeight() / 3);
regionOverlay.setLayoutX(10);
regionOverlay.setLayoutY(newValue.getHeight() / 2);
regionOverlay.autosize();
});
root.setPrefSize(400, 400);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
If all you need is a red rectangle, i'd advise you to use the Rectangle shape instead of panes. This allows you to bind its widths and heights explicitly.
I can not understand how moveTo method work in javafx. here is my example
I have a GridPane that consist of 4 columns and 1 row. All the columns h has a StackPane and the last Stackpane also has an empty label.
public class PathTransitionTExample extends Application {
StackPane pane;
GridPane grid;
Label label;
Scene scene;
#Override
public void start(Stage primaryStage) {
label = new Label();
label.setPrefSize(Double.MAX_VALUE, Double.MAX_VALUE);
grid = new GridPane();
grid.getStyleClass().add("gridPane");
for (int x = 0; x < 4; x++) {
grid.add(pane = new StackPane(), x, 0);
pane.setPrefSize(50, 50);
pane.getStyleClass().add("stackPane");
}
pane = (StackPane) grid.getChildren().get(3);
pane.getChildren().add(label);
scene = new Scene(grid, 260, 50);
scene.getStylesheets().add(PathTransitionTest.class.getResource("pathCSS.css").toExternalForm());
scene.setOnMouseClicked(me -> pathTransition());
primaryStage.setTitle("Path Transition");
primaryStage.setScene(scene);
primaryStage.show();
}
//pathCSS.css
.gridPane{
-fx-background-color: red;
-fx-hGap: 20;
}
.stackPane{
-fx-background-color: orange;
}
.label {
-fx-background-color: blue;
}
I want to move the label in the grid pane from 0.3 to 0.0 however when I am trying to do that the whole transition slips.
private void pathTransition() {
//the Coordinates of the label
double oldMinX = grid.getChildren().get(3).getLayoutX();
double oldMinY = grid.getChildren().get(3).getLayoutY();
//the coordinates of the stack pane where i want the label move
double newMinX = grid.getChildren().get(1).getLayoutX();
double newMinY = grid.getChildren().get(1).getLayoutY();
Path path = new Path();
path.getElements().add(new MoveTo(oldMinX, oldMinY ));
path.getElements().add(new LineTo(newMinX,newMinY ));
PathTransition pathTransition = new PathTransition();
pathTransition.setDuration(new Duration(500));
pathTransition.setPath(path);
pathTransition.setNode(label);
pathTransition.play();
}
If I change the arguments of MoveTo and LineTo by the following I can achieve the animation I want but I cant understand why. :\
double oldMinX = grid.getChildren().get(3).getLayoutX() -185;
double oldMinY = grid.getChildren().get(3).getLayoutY()+ grid.getChildren().get(3).getBoundsInLocal().getHeight()/2 ;
double newMinX = grid.getChildren().get(1).getLayoutX()-255 ;
double newMinY = grid.getChildren().get(1).getLayoutY() + grid.getChildren().get(0).getBoundsInLocal().getHeight()/2 ;
I guess It is because transitions use different coordinate systems than scenes but I cant really find anything that explains well :( Could someone give me some hints how It is working?
Thank you so much in advance.
I realized that i shouldn't use GridPane. If i do it without using containers the transition is working fine.
I'm using the following code to create a simple grid of buttons for a calculator:
BorderPane rootNode = new BorderPane();
GridPane gridPane = new GridPane();
rootNode.setCenter(gridPane);
int counter = 1;
for(int row = 3; row > 0; row--)
for(int col = 0; col < 3; col++) {
Button button = new Button("" + counter++);
button.setOnAction(this);
gridPane.add(button, col, row);
}
gridPane.add(new Button("R"), 0, 4);
gridPane.add(new Button("0"), 1, 4);
(Wanted to post an image of how it looks here, but I don't have enough reputation points to be allowed to do so)
The GridPane ends up being tiny and crammed up in the upper left corner, but I want it to take up all available space in the BorderPane's center region (that would be the entire window in this case). I've tried messing around with a bunch of things like various setSize methods, but havn't had much luck.
Your GridPane is already taking all the space available to it i.e. the entire Borderpane. Its the GridCells which are not using the space available to the GridPane.
You can make use of the Hgrow and Vgrow options available in the GridPane to make the cells take up the entire space available.
Here is an example which uses setHgrow to use the entire width available to the GridPane. You may add the same for the Height.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage stage) {
BorderPane rootNode = new BorderPane();
rootNode.setMinSize(300, 300);
rootNode.setStyle("-fx-background-color: RED;");
GridPane gridPane = new GridPane();
gridPane.setStyle("-fx-background-color: BLUE;");
rootNode.setCenter(gridPane);
int counter = 1;
for (int row = 3; row > 0; row--)
for (int col = 0; col < 3; col++) {
Button button = new Button("" + counter++);
gridPane.add(button, col, row);
GridPane.setHgrow(button, Priority.ALWAYS);
}
Button r = new Button("R");
gridPane.add(r, 0, 4);
GridPane.setHgrow(r, Priority.ALWAYS);
Button r0 = new Button("0");
gridPane.add(r0, 1, 4);
GridPane.setHgrow(r0, Priority.ALWAYS);
Scene scene = new Scene(rootNode);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Sorry, I missunderstood the question.
The Buttons are just too small, so not taking all the space they have in the borderpane? The width of a button depends on the size of the text it has. You just write a number in it so they are pretty small then. Use button.setPrefWidth(Integer.MAX_VALUE) and they use all the width they can get!
I have an editable ComboBox and I wish to "hide" the down arrow button so that it looks like a normal textbox.
Use css as,
.combo-box .arrow, .combo-box .arrow-button{
-fx-background-color: transparent;
}
Sample code::
public class ComboboxSample extends Application {
public static void main(String[] args) {
launch(args);
}
final Button button = new Button("Send");
final Label notification = new Label();
final TextField subject = new TextField("");
final TextArea text = new TextArea("");
String address = " ";
#Override
public void start(Stage stage) {
stage.setTitle("ComboBoxSample");
Scene scene = new Scene(new Group(), 450, 250);
// Load the css as below to the scene
scene.getStylesheets()
.add(ComboboxSample.class.getResource("styles.css").toExternalForm());
final ComboBox emailComboBox = new ComboBox();
emailComboBox.setEditable(true);
emailComboBox.getItems().addAll("jacob.smith#example.com",
"isabella.johnson#example.com", "ethan.williams#example.com",
"emma.jones#example.com", "michael.brown#example.com");
final ComboBox priorityComboBox = new ComboBox();
priorityComboBox.getItems().addAll("Highest", "High", "Normal", "Low",
"Lowest");
priorityComboBox.setValue("Normal");
GridPane grid = new GridPane();
grid.setVgap(4);
grid.setHgap(10);
grid.setPadding(new Insets(5, 5, 5, 5));
grid.add(new Label("To: "), 0, 0);
grid.add(emailComboBox, 1, 0);
grid.add(new Label("Priority: "), 2, 0);
grid.add(priorityComboBox, 3, 0);
grid.add(new Label("Subject: "), 0, 1);
grid.add(subject, 1, 1, 3, 1);
grid.add(text, 0, 2, 4, 1);
grid.add(button, 0, 3);
grid.add(notification, 1, 3, 3, 1);
Group root = (Group) scene.getRoot();
root.getChildren().add(grid);
stage.setScene(scene);
stage.show();
}
}
Output:
.combo-box1 .arrow-button
{
-fx-background-color: null;
-fx-background-insets: 0;
-fx-background-radius: 0;
-fx-padding: 0.0em 0em 0.0em 0.0em; /* 0 3 0 0 */
}
.combo-box1 .arrow-button .arrow
{
-fx-background-color: -fx-mark-highlight-color, -fx-mark-color;
-fx-background-insets: 0 0 0 0, 0;
-fx-padding: 0em 0em 0em 0em; /* 3 3.75 3 3.75 */
/*
-fx-shape: "M 0 0 h 7 l -3.5 4 z";
*/
-fx-shape: null;
}
I used the following ccs code:
.combo-box1 .arrow-button {
-fx-opacity: 0.0;
-fx-cursor: text;
}
and this in java:
combobox.getStyleClass().add("combo-box1");
There are several ways to do this, here are four. The code is Jython with JavaFX.
First, the enum, for context.
public enum URLBarArrowConstants {
//URLBarArrow Constants
BYCSS_AND_SHAPE,
BYCSS_AND_NO_SHAPE,
NOCSS_AND_SHAPE,
NOCSS_AND_NO_SHAPE;
}
Second, the css files, for context.
EG #1
/*ComboBox's Arrow is a Region.*/
.combo-box .arrow-button .arrow {
-fx-shape: "...";
-fx-scale-shape: true;
-fx-position-shape: true;
}
EG#2
/*ComboBox's Arrow is a Region.*/
.combo-box .arrow-button .arrow {
/*Setting either of these two will do.*/
-fx-background-color: transparent;
-fx-opacity: 0.0;
}
/*ComboBox's Arrow Button is a Stack Pane.*/
.combo-box .arrow-button{
-fx-background-position: center;
-fx-background-repeat: no-repeat;
-fx-background-image: url("..<file>.png");
}
The method, in my main file.
def setCustomURLBarArrow(self, url_bar, scene, URLBarArrowConstant):
from javafx.scene.paint import Paint
from javafx.scene.shape import Shape, SVGPath, FillRule
Don't configure the ComboBox Arrow by CSS, instead, do it programmatically and change the Regions SVG Shape
if URLBarArrowConstant == URLBarArrowConstants.NOCSS_AND_SHAPE:
#SVG Object
previous_url_bar = SVGPath()
#SVG Path
previous_url_bar.setContent("...") # edit this
#SVG Fill Rule
previous_url_bar.setFillRule(FillRule.NON_ZERO)
#Set Fill --
previous_url_bar.setFill(Paint.valueOf(Color.web("...").toString())) //edit here
#Apply CSS Sheet
url_bar.applyCss()
#Set Region's Shape
arrow_region = url_bar.lookup(".arrow").setShape(previous_url_bar)
Configure the ComboBox Arrow by CSS and change the Regions SVG Shape
elif URLBarArrowConstant == URLBarArrowConstants.BYCSS_AND_SHAPE:
#Apply Stylesheet for URL Bar
scene.getStylesheets().add(File("..<file>.css").toURI().toString()) //edit here
Configure the ComboBox Arrow by CSS but instead, merely hide the arrow by setting the transparency/opacity values and set a background.
elif URLBarArrowConstant == URLBarArrowConstants.BYCSS_AND_NO_SHAPE:
#Apply Stylesheet for URL Bar
scene.getStylesheets().add(File("..<file>.css").toURI().toString()) //edit here
Don't configure the ComboBox Arrow by CSS, instead, do it programmatically and merely hide the arrow by setting the transparency/opacity values and set a background.
elif URLBarArrowConstant == URLBarArrowConstants.NOCSS_AND_NO_SHAPE:
from javafx.scene.paint import Paint
from javafx.scene.layout import CornerRadii
from javafx.scene.layout import Background, BackgroundSize, BackgroundImage, BackgroundPosition, BackgroundRepeat, BackgroundFill
#Apply CSS Sheet
url_bar.applyCss()
#Grab Arrow(Region), ArrowButton(StackPane) ComboBox properties
arrow_region = url_bar.lookup(".arrow")
arrow_button = url_bar.lookup(".arrow-button")
#Either Set Opacity to 0 or set background color to transparent.
arrow_region.setOpacity(0.0)
arrow_region.setBackground( Background( array(BackgroundFill, [BackgroundFill( Paint.valueOf(Color.TRANSPARENT.toString()), CornerRadii.EMPTY, Insets.EMPTY)]) ) )
#Set a Background Image for the .arrow-button StackPane.
arrow_button.setBackground(Background( array(BackgroundImage, [BackgroundImage( Image( String(File('..<file>.png').toURI().toString()), True) , BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.CENTER, BackgroundSize.DEFAULT)] ) ) ) //if you want, edit this