使用滑块更改文本颜色

Changing text color with a slider

我正在尝试制作一个程序,允许用户通过单选按钮 select RGB 颜色,并使用滑块在 0 - 255 之间更改值。颜色更改应适用于文本。当 R、G 或 B 为 selected 时,文本中应仅显示 selected 颜色(即,如果绿色为 selected,则红色和蓝色值为 0)。

目前程序在一定程度上可以工作。例如,如果滑块位于值 150,并且我 select 编辑了一种新颜色,然后移动了滑块,则文本颜色设置为 150,或者在任何情况下滑块在尝试之前设置的值将其移动到新值。如果我想让它更新,我必须在移动滑块之前 select 一种新颜色。它只为每种 selected 颜色更新一次。我希望它无缝地更新 selected 颜色。下面的代码示例:

public class Oblig5 extends Application {

    static int colorValue = 0;
    static int red = 0;
    static int green = 0;
    static int blue = 0;

    public static void main(String[] args) {

        launch(args);

    }

    public void start(Stage primaryStage) {
        // Create panes
        BorderPane bPane = new BorderPane();
        VBox vBox = new VBox();
        bPane.setLeft(vBox);

        // Create text and place it in the pane
        Text text = new Text("Oblig 5");
        text.setFont(Font.font("Times New Roman", FontWeight.NORMAL, FontPosture.REGULAR, 40));
        bPane.setCenter(text);

        // Create radio buttons and place them in the VBox
        RadioButton rbRed = new RadioButton("Red");
        RadioButton rbGreen = new RadioButton("Green");
        RadioButton rbBlue = new RadioButton("Blue");


        ToggleGroup group = new ToggleGroup();
        rbRed.setToggleGroup(group);
        rbGreen.setToggleGroup(group);
        rbBlue.setToggleGroup(group);

        // Create handlers for radiobuttons 
        rbRed.setOnAction(e -> {
            if (rbRed.isSelected()) {
                red = colorValue;
                green = 0;
                blue = 0;
            }
        });

        rbGreen.setOnAction(e -> {
            if (rbGreen.isSelected()) {
                red = 0;
                green = colorValue;
                blue = 0;
            }
        });

        rbBlue.setOnAction(e -> {
            if (rbBlue.isSelected()) {
                red = 0;
                green = 0;
                blue = colorValue;
            }
        });

        vBox.getChildren().addAll(rbRed, rbGreen, rbBlue);

        // Create a slider and place it in the BorderPane
        Slider slider = new Slider(0, 255, 135);
        slider.setShowTickLabels(true);
        slider.setShowTickMarks(true);
        bPane.setBottom(slider);
        bPane.setAlignment(slider, Pos.CENTER);

        // Create a handler for the slider
        slider.valueProperty().addListener(ov -> {
            colorValue = (int) slider.getValue();
            text.setFill(Color.rgb(red, green, blue));
        });

        // Create a scene and place it in the stage
        Scene scene = new Scene(bPane, 400, 400);
        primaryStage.setScene(scene);
        primaryStage.setTitle("Oblig 5");
        primaryStage.show();

    }

}

非常感谢任何意见!

您可以将 Color 设置为用作 userData 切换。这允许您根据滑块值和选定的切换为文本的 fill 属性 创建绑定:

// create radio buttons and add color at full brightness
RadioButton rbRed = new RadioButton("Red");
rbRed.setUserData(Color.RED);
RadioButton rbGreen = new RadioButton("Green");
rbGreen.setUserData(Color.LIME);
RadioButton rbBlue = new RadioButton("Blue");
rbBlue.setUserData(Color.BLUE);

ToggleGroup group = new ToggleGroup();
rbRed.setToggleGroup(group);
rbGreen.setToggleGroup(group);
rbBlue.setToggleGroup(group);

group.selectToggle(rbRed);

...

// create binding based on toggle user data and slider value
text.fillProperty().bind(Bindings.createObjectBinding(() -> {
    Color color = (Color) group.getSelectedToggle().getUserData();

    // use color determined by toggle with brightness adjusted based on slider value
    return color.deriveColor(0, 1, slider.getValue() / slider.getMax(), 1);
}, slider.valueProperty(), group.selectedToggleProperty()));

请注意,使用这些代码片段无需保留侦听器。特别是应该删除更新文本填充的侦听器,因为尝试分配绑定 属性 会导致异常。

[注意:@fabian post在我写这篇文章时编辑了一个答案。任何一个答案都可以,我想我也会 post 这个,因为它显示的技术略有不同。与往常一样,在 JavaFX 中有多种实现同一目标的好方法。]

当所选按钮发生变化或滑块值发生变化时,您需要使用适当的值设置文本填充。现在,当所选按钮发生变化时,您只更新变量 redgreenblue(但不更改文本填充),当滑块值发生变化时,您用 redgreenblue 调用 setFill(...),但不要更改这些变量的值。

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.RadioButton;
import javafx.scene.control.Slider;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontPosture;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class Oblig5 extends Application {

    public static void main(String[] args) {

        launch(args);

    }

    public void start(Stage primaryStage) {
        // Create panes
        BorderPane bPane = new BorderPane();
        VBox vBox = new VBox();
        bPane.setLeft(vBox);

        Text text = new Text("Oblig 5");
        text.setFont(Font.font("Times New Roman", FontWeight.NORMAL, FontPosture.REGULAR, 40));
        bPane.setCenter(text);

        RadioButton rbRed = new RadioButton("Red");
        RadioButton rbGreen = new RadioButton("Green");
        RadioButton rbBlue = new RadioButton("Blue");


        ToggleGroup group = new ToggleGroup();
        rbRed.setToggleGroup(group);
        rbGreen.setToggleGroup(group);
        rbBlue.setToggleGroup(group);

        vBox.getChildren().addAll(rbRed, rbGreen, rbBlue);

        Slider slider = new Slider(0, 255, 135);
        slider.setShowTickLabels(true);
        slider.setShowTickMarks(true);
        bPane.setBottom(slider);
        BorderPane.setAlignment(slider, Pos.CENTER);

        // Create a handler for the updating text fill:
        ChangeListener<Object> updateListener = (obs, oldValue, newValue) -> {
            int colorValue = (int) slider.getValue() ;
            int red   =   rbRed.isSelected() ? colorValue : 0 ;
            int green = rbGreen.isSelected() ? colorValue : 0 ;
            int blue  =  rbBlue.isSelected() ? colorValue : 0 ;
            text.setFill(Color.rgb(red, green, blue));
        };
        slider.valueProperty().addListener(updateListener);
        group.selectedToggleProperty().addListener(updateListener);

        // Create a scene and place it in the stage
        Scene scene = new Scene(bPane, 400, 400);
        primaryStage.setScene(scene);
        primaryStage.setTitle("Oblig 5");
        primaryStage.show();

    }


}