【问题标题】:Javafx Image Crop according to hovering mouse positionJavafx 根据鼠标悬停位置裁剪图像
【发布时间】:2021-11-13 14:55:05
【问题描述】:

我正在开发一个追踪程序,将点放置在 X 射线上的解剖点上。我的问题是,我试图放大我的 X 射线图像 (Imageview),而我的鼠标悬停在它上面并显示在另一个 Imageview 中。我希望我的鼠标在它周围创建一个虚拟矩形并在移动时保持在中心并将实时图像传输到其他小Imageview,到目前为止我已经这样做了,但是有一些小故障。我的矩形没有完全按照我的鼠标移动,当我移动到角落时,故障加速,你有什么建议?我正在分享我的错误和代码以澄清所有这些事情。

也许我应该创建一个矩形并将其放置在鼠标位置周围并实时裁剪图像,适合zoomedImageview,并一直显示,但我被困在了这个。

主要问题是,鼠标位置和zoomedImageview的中心位置必须一直重合。

Xray Imageview Fitwidth-height 为 800x800 zoomedImageview Fitwidth-height 为 250x250

public class DrawingController {

        @FXML 
    ImageView xrayImage;
        
         @FXML
    ImageView zoomedImage;

   public void initialize()
    {

   xrayImage.setOnMouseMoved(e -> {    //HOVERING ON XRAY
   
PixelReader reader = XrayImageview.getImage().getPixelReader();   
WritableImage newImage = new WritableImage(reader,

(int) e.getX(),  //x and y is picked according to hovering mouse position
   (int) e.getY(),
   (int) 250,     // 250x250 rectangle is requested.
   (int) 250);

zoomedImage.setImage(newImage);  // Displaying zoomed image

        });
}}

我的 FXML 文件是:

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

<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="913.0" prefWidth="1238.0" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1" fx:controller="main.java.controllers.DrawingController">
   <children>
      <ImageView fitHeight="800.0" fitWidth="800.0" layoutX="418.0" layoutY="33.0" pickOnBounds="true" preserveRatio="true" fx:id="xrayImage">
         <image>
            <Image url="@threatCare.png" />
         </image>
      </ImageView>
      <ImageView fx:id="zoomedImage" fitHeight="250.0" fitWidth="250.0" layoutX="108.0" layoutY="433.0" pickOnBounds="true" preserveRatio="true" />
   </children>
</AnchorPane>

还有主类:

package main.java;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
import main.java.database.DatabaseCreator;

import javax.swing.text.html.ImageView;
import java.awt.*;

public class Runner extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception{
     
        Parent root = FXMLLoader.load(getClass().getResource("../resources/DrawingPanel.fxml"));

        primaryStage.setTitle("TreatCare Software Systems");
         Scene scene = new Scene(root,1200,950);
        primaryStage.setScene(scene);
        primaryStage.setMinWidth(1200);
        primaryStage.setMinHeight(950);
        primaryStage.setMaximized(true);
        primaryStage.setOnCloseRequest( e -> SystemClose());
        primaryStage.show();
    }

    private void SystemClose(){
        System.exit(0);         
    }

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

【问题讨论】:

  • İ 只是想根据我悬停的鼠标位置放大我的图像视图。我认为代码很清楚理解,我不知道你到底在寻找什么对不起我的无知@kleopatra
  • 并且您希望 me 编写样板来重现 您的 问题? *tsss ...请阅读参考的帮助页面并采取相应措施。并在公开展示 java 代码时遵守 java 命名约定。
  • @kleopatra 我刚刚编辑了我的分享,如果你能帮助我,我将不胜感激,这个算法有一些故障,我不知道为什么,我很抱歉我的表达方式

标签: java javafx hover zooming crop


【解决方案1】:

您正在缩放图像,因此您需要根据该缩放转换鼠标坐标。

来自您的 .fxml 文件:

<ImageView fitHeight="800.0" fitWidth="800.0" layoutX="418.0" layoutY="33.0" pickOnBounds="true" preserveRatio="true" fx:id="xrayImage">

该行中有三个属性可以缩放图像:

  • fitWidth="800.0" - 将图像缩放到 800 像素宽
  • fitHeight="800.0" - 将图像缩放到 800 像素高
  • preserveRatio="true" - 覆盖所有缩放,因此图像在两个维度上始终具有相同的比例

所以你需要根据这些乘以你的鼠标坐标:

xrayImage.setOnMouseMoved(e -> {    //HOVERING ON XRAY
    Image image = xrayImage.getImage();

    double x = e.getX();
    double y = e.getY();
    double xScale = (xrayImage.getFitWidth() > 0 ?
        image.getWidth() / xrayImage.getFitWidth() : 1);
    double yScale = (xrayImage.getFitHeight() > 0 ?
        image.getHeight() / xrayImage.getFitHeight() : 1);
    if (xrayImage.isPreserveRatio()) {
        double scale = Math.max(xScale, yScale);
        x *= scale;
        y *= scale;
    } else {
        x *= xScale;
        y *= yScale;
    }

    x = Math.max(0, x - 125);
    y = Math.max(0, y - 125);
    double width = Math.min(image.getWidth() - x, 250);
    double height = Math.min(image.getHeight() - y, 250);

    PixelReader reader = image.getPixelReader();   
    WritableImage newImage = new WritableImage(reader,
        (int) x, (int) y, (int) width, (int) height);

    zoomedImage.setImage(newImage);  // Displaying zoomed image
});

