答案 0 :(得分:1)
解决方案有点像黑客,但它避免使用私有API。
这些是必需的步骤:
ColorPicker
时显示的弹出窗口控件。一旦我们有弹出窗口,我们将使用查找来获取方形颜色集: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);
}
}
答案 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;
}
}
}