JavaFX Circle и ImageView

Мне нужно использовать javaFX2, чтобы сделать следующее:

1-) Загрузите изображение и отобразите его с помощью imageView. [ОК]

2-) Щелкните правой кнопкой мыши и выберите опцию «Добавить узел», и на экране появится черный кружок, и вы можете перетащить его в любое место изображения. [ОК]

3-) Используйте колесо прокрутки для мыши, чтобы увеличить или уменьшить изображение, создавая «ощущение масштабирования» на изображении. [ОК]

3.1-) Однако каждый раз, когда я масштабирую изображение, я хочу, чтобы мои круги следовали пропорциям масштаба, что означает, что они не могут оставаться в одном и том же положении на экране. [Понятия не имею]

Моя проблема - это пункт номер 3.1, потому что я не знаю, как перемещать свои круги на изображении таким образом, чтобы они могли казаться на месте изображения после увеличения или уменьшения масштаба. Я пытался использовать методы setCenterX() и setCenterY(), а также методы перехода, но не смог найти способ сделать это.

Код для загрузки моего изображения:

@FXML
ImageView bluePrintView;
@FXML
private void loadBtnAction(ActionEvent event) {
    FileChooser fileChooser = new FileChooser();
    //Show open file dialog
    File file = fileChooser.showOpenDialog(null);
    /*Load Image*/
    System.out.println(file.getPath());
        Image img = new Image("file:" + file.getPath());
        bluePrintView.setImage(img);
        bluePrintView.setFitHeight(scrollPaneImage.getHeight());
        bluePrintView.setFitWidth(scrollPaneImage.getWidth());
        bluePrintView.setSmooth(true);
        bluePrintView.setScaleX(1);
        bluePrintView.setScaleY(1);
    event.consume();

}

Код для масштабирования ImageView:

@FXML
private void zoomAction(ScrollEvent event) {
    if (event.getDeltaY() < 0) {
        if (bluePrintView.getScaleX() > 0.8 && bluePrintView.getScaleY() > 0.8) {
            bluePrintView.setScaleX(bluePrintView.getScaleX() - 0.1);
            bluePrintView.setScaleY(bluePrintView.getScaleY() - 0.1);
            System.out.println("ImageView(X,Y): "+bluePrintView.getFitHeight()+" "+bluePrintView.getFitWidth());
            System.out.println("Image(X,Y): "+bluePrintView.getImage().getHeight()+" "+bluePrintView.getImage().getWidth());
            if (!nodeList.isEmpty()) {
                for (int i = 0; i < nodeList.size(); i++) {
                       nodeList.get(i).zoomOutNode(bluePrintView.getFitHeight(),bluePrintView.getFitWidth());
                }
            }
        }
    } else {
        bluePrintView.setScaleX(bluePrintView.getScaleX() + 0.1);
        bluePrintView.setScaleY(bluePrintView.getScaleY() + 0.1);
        System.out.println("ImageView(X,Y): "+bluePrintView.getFitHeight()+" "+bluePrintView.getFitWidth());
        System.out.println("Image(X,Y): "+bluePrintView.getImage().getHeight()+" "+bluePrintView.getImage().getWidth());
        if (!nodeList.isEmpty()) {
            for (int i = 0; i < nodeList.size(); i++) {
                  nodeList.get(i).zoomInNode(bluePrintView.getFitHeight(),bluePrintView.getFitWidth());
            }
        }
    }
    event.consume();
}

Код для создания круга и выполнения некоторых операций:

public class NodeShape {

final Circle node = new Circle();
double axisX = 0, axisY = 0;

public Circle createNode(Group rootGroup, double axisX, double axisY, double radius, String color) {
    node.setCenterX(axisX);
    node.setCenterY(axisY);
    node.setRadius(radius);
    node.fillProperty().setValue(Paint.valueOf(color));
    System.out.println(node.getTranslateX() + " " + node.getTranslateY());
    System.out.println("getCenter: " + node.getCenterX() + " " + node.getCenterY());
    rootGroup.getChildren().add(node);
    node.setOnMouseDragged(new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent t) {
            node.setCenterX(t.getX());
            node.setCenterY(t.getY());
            NodeShape.this.axisX = t.getX();
            NodeShape.this.axisY = t.getY();
            System.out.println("Circle getTranslate: " + node.getTranslateX() + " " + node.getTranslateY());
            System.out.println("Circle getCenter: " + node.getCenterX() + " " + node.getCenterY());
            t.consume();
        }
    });
    node.setOnMouseClicked(new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent t) {
            if (t.getButton().equals(MouseButton.PRIMARY)) {
                if (t.getClickCount() == 2) {
                    node.setVisible(false);
                    node.setDisable(true);
                }else if(t.getClickCount() == 1){
                    System.out.println("Circle Position: "+node.getCenterX()+" "+node.getCenterY());
                }
            }
            t.consume();
        }
    });
    node.setOnScroll(new EventHandler<ScrollEvent>() {
        @Override
        public void handle(ScrollEvent t) {
            if (t.getDeltaY() < 0) {
                if (node.getScaleX() > 0.8 && node.getScaleY() > 0.8) {
                    node.setScaleX(node.getScaleX() - 0.1);
                    node.setScaleY(node.getScaleY() - 0.1);
                }
            } else {
                node.setScaleX(node.getScaleX() + 0.1);
                node.setScaleY(node.getScaleY() + 0.1);
            }
            t.consume();
        }
    });
    return node;
}

public void zoomInNode(double imgHeight, double imgWidth) {
    node.setCenterX(0.1);
    //node.setTranslateY(imgHeight/1100 + 10);
    //node.setCenterX(node.getCenterX() + Math.abs(axisX - node.getRadius()));
    //node.setCenterY(node.getCenterY() + Math.abs(axisY - node.getRadius()));
    System.out.println("Circle getCenter: " + node.getCenterX() + " " + node.getCenterY());
    System.out.println("Circle getCenter: " + node.getTranslateX()+ " " + node.getTranslateY());
}

public void zoomOutNode(double imgHeight, double imgWidth) {
    node.setCenterX(-0.1);
 //   node.setTranslateY(imgHeight/200 - 10);
    //node.setCenterX(node.getCenterX() - Math.abs(axisX - node.getRadius()));
    //node.setCenterY(node.getCenterY() - Math.abs(axisY - node.getRadius()));
    System.out.println("Circle getCenter: " + node.getCenterX() + " " + node.getCenterY());
    System.out.println("Circle getCenter: " + node.getTranslateX()+ " " + node.getTranslateY());
}

public void zoomResetNode() {
    node.setCenterX(axisX);
    node.setCenterY(axisY);
}}

Мой код файла FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" fx:id="rootPane" pickOnBounds="true" prefHeight="420.0" prefWidth="817.0" snapToPixel="true" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="blueprints.NewSonarViewController">
  <children>
    <Group id="Group" layoutX="0.0" layoutY="0.0">
      <children>
        <ScrollPane fx:id="scrollPaneImage" layoutX="0.0" layoutY="0.0" prefHeight="420.0" prefWidth="817.0">
          <content>
            <Group id="Group" fx:id="rootGroup">
              <children>
                <ImageView fx:id="bluePrintView" cache="false" fitHeight="419.0" fitWidth="816.0" layoutX="0.0" layoutY="0.0" onMouseClicked="#zoomResetAction" onScroll="#zoomAction" pickOnBounds="true" preserveRatio="false" rotate="0.0" visible="true" />
              </children>
            </Group>
          </content>
          <contextMenu>
            <ContextMenu>
              <items>
                <MenuItem mnemonicParsing="false" onAction="#loadBtnAction" text="Load Image" />
                <MenuItem mnemonicParsing="false" onAction="#addSynk" text="Add Synk" />
                <MenuItem mnemonicParsing="false" onAction="#addNode" text="AddNode" />
              </items>
            </ContextMenu>
          </contextMenu>
        </ScrollPane>
      </children>
    </Group>
  </children>
</AnchorPane>

