Панель растет в неправильном направленииJAVA

Программисты JAVA общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 Панель растет в неправильном направлении

Сообщение Anonymous »

Я пытаюсь изменить размер узла, перетаскивая его пользовательскую границу, и это работает нормально. Однако родительская панель не увеличивается в одном направлении при перетаскивании верхней и левой границ. Вот демо, изначально у меня есть собственный класс рамки:

Код: Выделить всё

class Outline extends Group {

private final Path[] paths;
private final Node node;
private final DoubleProperty width;

public Outline(@NotNull Node node, double width) {
this.node = node;
this.width = new SimpleDoubleProperty(width);
paths = new Path[]{
createBorder(BorderLine.LEFT),
createBorder(BorderLine.TOP),
createBorder(BorderLine.RIGHT),
createBorder(BorderLine.BOTTOM)
};

setManaged(false);
getChildren().addAll(paths);
}

@NotNull
private Path createBorder(@NotNull BorderLine borderLine) {
MoveTo moveTo = new MoveTo();
LineTo lineTo = new LineTo();

applyBounds(borderLine, node.getLayoutBounds(), moveTo, lineTo);
node.boundsInParentProperty().addListener((observable, oldValue, newValue) ->
applyBounds(borderLine, newValue, moveTo, lineTo));

Path path = new Path(moveTo, lineTo);
path.strokeWidthProperty().bind(width);
return path;
}

private void applyBounds(@NotNull BorderLine borderLine,
Bounds bounds,
MoveTo moveTo,
LineTo lineTo) {
switch (borderLine) {
case LEFT -> {
moveTo.setX(bounds.getMinX());
moveTo.setY(bounds.getMinY());
lineTo.setX(bounds.getMinX());
lineTo.setY(bounds.getMaxY());
}
case TOP -> {
moveTo.setX(bounds.getMinX());
moveTo.setY(bounds.getMinY());
lineTo.setX(bounds.getMaxX());
lineTo.setY(bounds.getMinY());
}
case RIGHT -> {
moveTo.setX(bounds.getMaxX());
moveTo.setY(bounds.getMinY());
lineTo.setX(bounds.getMaxX());
lineTo.setY(bounds.getMaxY());
}
case BOTTOM -> {
moveTo.setX(bounds.getMinX());
moveTo.setY(bounds.getMaxY());
lineTo.setX(bounds.getMaxX());
lineTo.setY(bounds.getMaxY());
}
}
}

public Path[] getPaths() {
return paths;
}

public enum BorderLine {
LEFT, RIGHT, TOP, BOTTOM;
}
}
Далее у меня есть класс ResizableNode, который пытается ограничить себя предыдущей границей, а также добавляет изменение размера путем перетаскивания логики к границе:

Код: Выделить всё

