You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java实现鼠标中心点缩放后选物坐标错位及绘图复位问题

解决方案:围绕鼠标缩放+坐标匹配修复

核心问题分析

  1. 原实现中每次paintComponent依赖实时鼠标位置做变换,导致repaint时鼠标位置变化就会让绘图复位。
  2. 鼠标点击坐标转换未考虑平移偏移,导致缩放后选中位置错位。
  3. 错误处理了Graphics对象(直接dispose系统传入的实例)。

步骤1:维护视图状态变量

在控制器(或绘图面板)中新增两个变量,记录视图的平移偏移量,配合现有缩放比例使用:

// 视图相对于原始世界坐标的平移偏移
private double offsetX = 0;
private double offsetY = 0;
// 保留原有的缩放比例变量
private double scaleZoom = 1.0;

// 提供getter方法供视图调用
public double getOffsetX() { return offsetX; }
public double getOffsetY() { return offsetY; }
public double getScaleZoom() { return scaleZoom; }

步骤2:修正鼠标滚轮缩放逻辑

缩放时必须计算偏移量,保证鼠标点在缩放前后对应同一个世界坐标,避免视图跳变:

@Override
public void mouseWheelMoved(MouseWheelEvent evt) {
    double zoomFactor = Math.pow(1.1, evt.getScrollAmount());
    Point mouseScreenPos = evt.getPoint();
    
    // 1. 将当前鼠标屏幕坐标转换为世界坐标(缩放前)
    double worldX = (mouseScreenPos.x - offsetX) / scaleZoom;
    double worldY = (mouseScreenPos.y - offsetY) / scaleZoom;
    
    // 2. 更新缩放比例
    if (evt.getWheelRotation() > 0) {
        scaleZoom *= zoomFactor;
    } else {
        scaleZoom /= zoomFactor;
    }
    
    // 3. 重新计算偏移量,让鼠标点仍对应原来的世界坐标
    offsetX = mouseScreenPos.x - worldX * scaleZoom;
    offsetY = mouseScreenPos.y - worldY * scaleZoom;
    
    drawingPanel.repaint();
}

步骤3:修正paintComponent绘制逻辑

不再依赖实时鼠标位置,改用维护的offset和scale做变换,同时正确处理Graphics2D对象:

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    if (mainWindow == null) return;

    // 创建Graphics2D副本,避免修改系统传入的实例
    Graphics2D g2d = (Graphics2D) g.create();
    
    // 应用平移+缩放变换
    g2d.translate(offsetX, offsetY);
    g2d.scale(scaleZoom, scaleZoom);

    // 直接使用原始尺寸绘制,变换已处理缩放和平移
    MainDrawer mainDrawer = new MainDrawer(mainWindow.controller, this.chaletDrawer, intialDimension);
    mainDrawer.draw(g2d);

    // 释放自己创建的Graphics2D实例
    g2d.dispose();
}

步骤4:修正鼠标点击坐标转换

加入平移偏移量的计算,将屏幕坐标正确转换为原始世界坐标:

@Override
public void mousePressed(MouseEvent evt) {
    Point mouseScreenPos = evt.getPoint();
    double scale = controller.getScaleZoom();
    double offsetX = controller.getOffsetX();
    double offsetY = controller.getOffsetY();

    // 1. 将屏幕坐标转换为世界坐标
    double worldX = (mouseScreenPos.x - offsetX) / scale;
    double worldY = (mouseScreenPos.y - offsetY) / scale;

    // 2. 转换为元素选中逻辑所需坐标(保留原有的-100和/4处理)
    int unscaledX = (int) ((worldX - 100) / 4);
    int unscaledY = (int) ((worldY - 100) / 4);

    System.out.println("Unscaled Mouse Point: (" + unscaledX + ", " + unscaledY + ")");

    controller.switchSelectionStatusAccessoire(unscaledX, unscaledY, viewType);
    drawingPanel.repaint();
}

内容的提问来源于stack exchange,提问作者Frédérique Soulière

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 10:45:00