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

JavaFX文本框窗口调整时被裁剪的问题解决求助

计时器应用TextField布局裁剪问题解决方案

我正在开发一款计时器应用,使用JavaFX实现,但调整窗口大小时,TextField会出现被裁剪的情况(截图显示文本框底部被窗口边缘截断)。虽后续版本会将文本框替换为菜单按钮,但仍希望尽早解决该布局问题。

以下是我的JavaFX代码:

package com.jammin.timetimer;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Arc;
import javafx.scene.shape.ArcType;
import javafx.stage.Stage;
import javafx.util.converter.IntegerStringConverter;

public class HelloApplication extends Application {

    @Override
    public void start(Stage PrimaryStage) {
        //Adds all the necessary elements into the window

        StackPane myStackPane = new StackPane();

        VBox myVBox = new VBox(myStackPane);
        myVBox.setAlignment(Pos.BOTTOM_CENTER);
        // 添加内边距,避免元素贴边被裁剪
        myVBox.setPadding(new Insets(10));
        // 设置StackPane占满VBox剩余空间
        VBox.setVgrow(myStackPane, Priority.ALWAYS);

        HBox myHBox = new HBox(myVBox);
        myHBox.setAlignment(Pos.CENTER);
        // 允许VBox在HBox中填充高度
        HBox.setFillHeight(myVBox, true);

        Scene myScene = new Scene(myHBox, 400,400);

        ImageView myImageView = new ImageView(new Image("file:src/main/resources/img/timer_ticks.png"));
        myImageView.fitHeightProperty().bind(myScene.heightProperty());
        myImageView.fitWidthProperty().bind(myScene.widthProperty());
        myImageView.setPreserveRatio(true);
        myStackPane.getChildren().addAll(myImageView);

        Arc myArc = createArc(myStackPane, myScene);

        TextField myTextField = createTextField(myArc, myScene);

        myVBox.getChildren().add(myTextField);

        PrimaryStage.setScene(myScene);
        PrimaryStage.show();
    }

    //Constructor for my Arc
    public Arc createArc(StackPane myStackPane, Scene myScene){
        Arc myArc = new Arc(100,100,100,100,0,360);
        myArc.setFill(Color.GREEN);
        myArc.setType(ArcType.ROUND);
        myStackPane.getChildren().add(myArc);

       myScene.widthProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observableValue, Number number, Number t1) {
                if (t1.doubleValue() <= myScene.getHeight()*1.05){
                    myArc.setRadiusX(t1.doubleValue()/2.9);
                    myArc.setRadiusY(t1.doubleValue()/2.9);
                }
            }
        });

        myScene.heightProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observableValue, Number number, Number t1) {
                if (t1.doubleValue() <= myScene.getWidth()){
                    myArc.setRadiusX(t1.doubleValue()/2.9);
                    myArc.setRadiusY(t1.doubleValue()/2.9);
                }
            }
        });

        return myArc;
    }

    //Textfield to enter the time
    public TextField createTextField(Arc myArc, Scene myScene){
        TextField myTextField = new TextField("Enter Time 1-60");
        // 绑定最小高度到窗口高度的10%,随窗口调整自动变化
        myTextField.minHeightProperty().bind(myScene.heightProperty().multiply(0.1));
        // 设置首选高度,保证显示完整
        myTextField.setPrefHeight(40);

        TextFormatter<Integer> myTextFormatter = new TextFormatter<>(new IntegerStringConverter(), 60, this::filter);

        myTextField.setTextFormatter(myTextFormatter);

       // myTextField.setOnAction((evt) -> myArc.setLength(myTextFormatter.getValue()!=null ? 6*myTextFormatter.getValue():0));

        return myTextField;
    }

    //Filter to only allow for use of time between 1-60minutes
    public TextFormatter.Change filter(TextFormatter.Change myChange){
        if (myChange.getControlNewText().isEmpty()){
            return myChange;
        }
        int myVal = Integer.parseInt(myChange.getControlNewText());

        return myVal >=0 && myVal <= 60 ? myChange : null;
    }
}

核心修复说明:

  • 添加内边距:给VBox设置setPadding(new Insets(10)),避免TextField紧贴窗口边缘被截断
  • 布局空间分配:通过VBox.setVgrow(myStackPane, Priority.ALWAYS)让StackPane占满VBox的剩余垂直空间,确保TextField始终保留足够的显示区域
  • 动态高度绑定:将TextField的最小高度绑定到窗口高度的10%,而非固定初始值,随窗口大小自动调整高度
  • 容器填充设置:给HBox开启setFillHeight(true),允许VBox在HBox中充分利用垂直空间,避免布局挤压

内容的提问来源于stack exchange,提问作者Jack Wanamaker

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 09:52:08