class ResizableNode extends Pane {

public final double MIN_POSSIBLE_WIDTH = 10;
public final double MIN_POSSIBLE_HEIGHT = 10;

private final Rectangle nodeArea = new Rectangle(140, 140, Color.TRANSPARENT);

public ResizableNode() {
Outline outline = new Outline(nodeArea, 4);

makeResizeable(BorderLine.LEFT, outline.getPaths()[0]);
makeResizeable(BorderLine.TOP, outline.getPaths()[1]);
makeResizeable(BorderLine.RIGHT, outline.getPaths()[2]);
makeResizeable(BorderLine.BOTTOM, outline.getPaths()[3]);

Pane nodeAreaPane = new Pane(nodeArea, outline);
nodeAreaPane.setBackground(Background.fill(Color.RED));

getChildren().addAll(nodeAreaPane);
}

private void makeResizeable(@NotNull BorderLine borderLine, @NotNull Path path) {
final AtomicReference initialX = new AtomicReference(0.0),
initialY = new AtomicReference(0.0),
initialCoordX = new AtomicReference(0.0),
initialCoordY = new AtomicReference(0.0),
initialWidth = new AtomicReference(0.0),
initialHeight = new AtomicReference(0.0);

path.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> {
initialX.set(event.getX());
initialY.set(event.getY());
initialCoordX.set(nodeArea.getX());
initialCoordY.set(nodeArea.getY());
initialWidth.set(nodeArea.getWidth());
initialHeight.set(nodeArea.getHeight());
});

switch (borderLine) {
case LEFT ->  {
path.setCursor(Cursor.E_RESIZE);
path.addEventFilter(MouseEvent.MOUSE_DRAGGED, event -> {
double deltaX = (event.getX() - initialX.get()) * 1, newWidth = initialWidth.get() - deltaX;
if (newWidth < MIN_POSSIBLE_WIDTH) {
event.consume();
return;
}
nodeArea.setWidth(newWidth);
nodeArea.setX(initialCoordX.get() + deltaX);
event.consume();
});
}
case TOP -> {
path.setCursor(Cursor.S_RESIZE);
path.addEventFilter(MouseEvent.MOUSE_DRAGGED, event -> {
double deltaY = (initialY.get() - event.getY()) * 1, newHeight = initialHeight.get() + deltaY;
if (newHeight < MIN_POSSIBLE_HEIGHT) {
event.consume();
return;
}
nodeArea.setHeight(newHeight);
nodeArea.setY(initialCoordY.get() - deltaY);
event.consume();
});
}
case RIGHT -> {
path.setCursor(Cursor.E_RESIZE);
path.addEventFilter(MouseEvent.MOUSE_DRAGGED, event -> {
double deltaX = (-initialX.get() + event.getX()) * 1, newWidth = initialWidth.get() + deltaX;
if (newWidth < MIN_POSSIBLE_WIDTH) {
event.consume();
return;
}
nodeArea.setWidth(newWidth);
event.consume();
});
}
case BOTTOM -> {
path.setCursor(Cursor.S_RESIZE);
path.addEventFilter(MouseEvent.MOUSE_DRAGGED, event -> {
double deltaY = (event.getY() - initialY.get()) * 1, newHeight = initialHeight.get() + deltaY;
if (newHeight < MIN_POSSIBLE_HEIGHT) {
event.consume();
return;
}
nodeArea.setHeight(newHeight);
event.consume();
});
}
}
}

}
Прямоугольник nodeArea и граница работают нормально при изменении размера путем перетаскивания, однако nodeAreaPane увеличивается в другом направлении при перетаскивании слева или сверху. Вот снимок после изменения размера узла:
Изображение

Вот полная демонстрация:

Код: Выделить всё

import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.scene.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import org.jetbrains.annotations.NotNull;

import java.util.concurrent.atomic.AtomicReference;

import static com.tranquilbs.Outline.BorderLine;

public class ResizableNodeDemo extends Application {

@Override
public void start(Stage primaryStage) {
Pane root = new StackPane(new ResizableNode());
root.setPadding(new Insets(100));

primaryStage.setTitle("ResizableNodeDemo");
primaryStage.setScene(new Scene(root, 400, 400));
primaryStage.show();
}

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

class ResizableNode extends Pane {

public final double MIN_POSSIBLE_WIDTH = 10;
public final double MIN_POSSIBLE_HEIGHT = 10;

private final Rectangle nodeArea = new Rectangle(140, 140, Color.TRANSPARENT);

public ResizableNode() {
Outline outline = new Outline(nodeArea, 4);

makeResizeable(BorderLine.LEFT, outline.getPaths()[0]);
makeResizeable(BorderLine.TOP, outline.getPaths()[1]);
makeResizeable(BorderLine.RIGHT, outline.getPaths()[2]);
makeResizeable(BorderLine.BOTTOM, outline.getPaths()[3]);

Pane nodeAreaPane = new Pane(nodeArea, outline);
nodeAreaPane.setBackground(Background.fill(Color.RED));

getChildren().addAll(nodeAreaPane);
}

private void makeResizeable(@NotNull BorderLine borderLine, @NotNull Path path) {
final AtomicReference initialX = new AtomicReference(0.0),
initialY = new AtomicReference(0.0),
initialCoordX = new AtomicReference(0.0),
initialCoordY = new AtomicReference(0.0),
initialWidth = new AtomicReference(0.0),
initialHeight = new AtomicReference(0.0);

path.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> {
initialX.set(event.getX());
initialY.set(event.getY());
initialCoordX.set(nodeArea.getX());
initialCoordY.set(nodeArea.getY());
initialWidth.set(nodeArea.getWidth());
initialHeight.set(nodeArea.getHeight());
});

switch (borderLine) {
case LEFT -> {
path.setCursor(Cursor.E_RESIZE);
path.addEventFilter(MouseEvent.MOUSE_DRAGGED, event -> {
double deltaX = (event.getX() - initialX.get()) * 1, newWidth = initialWidth.get() - deltaX;
if (newWidth < MIN_POSSIBLE_WIDTH) {
event.consume();
return;
}
nodeArea.setWidth(newWidth);
nodeArea.setX(initialCoordX.get() + deltaX);
event.consume();
});
}
case TOP -> {
path.setCursor(Cursor.S_RESIZE);
path.addEventFilter(MouseEvent.MOUSE_DRAGGED, event -> {
double deltaY = (initialY.get() - event.getY()) * 1, newHeight = initialHeight.get() + deltaY;
if (newHeight < MIN_POSSIBLE_HEIGHT) {
event.consume();
return;
}
nodeArea.setHeight(newHeight);
nodeArea.setY(initialCoordY.get() - deltaY);
event.consume();
});
}
case RIGHT -> {
path.setCursor(Cursor.E_RESIZE);
path.addEventFilter(MouseEvent.MOUSE_DRAGGED, event -> {
double deltaX = (-initialX.get() + event.getX()) * 1, newWidth = initialWidth.get() + deltaX;
if (newWidth <  MIN_POSSIBLE_WIDTH) {
event.consume();
return;
}
nodeArea.setWidth(newWidth);
event.consume();
});
}
case BOTTOM -> {
path.setCursor(Cursor.S_RESIZE);
path.addEventFilter(MouseEvent.MOUSE_DRAGGED, event -> {
double deltaY = (event.getY() - initialY.get()) * 1, newHeight = initialHeight.get() + deltaY;
if (newHeight < MIN_POSSIBLE_HEIGHT) {
event.consume();
return;
}
nodeArea.setHeight(newHeight);
event.consume();
});
}
}
}

}

