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
相关产品推荐
相关产品推荐