【讨论】:

  • 我不知道如何表达我的喜悦,这就是我要找的人,谢谢。但是如果我想增加缩放量怎么办? @VGR
  • @Özden 由于 zoomedImage 还定义了 fitWidth 和 fitHeight 值,我想您可以将 250 和 125 常量更改为更小的值以放大更多。
  • @Özden “我不知道如何表达我的喜悦” 这就是:stackoverflow.com/help/someone-answers
  • @VGR 我更改了所有数值,但它只会在悬停而不是缩放时导致差异:( ??
  • @Özden 我将 250 更改为 150,将 125 更改为 75,对我来说效果很好。
【解决方案2】:

我向DrawingPanel.fxml 添加了一个窗格。 Pane 的目的是显示裁剪区域的边界(标记):

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

<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.StackPane?>

<AnchorPane prefHeight="913.0" prefWidth="1238.0" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1" 
                                                                            fx:controller="DrawingController">
   <children>
      <StackPane layoutX="418.0" layoutY="33.0">
         <children>
            <ImageView  fitHeight="800.0" fitWidth="800.0" preserveRatio="true" pickOnBounds="true" fx:id="xrayImagePane">
               <image>         
                <Image url="https://www.almanac.com/sites/default/files/image_nodes/cosmos-flower.jpg" />
               </image>
            </ImageView>
            <!-- Stack a Pane over the ImageView. Add the marker to this Pane -->
            <Pane fx:id="markerPane" prefHeight="200.0" prefWidth="200.0" />
         </children>
      </StackPane>
      <ImageView fx:id="croppedImageView" fitHeight="250.0" fitWidth="250.0" layoutX="108.0" layoutY="433.0" pickOnBounds="true" preserveRatio="true" />
   </children>
</AnchorPane>

控制器添加和更新标记并更新裁剪图像。我从VGR's answer 借了一些代码来处理比例,但请注意使用getLayoutBounds() 来计算比例:

import javafx.fxml.FXML;
import javafx.geometry.Bounds;
import javafx.scene.image.*;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;

public class DrawingController {

    @FXML
    ImageView xrayImagePane;
    private Image fullImage;
    private PixelReader reader;

    @FXML
    Pane markerPane;
    private Rectangle marker;

    @FXML
    ImageView croppedImageView;

    private static int ZOOM_WONDOW_SIZE = 250;
    private static Color MARKER_COLOR  = Color.BLUE;

    @FXML
    public void initialize(){

        marker = new Rectangle(0,0, ZOOM_WONDOW_SIZE, ZOOM_WONDOW_SIZE);
        marker.setStroke(MARKER_COLOR);
        marker.setFill(Color.TRANSPARENT);
        marker.setStrokeWidth(3);
        markerPane.getChildren().add(marker);

        fullImage = xrayImagePane.getImage();
        reader = fullImage.getPixelReader();

        markerPane.setOnMouseMoved(e -> {
            updateMarker(e.getX(), e.getY());
            updateZoomImage();
        });
    }

    //update marker location based on mouse location
    private void updateMarker(double x, double y) {
        //use layout bounds because you do not know if the actual size is xrayImagePane.getFitWidth()
        //or fullImage.getWidth()
        Bounds imageViewBounds = xrayImagePane.getLayoutBounds();
        double imageWidth = imageViewBounds.getWidth();
        double newX= Math.max(0, x - ZOOM_WONDOW_SIZE/2 );
        newX =  newX + ZOOM_WONDOW_SIZE >= imageWidth ?  imageWidth - ZOOM_WONDOW_SIZE : newX;

        double imageHeight = imageViewBounds.getHeight();
        double newY = Math.max(0, y - ZOOM_WONDOW_SIZE/2 );
        newY=  newY + ZOOM_WONDOW_SIZE >= imageHeight ?  imageHeight - ZOOM_WONDOW_SIZE : newY;

        marker.setX(newX);
        marker.setY(newY);
    }

    //update zoomed image based on marker and scale
    private void updateZoomImage() {

        //adapted from VGR's answer https://stackoverflow.com/a/69273511/3992939
        double x = marker.getX();
        double y = marker.getY();
        double width = marker.getWidth();
        double height= marker.getHeight();
        //use layout bounds because you do not know if the actual size is xrayImagePane.getFitWidth()
        //or fullImage.getWidth()
        Bounds imageViewBounds = xrayImagePane.getLayoutBounds();

        double xScale = xrayImagePane.getFitWidth() > 0 ?
                            fullImage.getWidth() / imageViewBounds.getWidth() : 1;
        double yScale = xrayImagePane.getFitHeight() > 0 ?
                           fullImage.getHeight() / imageViewBounds.getHeight(): 1;
        if (xrayImagePane.isPreserveRatio()) {
            double scale = Math.min(xScale, yScale);
            x *= scale;
            y *= scale;
            width *= scale;
            height *= scale;
        } else {
            x *= xScale;
            y *= yScale;
            width *= xScale;
            height *= yScale;
        }

        WritableImage croppedImage = new WritableImage(reader,
                (int) x,
                (int) y,
                (int) width,
                (int) height
                );
        croppedImageView.setImage(croppedImage); 
    }
}

使用测试它

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.*;
import javafx.stage.Stage;

public class Runner extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception{

        Parent root = FXMLLoader.load(getClass().getResource("DrawingPanel.fxml"));

        primaryStage.setTitle("TreatCare Software Systems");
         Scene scene = new Scene(root);
        primaryStage.setScene(scene);

        primaryStage.setOnCloseRequest( e -> SystemClose());
        primaryStage.show();
    }

    private void SystemClose(){
        System.exit(0);
    }

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-04
    • 1970-01-01
    • 1970-01-01
    • 2013-05-10
    • 1970-01-01
    相关资源
    最近更新 更多