person tsukanomon    schedule 27.08.2013    source источник
comment
поэтому вы хотите масштабировать изображение без масштабирования круга, и после масштабирования вы хотите иметь положение круга относительно масштабированного изображения, поэтому, если круг находится в центре изображения, круг не должен двигаться при изменении масштаба изображения, это правильно?   -  person Eeliya    schedule 28.08.2013


Ответы (2)


Моя идея состоит в том, что вы добавляете ImageView и Circle к вашему rootGroup, а затем применяете шкалу к rootGroup. Смотрите мой пример ниже.

Вид:

<AnchorPane id="AnchorPane" fx:id="rootPane" pickOnBounds="true" prefHeight="420.0" prefWidth="817.0" snapToPixel="true" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="javafx.scale.Controller">
  <children>
    <Group id="Group" layoutX="0.0" layoutY="0.0" onScroll="#scrolling">
      <children>
        <ScrollPane fx:id="scrollPaneImage" layoutX="0.0" layoutY="0.0" prefHeight="420.0" prefWidth="817.0">
          <content>
            <Group id="Group" fx:id="rootGroup">
            </Group>
          </content>
        </ScrollPane>
      </children>
    </Group>
  </children>
</AnchorPane>

Контроллер:

public class Controller {

    @FXML
    private Group rootGroup;
    private Group zoomGroup;

    private double scale = 1;

    public void initialize() {
        zoomGroup = new Group();

        Image image = new Image(getClass().getResourceAsStream("image.jpg"));
        ImageView imageView = new ImageView(image);
        imageView.setX(50);
        imageView.setY(50);

        Circle circle = new Circle();
        circle.setRadius(20);
        circle.setCenterX(100);
        circle.setCenterY(200);
        circle.setFill(Paint.valueOf("RED"));

        zoomGroup.getChildren().add(imageView);
        zoomGroup.getChildren().add(circle);
        rootGroup.getChildren().add(zoomGroup);
    }

    public void scrolling(ScrollEvent scrollEvent) {
        if (scrollEvent.getDeltaY() > 0) {
            scale += 0.1;
        } else if (scrollEvent.getDeltaY() < 0) {
            scale -= 0.1;
        }
        zoomGroup.setScaleX(scale);
        zoomGroup.setScaleY(scale);
    }
}
person Katona    schedule 28.08.2013
comment
Это работает очень хорошо, однако это дало мне другую проблему: теперь, когда я масштабирую свое изображение, полосы прокрутки панели прокрутки не видят, что группа масштабируется, и из-за этого я не могу перемещаться по масштабированному изображению. Любая работа вокруг? - person tsukanomon; 29.08.2013
comment
@tsukanomon Я обновил контроллер, чтобы решить вашу проблему, но обратите внимание, что прокрутка взаимодействует с панелью прокрутки, которую, я думаю, вы можете решить на основе этот вопрос - person Katona; 29.08.2013
comment
ты чертов гений!!! Действительно работал. БОЛЬШОЕ СПАСИБО!!! И просто, если у вас есть немного времени... не могли бы вы объяснить мне, почему добавление еще одной группы, в данном случае zoomGroup, сработало? - person tsukanomon; 29.08.2013
comment
@tsukanomon Я взял идею из здесь - person Katona; 29.08.2013

Хорошо, если я правильно понял ваш вопрос, этот обходной путь должен решить вашу проблему:

Представьте, что у вас есть изображение шириной и высотой 100*200.

У вас есть круг на изображении в позиции (10,10).

После того, как вы измените масштаб изображения, новая ширина и высота вашего изображения станут 150 * 300.

чтобы вычислить новую позицию круга, просто сделайте это:

newCircleX = (currentCircleX * currentImageWidth) / oldImageWidth;
newCircleY = (currentCircleY * currentImageHeight) / oldImageHeight;

Надеюсь, это поможет.

person Eeliya    schedule 28.08.2013
comment
Следуя вашему примеру, тогда currentCircleX = 10; текущаяширина изображения = 150; старая ширина изображения = 100; Это правильно ? - person tsukanomon; 29.08.2013