JavaFX——当我创建 TextField 的新实例时,整个窗口变成白色

问题描述

我创建了 JavaFX 应用程序,使整个屏幕变黑。然后我决定添加 TextField 的新实例以获取用户的输入,但注意到现在整个屏幕都是白色的。我什至没有将它添加到任何窗格或场景中。我试图将 TextField 的背景颜色更改为空,但没有去除白色。

这是生成黑色窗口的代码

package org.medianik.tictactoe;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.Pane;
import javafx.stage.Screen;
import javafx.stage.Stage;

import java.io.InputStream;

import static org.medianik.tictactoe.util.Constants.*;

/**
 * JavaFX App
 */
public class TicTacToe extends Application{

    private static TicTacToe instance;
    public static TicTacToe getInstance(){
        return instance;
    }

    private final int width;
    private final int height;
    final Pane pane;

    public TicTacToe(){
        width = calculateWidth();
        height = calculateHeight();
        pane = new StackPane();
        instance = this;
    }


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

    /**
     * The entry point
     */
    @Override
    public void start(Stage stage){
        //In Constants.java:
        //public static final Color BACKGROUND_COLOR = Color.BLACK;
        var scene = new Scene(pane,width,height,BACKGROUND_COLOR);
        stage.setScene(scene);
        stage.show();
        setupIcon(stage);
//        new TextField();

    }

    private int calculateWidth(){
        var bounds = Screen.getPrimary().getBounds();
        return Math.min((int) bounds.getWidth() - GLOBAL_OFFSET,MAX_WIDTH);
    }

    private int calculateHeight(){
        var bounds = Screen.getPrimary().getBounds();
        return Math.min((int) bounds.getHeight() - GLOBAL_OFFSET,MAX_HEIGHT);
    }

    private void setupIcon(Stage stage){
        InputStream inputIcon = getClass().getResourceAsstream("/icon.png");
        Image icon = new Image(inputIcon);
        stage.getIcons().add(icon);
    }

    @Override
    public void stop() throws Exception{
        System.out.println("stop");
    }

    public int getWidth(){
        return width;
    }

    public int getHeight(){
        return height;
    }
}

这是窗口: Picture of ordinary person 但是如果我取消注释一行:

    /**
     * The entry point
     */
    @Override
    public void start(Stage stage){
        //In Constants.java:
        //public static final Color BACKGROUND_COLOR = Color.BLACK;
        var scene = new Scene(pane,BACKGROUND_COLOR);
        stage.setScene(scene);
        stage.show();
        setupIcon(stage);
        new TextField();

    }

一切都变白了: Picture of insane one

即使我将背景设为,也没有任何变化:

    /**
     * The entry point
     */
    @Override
    public void start(Stage stage){
        var scene = new Scene(pane,BACKGROUND_COLOR);
        stage.setScene(scene);
        stage.show();
        setupIcon(stage);
        TextField text = new TextField();
        text.setBackground(Background.EMPTY);
    }

我该怎么做才能解决这个问题?

解决方法

看到这个有点惊讶(并且没有立即回答;)所以做了一些挖掘:

  • 验证我可以在(稍微精简的)示例中重现不同的行为
  • 在创建 TextField 之前/之后添加了窗格状态的调试打印输出:注意其背景之前为空,之后不为空
  • 在调试器中创建字段:在控件的类加载上记录了 styleSheet init

所以不同的原因是默认的styleSheet加载在类Control的静态代码块中(可能还有其他路径):

static {
    ... 
    // Ensures that the default application user agent stylesheet is loaded
    if (Application.getUserAgentStylesheet() == null) {
        PlatformImpl.setDefaultPlatformUserAgentStylesheet();
    }
}

修改示例:

public class TicTacToe extends Application{

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

    @Override
    public void start(Stage stage){
        Pane pane = new StackPane();
        var scene = new Scene(pane,500,300,Color.BLACK);
        stage.setScene(scene);
        stage.show();
        System.out.println("pane before styling: " + pane.getBackground()); 
        new TextField();
        Platform.runLater(() -> {
            System.out.println("pane after styling: "  + pane.getBackground()); 
        });
    }

}