JavaFX ColorPicker显示uncolor选项

时间:2016-03-20 11:00:37

标签: javafx javafx-2 javafx-8

我想在ColorPicker中显示非颜色选项。 我怎么能表现出来?

感谢。 enter image description here

2 个答案:

答案 0 :(得分:1)

解决方案有点像黑客,但它避免使用私有API。

这些是必需的步骤:

  • 获取单击ColorPicker时显示的弹出窗口控件。

您可以找到它herehere

  • 在弹出窗口中获取方形颜色,以便我们可以更改其中一个。我会用最后一个。

一旦我们有弹出窗口,我们将使用查找来获取方形颜色集:Set<Node> squares = popup.lookupAll(".color-rect");

让我们使用最后一种颜色来添加我们自定义的'un-color'。

  • 了解如何绘制红色对角线。

我想出了LinearGradient

final LinearGradient redLine = new LinearGradient(0, 0, 1, 1, true, CycleMethod.NO_CYCLE, 
    new Stop(0, Color.WHITE), new Stop(0.45, Color.WHITE), 
    new Stop(0.46, Color.RED), new Stop(0.54, Color.RED), 
    new Stop(0.55, Color.WHITE), new Stop(1, Color.WHITE));

这样做很好,但遗憾的是,渐变会破坏ColorPicker控件,这是ComboBoxBase<Color>的扩展,并且用于矩形的所有填充都将转换为Color而非Paint。这意味着我们必须在过渡期间使用颜色(例如Color.TRANSPARENT)。

  • 解决其他问题,例如弹出窗口关闭时会看到的方形颜色,或悬停时显示的方形颜色。

为此,我们需要在颜色选择器和悬停的方块中查找方形颜色,当这些颜色与透明颜色匹配时,用渐变替换颜色。

这是代码:

public class UnColorPicker extends Application {

    private final LinearGradient redLine = new LinearGradient(0, 0, 1, 1, true, CycleMethod.NO_CYCLE, 
                            new Stop(0, Color.WHITE), new Stop(0.45, Color.WHITE), new Stop(0.46, Color.RED),
                            new Stop(0.54, Color.RED), new Stop(0.55, Color.WHITE), new Stop(1, Color.WHITE));

    @Override
    public void start(Stage primaryStage) {
        ColorPicker picker = new ColorPicker();
        StackPane root = new StackPane(picker);
        Scene scene = new Scene(root, 500, 400);

        primaryStage.setScene(scene);
        primaryStage.show();

        Rectangle rect = (Rectangle) root.lookup(".picker-color-rect");
        Label label = (Label) root.lookup(".color-picker-label");
        picker.showingProperty().addListener((obs, b, b1) -> {
            if (b1) {
                PopupWindow popupWindow = getPopupWindow();
                Node popup = popupWindow.getScene().getRoot().getChildrenUnmodifiable().get(0);
                StackPane hover = (StackPane) popup.lookup(".hover-square");
                Rectangle rectH = (Rectangle) hover.getChildren().get(0);
                Set<Node> squares = popup.lookupAll(".color-rect");
                squares.stream()
                        .skip(squares.size()-2)
                        .map(Rectangle.class::cast)
                        .findFirst()
                        .ifPresent(r -> {
                            r.getParent().setOnMousePressed(e -> {
                                // avoid CastException
                                r.setFill(Color.TRANSPARENT);
                                e.consume();
                            });
                            r.getParent().setOnMouseReleased(e -> {
                                Platform.runLater(() -> {
                                    rect.setFill(redLine);
                                    label.setText("Un-color");
                                });
                            });
                            r.setFill(redLine);
                            Tooltip.install(r.getParent(), new Tooltip("Un-color"));
                        });
                hover.visibleProperty().addListener((obs2, ov, nv) -> {
                    if (nv && rectH.getFill().equals(Color.TRANSPARENT)) {
                        Platform.runLater(() -> rectH.setFill(redLine));
                    }
                });
            }
        });
    }

    private PopupWindow getPopupWindow() {
        @SuppressWarnings("deprecation") 
        final Iterator<Window> windows = Window.impl_getWindows();
        while (windows.hasNext()) {
            final Window window = windows.next();
            if (window instanceof PopupWindow) {
                return (PopupWindow)window;
            }
        }
        return null;
    }

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

}

Uncolor picker

答案 1 :(得分:1)

上面发布的方法对我来说不再适用,所以我提出了一个稍微不同的解决方案,尽管这个想法是一样的。它还避免使用已弃用的函数。

我将ColorPicker类子类化为构建我自己的CustomColorPicker,可以使用它。

这是我的代码:

@SuppressWarnings("restriction")
public class CustomColorPicker extends ColorPicker {

    final static LinearGradient RED_LINE = new LinearGradient(0, 0, 1, 1, true, CycleMethod.NO_CYCLE, 
                                                        new Stop(0, Color.WHITE), new Stop(0.45, Color.WHITE), 
                                                        new Stop(0.46, Color.RED), new Stop(0.54, Color.RED), 
                                                        new Stop(0.55, Color.WHITE), new Stop(1, Color.WHITE));

    @Override 
    protected Skin<?> createDefaultSkin() {

        final CustomColorPickerSkin skin = new CustomColorPickerSkin(this);
        final Label lbl = (Label)skin.getDisplayNode();
        final StackPane pane = (StackPane)lbl.getGraphic();
        final Rectangle rect = (Rectangle)pane.getChildren().get(0);

        // set initial color to red line if transparent is shown
        if (getValue().equals(Color.TRANSPARENT))
            rect.setFill(RED_LINE);

        // set color to red line when transparent is selected
        rect.fillProperty().addListener((o, oldVal, newVal) -> {
            if (newVal != null && newVal.equals(Color.TRANSPARENT))
                rect.setFill(RED_LINE);     
        });

        return skin;
     }

    private class CustomColorPickerSkin extends ColorPickerSkin {

        private boolean initialized = false;

        public CustomColorPickerSkin(ColorPicker colorPicker) {
            super(colorPicker);
        }

        @Override 
        protected Node getPopupContent() {
            final ColorPalette popupContent = (ColorPalette)super.getPopupContent();

            // make sure listeners and geometry are only created once
            if (!initialized) {
                final VBox paletteBox = (VBox)popupContent.getChildrenUnmodifiable().get(0);
                final StackPane hoverSquare = (StackPane)popupContent.getChildrenUnmodifiable().get(1); // ColorSquare
                final Rectangle hoverRect = (Rectangle)hoverSquare.getChildren().get(0); // ColorSquare
                final GridPane grid = (GridPane)paletteBox.getChildren().get(0); // ColorPalette
                final StackPane colorSquare = (StackPane)grid.getChildren().get(grid.getChildren().size()-1); // ColorSquare
                final Rectangle colorRect = (Rectangle)colorSquare.getChildren().get(0);

                // set fill color of original color rectangle to transparent
                // (can't be set to red line gradient because ComboBoxBase<Color> tries to cast it to Color)
                colorRect.setFill(Color.TRANSPARENT);
                // put another rectangle with red line on top of it
                colorSquare.getChildren().add(new Rectangle(colorRect.getWidth(), colorRect.getHeight(), RED_LINE));
                // show red line gradient also in hover rectangle when the transparent color is selected
                hoverRect.fillProperty().addListener((o, oldVal, newVal) -> {
                    if (newVal.equals(Color.TRANSPARENT))
                        hoverRect.setFill(RED_LINE);
                });

                initialized = true;
            }

            return popupContent;
        }
    }
}