如果通過Shape.subtract(...)
創建Shape
,則沒有任何機制可以在事後更改其屬性(用於更改用於創建它的形狀的邊界)。您必須從其父項中移除該形狀,重新計算矩形和剪輯,重新計算形狀,並將新形狀重新添加到場景中。
在這裏使用Path
可能會更好,因此您可以在不創建新形狀的情況下操縱座標。在外部(填充部分)周圍繞一個方向(順時針方向),然後繞內部(透明部分)繞另一個方向(逆時針)移動。所得到的形狀將與從外部減去內部相同。初始設置可能需要更多的代碼,但是您可以根據需要操作座標。
我不確定你正在尋找什麼功能,但是下面允許你通過點擊和拖動它來拖動內部部分,並允許你通過點擊和拖動外部來拖動整個窗口一部分。你應該足夠了解你需要什麼。我沒有在你的例子中包含好的圓角,但你可以很容易地實現那些使用ArcTo
路徑元素。
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ObservableDoubleValue;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.ClosePath;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.PathElement;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class TransparentRectangle extends Application {
@Override
public void start(Stage stage) {
Pane root = new Pane();
PathElement start = new MoveTo(0, 0);
PathElement outerTopRight = createBoundLineTo(root.widthProperty(), 0);
PathElement outerBottomRight = createBoundLineTo(root.widthProperty(), root.heightProperty());
PathElement outerBottomLeft = createBoundLineTo(0, root.heightProperty());
PathElement outerTopLeft = new LineTo(0, 0);
DoubleProperty innerLeft = new SimpleDoubleProperty(20);
DoubleProperty innerTop = new SimpleDoubleProperty(20);
DoubleBinding innerRight = innerLeft.add(180);
DoubleBinding innerBottom = innerTop.add(180);
PathElement innerTopLeft = createBoundLineTo(innerLeft, innerTop);
PathElement innerTopRight = createBoundLineTo(innerRight, innerTop);
PathElement innerBottomRight = createBoundLineTo(innerRight, innerBottom);
PathElement innerBottomLeft = createBoundLineTo(innerLeft, innerBottom);
Path path = new Path(
start, outerTopRight,
outerBottomRight, outerBottomLeft,
outerTopLeft,
innerTopLeft, innerBottomLeft,
innerBottomRight, innerTopRight,
innerTopLeft, new ClosePath()
);
path.setFill(Color.GRAY);
path.setStroke(Color.TRANSPARENT);
root.getChildren().add(path);
class Wrapper<T> { T value ; }
Wrapper<Point2D> mouseLocation = new Wrapper<>();
// Drag on gray portion of path - move entire window:
path.setOnDragDetected(event -> {
mouseLocation.value = new Point2D(event.getScreenX(), event.getScreenY());
});
path.setOnMouseDragged(event -> {
if (mouseLocation.value != null) {
stage.setX(stage.getX() + event.getScreenX() - mouseLocation.value.getX());
stage.setY(stage.getY() + event.getScreenY() - mouseLocation.value.getY());
mouseLocation.value = new Point2D(event.getScreenX(), event.getScreenY());
}
});
path.setOnMouseReleased(event -> mouseLocation.value = null);
// Drag on scene (i.e not on path, i.e. on transparent part) - move transparent part
root.setOnDragDetected(event -> {
mouseLocation.value = new Point2D(event.getScreenX(), event.getScreenY());
});
root.setOnMouseDragged(event -> {
if (mouseLocation.value != null) {
innerLeft.set(innerLeft.get() + event.getScreenX() - mouseLocation.value.getX());
innerTop.set(innerTop.get() + event.getScreenY() - mouseLocation.value.getY());
mouseLocation.value = new Point2D(event.getScreenX(), event.getScreenY());
}
});
root.setOnMouseReleased(event -> mouseLocation.value = null);
// No close button on a transparent window, so exit on double click:
root.setOnMouseClicked(event -> {
if (event.getClickCount() == 2) Platform.exit();
event.consume();
});
Scene scene = new Scene(root, 800, 600);
scene.setFill(Color.TRANSPARENT);
stage.initStyle(StageStyle.TRANSPARENT);
stage.setScene(scene);
stage.show();
}
private PathElement createBoundLineTo(ObservableDoubleValue x, ObservableDoubleValue y) {
LineTo lineTo = new LineTo();
lineTo.xProperty().bind(x);
lineTo.yProperty().bind(y);
return lineTo ;
}
private PathElement createBoundLineTo(double fixedX, ObservableDoubleValue y) {
LineTo lineTo = new LineTo();
lineTo.setX(fixedX);
lineTo.yProperty().bind(y);
return lineTo ;
}
private PathElement createBoundLineTo(ObservableDoubleValue x, double fixedY) {
LineTo lineTo = new LineTo();
lineTo.setY(fixedY);
lineTo.xProperty().bind(x);
return lineTo ;
}
public static void main(String[] args) {
launch(args);
}
}
不錯的做法,非常感謝。我現在可以向前編碼,但有兩點:1.如何調整透明區域的大小2.我可以拖動透明區域的區域很難獲得。我怎樣才能讓它變大? – 2014-10-08 13:39:56
爲了使內部區域可調整大小,爲'innerRight'和'innerBottom'創建常規屬性(不要將它們綁定到innerLeft和innerTop)。然後你可以獨立操縱它們,從而改變尺寸。我不太清楚第二個問題,但在這個例子中,總面積只是由場景的大小('new Scene(root,800,600)')定義的。 – 2014-10-08 13:43:50
對於第一個問題,我會嘗試一下,第二個問題是,我將內部透明度更改爲藍色,以查看它是如何工作的。透明,很難拖動inne區域。 – 2014-10-08 13:48:37