直接显示自定义颜色对话框 - JavaFX ColorPicker

Rut*_*til 5 color-picker color-palette javafx-8


我需要在ContextMenu中为颜色选择显示"连续"调色板.与在ColorPicker上弹出的CustomColorDialog类似.
是否有一个不同的类用于此目的,或者是否可以通过扩展ColorPicker并直接显示CustomColorDialog而不是首先显示ColorPicker来解决.

ColorPicker JavaFX 8

TIA

Jos*_*eda 13

对于初学者来说,com.sun.javafx.scene.control.skin.CustomColorDialog是私有API,并且不建议使用它,因为它可能在将来发生变化,恕不另行通知.

此外,它是一个Dialog,什么意思你不能嵌入它ContextMenu,它有自己的窗口和它的模态.

这是在应用程序中使用此(非常大,不可自定义)对话框的简短示例,而不使用ColorPicker.

@Override
public void start(Stage primaryStage) {
    Button btn = new Button();
    btn.setText("Open Custom Color Dialog");
    btn.setOnAction(e -> {
        CustomColorDialog dialog = new CustomColorDialog(primaryStage.getOwner());
        dialog.show();
    });

    Scene scene = new Scene(new StackPane(btn), 300, 250);

    primaryStage.setTitle("CustomColorDialog");
    primaryStage.setScene(scene);
    primaryStage.show();
}
Run Code Online (Sandbox Code Playgroud)

您将获得对话框,但您将无法发送自定义颜色或检索所选颜色,因为类似customColorProperty()的属性只能在com.sun.javafx.scene.control.skin包中访问.

所以我们需要另一种方法来实现自定义颜色选择器.如果您查看源代码,CustomColorDialog您会发现它是一个相对简单的控件,而且最重要的是,几乎基于公共API:窗格,区域和颜色.

试图把所有东西放在一个ContextMenu可能是过度的,所以我想出了这个基本的例子,我将只使用对话框的左侧部分,在顶部显示中央栏.大多数代码都来自课堂.CSS样式也取自modena.css(在custom-color-dialogCSS选择器下),但是由于一些节点旋转了90度而被定制.

这是CustomColorDialog课程的简短版本:

public class MyCustomColorPicker extends VBox {

    private final ObjectProperty<Color> currentColorProperty = 
        new SimpleObjectProperty<>(Color.WHITE);
    private final ObjectProperty<Color> customColorProperty = 
        new SimpleObjectProperty<>(Color.TRANSPARENT);

    private Pane colorRect;
    private final Pane colorBar;
    private final Pane colorRectOverlayOne;
    private final Pane colorRectOverlayTwo;
    private Region colorRectIndicator;
    private final Region colorBarIndicator;
    private Pane newColorRect;

    private DoubleProperty hue = new SimpleDoubleProperty(-1);
    private DoubleProperty sat = new SimpleDoubleProperty(-1);
    private DoubleProperty bright = new SimpleDoubleProperty(-1);

    private DoubleProperty alpha = new SimpleDoubleProperty(100) {
        @Override protected void invalidated() {
            setCustomColor(new Color(getCustomColor().getRed(), getCustomColor().getGreen(), 
                    getCustomColor().getBlue(), clamp(alpha.get() / 100)));
        }
    };

