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

Java渲染方法中setColor失效:macOS显示空白白屏

问题:macOS下Java Swing Canvas绘制空白,Windows正常显示

我在跟随简易2D游戏教程学习时遇到问题:setColor和fillRect方法在macOS上无法正常工作,窗口仅显示空白白屏,但组员在Windows系统运行相同代码能正常显示蓝色全屏。

代码示例

package org.Display;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferStrategy;

public class Screen extends Canvas implements Runnable {
    JFrame frame;
    private Thread thread;
    private boolean running;
    int width;
    int height;

    public Screen(String title, int w, int h) {
        running = false;
        frame = new JFrame(title);

        width = w;
        height = h;

        // screen properties
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // closes the program when you click X
        frame.setSize(width, height); // set size of the screen
        frame.setResizable(false); // do not allow resizing
        frame.setVisible(true); // set the screen to visible
        frame.add(this);
    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }

    // start game logic
    public void start() {
        running = true;

        // create our new thread
        thread = new Thread(this);
        thread.start();

    }

    // stop game logic
    public void stop() {
        running = false;

        // stop our thread
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void run() {
        long lastTime = System.nanoTime();
        double amountOfTicks = 60.0;
        double ns = 1000000000 / amountOfTicks;
        double delta = 0;
        long timer = System.currentTimeMillis();
        int updates = 0;
        int frames = 0;

        while (running)
        {
            long now = System.nanoTime();
            delta += (now - lastTime) / ns;
            lastTime = now;
            while (delta >= 1)
            {
                tick();
                updates++;
                delta--;
            }
            Render();
            frames++;
            if (System.currentTimeMillis() - timer > 1000)
            {
                timer += 1000;
                System.out.println("FPS: " + frames + " TICKS: " + updates);
                frames = 0;
                updates = 0;
            }
        }

        stop();
    }

    // update screen
    private void tick() {

    }

    // paint onto window
    private void Render() {
        BufferStrategy bs = this.getBufferStrategy(); // makes transitions smoother

        // if haven't created BufferStrategy yet, create it
        if(bs == null) {
            this.createBufferStrategy(2);
            bs = this.getBufferStrategy();
        }

        Graphics g = bs.getDrawGraphics(); // create graphics

        // test if Render works
        g.setColor(Color.blue);
        g.fillRect(0, 0, width, height);

        bs.show();
        g.dispose(); // clear the screen
    }

    public void MainMenu() {
        // implement me
    }

    public void WiningScreen() {
        // implement me
    }

    public void GameScreen() {
        // implement me
    }

    public void GameOverScreen() {
        // implement me
    }
}

可能的原因及修复方案

1. 组件添加与窗口可见性顺序错误

macOS的AWT/Swing对组件添加时机更敏感:你的代码先设置窗口可见,再添加Canvas组件,导致UI线程未感知到新组件,Canvas从未被正确渲染。

修复:调整构造函数顺序,先添加组件再设置窗口可见:

public Screen(String title, int w, int h) {
    running = false;
    frame = new JFrame(title);

    width = w;
    height = h;

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(width, height);
    frame.setResizable(false);
    // 先添加Canvas到窗口
    frame.add(this);
    // 再设置窗口可见
    frame.setVisible(true);
}

2. Canvas未设置实际尺寸

你重写了getWidth()和getHeight()但未设置Canvas本身的尺寸,macOS下AWT会以0尺寸初始化Canvas,导致绘制内容不可见。

修复:显式设置Canvas尺寸,并用pack()适配窗口:

public Screen(String title, int w, int h) {
    running = false;
    frame = new JFrame(title);

    width = w;
    height = h;
    // 设置Canvas的首选尺寸与实际尺寸
    this.setPreferredSize(new Dimension(width, height));
    this.setSize(width, height);

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setResizable(false);
    frame.add(this);
    // 让窗口自动适配组件尺寸,替代手动setSize
    frame.pack();
    frame.setVisible(true);
}

3. BufferStrategy创建的线程安全问题

你的渲染逻辑在自定义线程中,macOS对AWT组件的线程操作要求更严格,可能导致BufferStrategy创建失败。

修复:确保组件显示后再启动渲染线程,并检查组件状态再创建BufferStrategy:

public void start() {
    running = true;
    // 在UI线程确认组件就绪后启动渲染线程
    SwingUtilities.invokeLater(() -> {
        thread = new Thread(this);
        thread.start();
    });
}

private void Render() {
    BufferStrategy bs = this.getBufferStrategy();
    if(bs == null) {
        // 仅在组件已显示时创建BufferStrategy
        if(this.isDisplayable()) {
            this.createBufferStrategy(2);
            bs = this.getBufferStrategy();
        } else {
            return;
        }
    }
    // 后续绘制逻辑不变...
}

4. macOS Retina屏幕适配问题

Retina屏幕的缩放因子可能导致绘制内容偏移或被隐藏。

修复:添加JVM启动参数禁用HiDPI适配:

-Dapple.awt.graphics.UseQuartz=true -Dsun.java2d.uiScale=1

或在代码中获取缩放因子调整绘制尺寸:

GraphicsConfiguration gc = this.getGraphicsConfiguration();
double scale = gc.getDefaultTransform().getScaleX();
g.fillRect(0, 0, (int)(width * scale), (int)(height * scale));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 18:52:03