缩放Canvas后调整ScrollPane内部尺寸以消除空白区域
问题描述
实现了点击按钮缩放Canvas游戏区域的功能,整体运行正常,但缩放后ScrollPane中原Canvas所在位置出现空白区域。尝试多种调整ScrollPane尺寸的方法均无效,希望让ScrollPane的内部区域随Canvas尺寸变化,消除空白区域。
现有代码
Java代码
public class GameView { @FXML public Canvas gameField; @FXML public ScrollPane scrollPane; public void doZoomOut() { Scale scale = new Scale(gameField.getScaleX() * 0.8, gameField.getScaleY() * 0.8); gameField.getTransforms().add(scale); scrollPane.resize(gameField.getWidth(), gameField.getHeight()); //无效 scrollPane.setPrefViewportWidth(gameField.getWidth()); //无效 scrollPane.setPrefViewportHeight(gameField.getHeight()); //无效 //Fit to Width/Height也无效 scrollPane.setPrefWidth(gameField.getWidth()); //无效 } }
FXML代码
<ScrollPane fx:id="scrollPane" fitToHeight="true" fitToWidth="true" style="-fx-background-color: transparent;" stylesheets="@../../../style.css"> <styleClass> <String fx:value="scroll-bar" /> <String fx:value="corner" /> <String fx:value="thumb" /> </styleClass> <Canvas fx:id="gameField" height="700.0" width="1200.0" /> </ScrollPane>
问题截图

解决方案
问题根源:你用Transforms.add(Scale)只是对Canvas做了视觉层面的缩放,但Canvas本身的width和height属性并没有改变,ScrollPane识别的内容区域还是Canvas的原始尺寸,所以缩放后会出现空白。
方法一:用Group包裹Canvas(推荐)
ScrollPane的内容如果是Group,Group会自动根据子节点的变换(比如Scale)调整自身边界,让ScrollPane能正确感知内容的实际大小,自动适配消除空白。
修改FXML代码
<ScrollPane fx:id="scrollPane" fitToHeight="true" fitToWidth="true" style="-fx-background-color: transparent;" stylesheets="@../../../style.css"> <styleClass> <String fx:value="scroll-bar" /> <String fx:value="corner" /> <String fx:value="thumb" /> </styleClass> <!-- 用Group包裹Canvas --> <Group> <Canvas fx:id="gameField" height="700.0" width="1200.0" /> </Group> </ScrollPane>
原Java缩放逻辑无需额外修改,缩放后Group会自动更新自身边界,ScrollPane会跟着调整内部区域,空白自然消失。
方法二:直接修改Canvas尺寸并适配绘图缩放
如果不想用Group,可以直接修改Canvas的实际尺寸,同时在绘图时应用缩放比例,让ScrollPane识别到Canvas的新尺寸:
修改Java代码
public class GameView { @FXML public Canvas gameField; @FXML public ScrollPane scrollPane; // 记录当前缩放比例 private double scaleX = 1.0; private double scaleY = 1.0; // 记录Canvas原始尺寸 private final double originalWidth = 1200.0; private final double originalHeight = 700.0; public void doZoomOut() { scaleX *= 0.8; scaleY *= 0.8; // 修改Canvas的实际尺寸 gameField.setWidth(originalWidth * scaleX); gameField.setHeight(originalHeight * scaleY); // 重新绘制内容时需应用缩放比例 redrawGameField(); } private void redrawGameField() { GraphicsContext gc = gameField.getGraphicsContext2D(); gc.clearRect(0, 0, gameField.getWidth(), gameField.getHeight()); // 应用缩放后再绘图 gc.save(); gc.scale(scaleX, scaleY); // 这里写你的游戏绘图逻辑,比如: // gc.fillRect(100, 100, 50, 50); gc.restore(); } }
这种方法需要同步维护缩放比例和Canvas尺寸,绘图时手动适配缩放,适合需要精确控制Canvas尺寸的场景。
内容的提问来源于stack exchange,提问作者unclled
相关产品推荐
相关产品推荐

