JavaFX - how to get background color of Tab, Butto

2019-02-19 11:34发布

Problem description: I can't get background of object in JavaFX. I don't mean Shapes, but normal Nodes like Buttons, Tabs and others. I don't know how to access to theirs background color.

What I want? I am developing IDE and I want to run Color animation on tab with file that user want to open and is already existing in program file collection. Before doing this animation I want to read original tab background color and that color is returned to tab at the end of animation. Also I want to get back hover and selected properties, which disappear when I set some color in animation and they never get back. All colors I am setting up in CSS file and I don't want to change it.

My question: How to get and set programmatically Node color? Or how to do color animation with save original properties and at the end of animation get this properties back?

One short example:

One short example

sample.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<TabPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="480.0" prefWidth="600.0" stylesheets="@style.css" tabClosingPolicy="UNAVAILABLE" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
  <tabs>
    <Tab text="Sample tab 1">
      <content>
        <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
      </content>
    </Tab>
    <Tab text="Sample tab 2">
      <content>
        <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
      </content>
    </Tab>
      <Tab text="Sample tab 3">
        <content>
          <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
        </content>
      </Tab>
  </tabs>
</TabPane>

styles.css

.tab{
-fx-background-color:   pink;}

.tab:hover{
-fx-background-color:   red;}

.tab:selected{
-fx-background-color:   yellow;}

2条回答
来,给爷笑一个
2楼-- · 2019-02-19 11:50

As far as I know, there is no way in the public API to determine what is being currently used as the background color for a Region (including for a Control) (unless you know it is either set by an inline style, in which case you can parse the result of getStyle() or by a call to setBackground(...)). But I see no reason you would want this; the color will revert to that defined in the css file if you remove any inline styles or background property.

Here's a simple example where the background color is set by a linear gradient (via an inline style) which slides as a task progresses:

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.IntegerBinding;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class ColoredTabDemo extends Application {

    private int tabCount ;

    @Override
    public void start(Stage primaryStage) {
        TabPane tabPane = new TabPane();
        for (int i = 0; i < 4; i++) {
            tabPane.getTabs().add(createTab());
        }
        Scene scene = new Scene(tabPane, 600, 400);
        scene.getStylesheets().add("colored-tab-demo.css");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private Tab createTab() {
        Tab tab = new Tab("Tab "+(++tabCount));
        Button button = new Button("Load file...");

        button.setOnAction(e -> {
            Task<Void> task = new Task<Void>() {
                @Override
                public Void call() throws Exception {

                    // simulate loading:
                    for (int i=1; i <= 500; i++) {
                        updateProgress(i, 500);
                        Thread.sleep(20);
                    }

                    return null ;

                }
            };

            IntegerBinding progressAsPercent = Bindings.createIntegerBinding(() -> 
                (int) (task.getProgress() * 100), task.progressProperty());

            tab.styleProperty().bind(Bindings.format("-fx-background-color: "
                    + "linear-gradient(to right, -fx-accent 0%%, -fx-accent %d%%, -fx-background %1$d%%, -fx-background 100%%);", 
                    progressAsPercent));

            button.setDisable(true);

            task.setOnSucceeded(evt -> {
                tab.styleProperty().unbind();
                tab.setStyle("");
                button.setDisable(false);
            });

            new Thread(task).start();
        });

        tab.setContent(new StackPane(button));

        return tab ;
    }

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

colored-tab-demo.css is almost exactly the same as you posted, but using a looked-up color instead of setting -fx-background-color directly:

.tab{
    -fx-background-color:   -fx-background;
    -fx-background: pink ;
}

.tab:hover{
    -fx-background:   red;
}

.tab:selected{
    -fx-background:   yellow;
}
查看更多
小情绪 Triste *
3楼-- · 2019-02-19 11:56

Can get/set Button color easy enough.

Just follow the methods from Background -> BackgroundFill -> first element of getFills() list -> getFill() -- which gives you the Paint object for this node's background. Then just cast this to a Color object. The value of the Color object is listed as a hex number whose last 6 hex digits equate to the hex RGB for that color. See output of code example below. It might be safer if I'd used the !equals(.) method rather than != for color checking but it seems to work fine anyway.

Say you have a checkerboard pattern of numbered 10 x 10 squares alternately colored blue or orange depending on whether the square's number is odd or even respectively. Say each square is a Button and whenever a player clicks on one of them, it is re-colored red. But if the player clicks again on the same square, it is restored to its original color.

Works for me.

.....
.....
.....

// Declare click response :
playBoard[i][j].setOnAction(e ->    
{
    n = Integer.parseInt(((Button)e.getSource()).getText());
    toggleColorButtonRed((Button)e.getSource(), n);
});

.....
.....
.....

private void toggleColorButtonRed(Button button, int n)
{
    Color color = (Color)button.getBackground().getFills().get(0).getFill();
    if (color != Color.RED)
        button.setBackground(new Background(new BackgroundFill(
                Color.RED, CornerRadii.EMPTY, Insets.EMPTY)));
    else 
    {
       System.out.println("You have clicked a " + color + " square !");
       if (n % 2 == 0)
            button.setBackground(new Background(new BackgroundFill(
                    Color.ORANGE, CornerRadii.EMPTY, Insets.EMPTY)));
       else 
            button.setBackground(new Background(new BackgroundFill(
                    Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
    }

}


 OUTPUT WHEN A SQUARE IS CLICKED TWICE
 =====================================

 You have clicked a 0xff0000ff square !
查看更多
登录 后发表回答