class Outline extends Group {

private final Path[] paths;
private final Node node;
private final DoubleProperty width;

public Outline(@NotNull Node node, double width) {
this.node = node;
this.width = new SimpleDoubleProperty(width);
paths = new Path[]{
createBorder(BorderLine.LEFT),
createBorder(BorderLine.TOP),
createBorder(BorderLine.RIGHT),
createBorder(BorderLine.BOTTOM)
};

setManaged(false);
getChildren().addAll(paths);
}

@NotNull
private Path createBorder(@NotNull BorderLine borderLine) {
MoveTo moveTo = new MoveTo();
LineTo lineTo = new LineTo();

applyBounds(borderLine, node.getLayoutBounds(), moveTo, lineTo);
node.boundsInParentProperty().addListener((observable, oldValue, newValue) ->
applyBounds(borderLine, newValue, moveTo, lineTo));

Path path = new Path(moveTo, lineTo);
path.strokeWidthProperty().bind(width);
return path;
}

private void applyBounds(@NotNull BorderLine borderLine, Bounds bounds, MoveTo moveTo, LineTo lineTo) {
switch (borderLine) {
case LEFT -> {
moveTo.setX(bounds.getMinX());
moveTo.setY(bounds.getMinY());
lineTo.setX(bounds.getMinX());
lineTo.setY(bounds.getMaxY());
}
case TOP -> {
moveTo.setX(bounds.getMinX());
moveTo.setY(bounds.getMinY());
lineTo.setX(bounds.getMaxX());
lineTo.setY(bounds.getMinY());
}
case RIGHT -> {
moveTo.setX(bounds.getMaxX());
moveTo.setY(bounds.getMinY());
lineTo.setX(bounds.getMaxX());
lineTo.setY(bounds.getMaxY());
}
case BOTTOM -> {
moveTo.setX(bounds.getMinX());
moveTo.setY(bounds.getMaxY());
lineTo.setX(bounds.getMaxX());
lineTo.setY(bounds.getMaxY());
}
}
}

public Path[] getPaths() {
return paths;
}

public enum BorderLine {
LEFT, RIGHT, TOP, BOTTOM;
}
}
У меня есть два ограничения на работу решения в моем приложении:

[*]

Код: Выделить всё

nodeAreaPane
должен иметь тип Pane (не подкласс).
[*]ResizableNode должен иметь суперкласс типа Pane (не подкласс).

Любая помощь приветствуется, заранее спасибо.

Подробнее здесь: https://stackoverflow.com/questions/791 ... -direction
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «JAVA»