Java实现鼠标中心点缩放后选物坐标错位及绘图复位问题
解决方案:围绕鼠标缩放+坐标匹配修复
核心问题分析
- 原实现中每次
paintComponent依赖实时鼠标位置做变换,导致repaint时鼠标位置变化就会让绘图复位。 - 鼠标点击坐标转换未考虑平移偏移,导致缩放后选中位置错位。
- 错误处理了
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
相关产品推荐
相关产品推荐