    public MyCustomColorPicker() {

        getStyleClass().add("my-custom-color");

        VBox box = new VBox();

        box.getStyleClass().add("color-rect-pane");
        customColorProperty().addListener((ov, t, t1) -> colorChanged());

        colorRectIndicator = new Region();
        colorRectIndicator.setId("color-rect-indicator");
        colorRectIndicator.setManaged(false);
        colorRectIndicator.setMouseTransparent(true);
        colorRectIndicator.setCache(true);

        final Pane colorRectOpacityContainer = new StackPane();

        colorRect = new StackPane();
        colorRect.getStyleClass().addAll("color-rect", "transparent-pattern");

        Pane colorRectHue = new Pane();
        colorRectHue.backgroundProperty().bind(new ObjectBinding<Background>() {

            {
                bind(hue);
            }

            @Override protected Background computeValue() {
                return new Background(new BackgroundFill(
                        Color.hsb(hue.getValue(), 1.0, 1.0), 
                        CornerRadii.EMPTY, Insets.EMPTY));

            }
        });            

        colorRectOverlayOne = new Pane();
        colorRectOverlayOne.getStyleClass().add("color-rect");
        colorRectOverlayOne.setBackground(new Background(new BackgroundFill(
                new LinearGradient(0, 0, 1, 0, true, CycleMethod.NO_CYCLE, 
                new Stop(0, Color.rgb(255, 255, 255, 1)), 
                new Stop(1, Color.rgb(255, 255, 255, 0))), 
                CornerRadii.EMPTY, Insets.EMPTY)));

        EventHandler<MouseEvent> rectMouseHandler = event -> {
            final double x = event.getX();
            final double y = event.getY();
            sat.set(clamp(x / colorRect.getWidth()) * 100);
            bright.set(100 - (clamp(y / colorRect.getHeight()) * 100));
            updateHSBColor();
        };

        colorRectOverlayTwo = new Pane();
        colorRectOverlayTwo.getStyleClass().addAll("color-rect");
        colorRectOverlayTwo.setBackground(new Background(new BackgroundFill(
                new LinearGradient(0, 0, 0, 1, true, CycleMethod.NO_CYCLE, 
                new Stop(0, Color.rgb(0, 0, 0, 0)), new Stop(1, Color.rgb(0, 0, 0, 1))), 
                CornerRadii.EMPTY, Insets.EMPTY)));
        colorRectOverlayTwo.setOnMouseDragged(rectMouseHandler);
        colorRectOverlayTwo.setOnMousePressed(rectMouseHandler);

        Pane colorRectBlackBorder = new Pane();
        colorRectBlackBorder.setMouseTransparent(true);
        colorRectBlackBorder.getStyleClass().addAll("color-rect", "color-rect-border");

        colorBar = new Pane();
        colorBar.getStyleClass().add("color-bar");
        colorBar.setBackground(new Background(new BackgroundFill(createHueGradient(), 
                CornerRadii.EMPTY, Insets.EMPTY)));

        colorBarIndicator = new Region();
        colorBarIndicator.setId("color-bar-indicator");
        colorBarIndicator.setMouseTransparent(true);
        colorBarIndicator.setCache(true);

        colorRectIndicator.layoutXProperty().bind(
            sat.divide(100).multiply(colorRect.widthProperty()));
        colorRectIndicator.layoutYProperty().bind(
            Bindings.subtract(1, bright.divide(100)).multiply(colorRect.heightProperty()));
        colorBarIndicator.layoutXProperty().bind(
            hue.divide(360).multiply(colorBar.widthProperty()));
        colorRectOpacityContainer.opacityProperty().bind(alpha.divide(100));

        EventHandler<MouseEvent> barMouseHandler = event -> {
            final double x = event.getX();
            hue.set(clamp(x / colorRect.getWidth()) * 360);
            updateHSBColor();
        };

        colorBar.setOnMouseDragged(barMouseHandler);
        colorBar.setOnMousePressed(barMouseHandler);

        newColorRect = new Pane();
        newColorRect.getStyleClass().add("color-new-rect");
        newColorRect.setId("new-color");
        newColorRect.backgroundProperty().bind(new ObjectBinding<Background>() {
            {
                bind(customColorProperty);
            }
            @Override protected Background computeValue() {
                return new Background(new BackgroundFill(customColorProperty.get(), CornerRadii.EMPTY, Insets.EMPTY));
            }
        });

        colorBar.getChildren().setAll(colorBarIndicator);
        colorRectOpacityContainer.getChildren().setAll(colorRectHue, colorRectOverlayOne, colorRectOverlayTwo);
        colorRect.getChildren().setAll(colorRectOpacityContainer, colorRectBlackBorder, colorRectIndicator);
        VBox.setVgrow(colorRect, Priority.SOMETIMES);
        box.getChildren().addAll(colorBar, colorRect, newColorRect);

        getChildren().add(box);

        if (currentColorProperty.get() == null) {
            currentColorProperty.set(Color.TRANSPARENT);
        }
        updateValues();

    }

    private void updateValues() {
        hue.set(getCurrentColor().getHue());
        sat.set(getCurrentColor().getSaturation()*100);
        bright.set(getCurrentColor().getBrightness()*100);
        alpha.set(getCurrentColor().getOpacity()*100);
        setCustomColor(Color.hsb(hue.get(), clamp(sat.get() / 100), 
                clamp(bright.get() / 100), clamp(alpha.get()/100)));
    }

    private void colorChanged() {
        hue.set(getCustomColor().getHue());
        sat.set(getCustomColor().getSaturation() * 100);
        bright.set(getCustomColor().getBrightness() * 100);
    }

    private void updateHSBColor() {
        Color newColor = Color.hsb(hue.get(), clamp(sat.get() / 100), 
                        clamp(bright.get() / 100), clamp(alpha.get() / 100));
        setCustomColor(newColor);
    }

    @Override 
    protected void layoutChildren() {
        super.layoutChildren();            
        colorRectIndicator.autosize();
    }

    static double clamp(double value) {
        return value < 0 ? 0 : value > 1 ? 1 : value;
    }

    private static LinearGradient createHueGradient() {
        double offset;
        Stop[] stops = new Stop[255];
        for (int x = 0; x < 255; x++) {
            offset = (double)((1.0 / 255) * x);
            int h = (int)((x / 255.0) * 360);
            stops[x] = new Stop(offset, Color.hsb(h, 1.0, 1.0));
        }
        return new LinearGradient(0f, 0f, 1f, 0f, true, CycleMethod.NO_CYCLE, stops);
    }

    public void setCurrentColor(Color currentColor) {
        this.currentColorProperty.set(currentColor);
        updateValues();
    }

    Color getCurrentColor() {
        return currentColorProperty.get();
    }

    final ObjectProperty<Color> customColorProperty() {
        return customColorProperty;
    }

    void setCustomColor(Color color) {
        customColorProperty.set(color);
    }

    Color getCustomColor() {
        return customColorProperty.get();
    }
}
Run Code Online (Sandbox Code Playgroud)

这是color.css文件:

.context-menu{
    -fx-background-color: derive(#ececec,26.4%);
}
.menu-item:focused {
    -fx-background-color: transparent;
}

/* CUSTOM COLOR */

.my-custom-color {
    -fx-background-color: derive(#ececec,26.4%);
    -fx-padding: 1.25em;
    -fx-spacing: 1.25em;
    -fx-min-width: 20em;
    -fx-pref-width: 20em;
    -fx-max-width: 20em;
}

.my-custom-color:focused,
.my-custom-color:selected {
    -fx-background-color: transparent;
}

.my-custom-color > .color-rect-pane {
    -fx-spacing: 0.75em;
    -fx-pref-height: 16.666667em;
    -fx-alignment: top-left;
    -fx-fill-height: true;
}

.my-custom-color .color-rect-pane .color-rect {
    -fx-min-width: 16.666667em;
    -fx-min-height: 16.666667em;
}

.my-custom-color .color-rect-pane .color-rect-border {
    -fx-border-color: derive(#ececec, -20%);
}

.my-custom-color > .color-rect-pane #color-rect-indicator {
    -fx-background-color: null;
    -fx-border-color: white;
    -fx-border-radius: 0.4166667em;
    -fx-translate-x: -0.4166667em;
    -fx-translate-y: -0.4166667em;
    -fx-pref-width: 0.833333em;
    -fx-pref-height: 0.833333em;
    -fx-effect: dropshadow(three-pass-box, black, 2, 0.0, 0, 1);
}

.my-custom-color > .color-rect-pane > .color-bar {
    -fx-min-height: 1.666667em;
    -fx-min-width: 16.666667em;
    -fx-max-height: 1.666667em;
    -fx-border-color: derive(#ececec, -20%);
}

.my-custom-color > .color-rect-pane > .color-bar > #color-bar-indicator {
    -fx-border-radius: 0.333333em;
    -fx-border-color: white;
    -fx-effect: dropshadow(three-pass-box, black, 2, 0.0, 0, 1);
    -fx-pref-height: 2em;
    -fx-pref-width: 0.833333em;
    -fx-translate-y: -0.1666667em;
    -fx-translate-x: -0.4166667em;
}

.my-custom-color .transparent-pattern {
    -fx-background-image: url("pattern-transparent.png"); 
    -fx-background-repeat: repeat;
    -fx-background-size: auto;
}

.my-custom-color .color-new-rect {
    -fx-min-width: 10.666667em;
    -fx-min-height: 1.75em;
    -fx-pref-width: 10.666667em;
    -fx-pref-height: 1.75em;
    -fx-border-color: derive(#ececec, -20%);
}
Run Code Online (Sandbox Code Playgroud)

图像可以在这里找到.

最后,我们的应用程序类.

public class CustomColorContextMenu extends Application {

    private final ObjectProperty<Color> sceneColorProperty = 
        new SimpleObjectProperty<>(Color.WHITE);

    @Override
    public void start(Stage primaryStage) {

        Rectangle rect = new Rectangle(400,400);
        rect.fillProperty().bind(sceneColorProperty);

        Scene scene = new Scene(new StackPane(rect), 400, 400);
        scene.getStylesheets().add(getClass().getResource("color.css").toExternalForm());
        scene.setOnMouseClicked(e->{
            if(e.getButton().equals(MouseButton.SECONDARY)){
                MyCustomColorPicker myCustomColorPicker = new MyCustomColorPicker();
                myCustomColorPicker.setCurrentColor(sceneColorProperty.get());

                CustomMenuItem itemColor = new CustomMenuItem(myCustomColorPicker);
                itemColor.setHideOnClick(false);
                sceneColorProperty.bind(myCustomColorPicker.customColorProperty());
                ContextMenu contextMenu = new ContextMenu(itemColor);
                contextMenu.setOnHiding(t->sceneColorProperty.unbind());
                contextMenu.show(scene.getWindow(),e.getScreenX(),e.getScreenY());
            }
        });

        primaryStage.setTitle("Custom Color Selector");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

}
Run Code Online (Sandbox Code Playgroud)

注意使用CustomMenuItem允许单击颜色选择器而不关闭上下文菜单.要关闭它,只需单击弹出窗口外的任何位置即可.

这是它的样子:

自定义颜色选择器

基于此自定义对话框,您可以改进它并添加您可能需要的功能.