我正在为我的游戏设置屏幕管理器,但它没有按我的意愿工作。我开发了在传递给此屏幕管理器的 JFrame 上在全屏和窗口之间切换的方法,但它给了我不应该存在的错误。为了获得独家全屏,我想通过移除框架上的装饰setUndecorated
,这需要框架不可见。所以我setVisible(false)
在任何之前申请,setUndecorated
但它没有任何效果。当打印输出清楚地显示框架不可见时,SetUndecorated 仍然抱怨可见性。
编辑:在与下面有用的评论者讨论时,我发现我的 bufferstrategys 内容在切换出全屏时完全丢失了,你如何避免这种情况?
Called from fullscreen before toggle, visible? false
Called from fullscreen after toogle, visible? false
Called from windowed before toggle, visible? true
Exception in thread "main" java.awt.IllegalComponentStateException:
The frame is displayable.
at java.awt.Frame.setUndecorated(Unknown Source)
at gfx.ScreenManager.setWindowed(ScreenManager.java:100)
at gfx.ScreenManager.main(ScreenManager.java:145)
Called from windowed after toggle before decorated, visible? false
我的屏幕管理器的当前迭代:
package gfx;
import java.awt.DisplayMode;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
public class ScreenManager {
private JFrame frame;
private GraphicsDevice gd;
private DisplayMode defaultMode;
private DisplayMode[] supportedModes;
// Use with frame from elsewhere
public ScreenManager(JFrame frame) {
this();
this.frame = frame;
}
// Used with a frame that is tied to instance
public ScreenManager() {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
this.gd = ge.getDefaultScreenDevice();
this.defaultMode = new DisplayMode(800, 600, 16, 60);
this.setSupportedModes();
this.frame = new JFrame();
}
// Get the supported displayrates from current graphicsdevice
private void setSupportedModes() {
this.supportedModes = gd.getDisplayModes();
}
// Check if the supplied displaymode is supported by current device
public boolean isSupportedDisplayMode(DisplayMode odm) {
for (DisplayMode dm : this.supportedModes) {
if (dm.getHeight() == odm.getHeight()
&& dm.getWidth() == odm.getWidth()
&& dm.getBitDepth() == odm.getBitDepth()
|| odm.getBitDepth() == DisplayMode.BIT_DEPTH_MULTI
&& dm.getRefreshRate() == odm.getBitDepth()
|| odm.getRefreshRate() == DisplayMode.REFRESH_RATE_UNKNOWN)
return true;
}
return false;
}
public void setFullScreen(DisplayMode displayMode) {
this.setFullScreen(displayMode, frame);
}
// Set fullscreen if supported displaymode, else default displaymode
public void setFullScreen(DisplayMode displayMode, JFrame frame) {
if (gd.isFullScreenSupported()) {
// Fullscreen on visible frame not allowed
System.out
.println("Called from fullscreen before toggle, visible? "
+ frame.isVisible());
frame.setVisible(false);
System.out.println("Called from fullscreen after toogle, visible? "
+ frame.isVisible());
// Remove decoration and unresiable
frame.setUndecorated(true);
frame.setResizable(false);
frame.setIgnoreRepaint(true);
// Set frame as fullscreenwindow
gd.setFullScreenWindow(frame);
// Set default if requested not supported or null
if (displayMode == null || !isSupportedDisplayMode(displayMode))
gd.setDisplayMode(defaultMode);
else
gd.setDisplayMode(displayMode);
// Create bufferstrategy
frame.createBufferStrategy(2);
}
}
// Make windowed
public void setWindowed() {
// Windowed from fullscreen if fullscreen, otherwise we are probably
// windowed already
if (gd.getFullScreenWindow() != null) {
System.out.println("Called from windowed before toggle, visible? "
+ frame.isVisible());
frame.setVisible(false);
System.out
.println("Called from windowed after toggle before decorated, visible? "
+ frame.isVisible());
frame.setUndecorated(false);
frame.setVisible(true);
frame.setIgnoreRepaint(false);
gd.setFullScreenWindow(null);
// gd.getFullScreenWindow().dispose(); < Clears frame, you lose all
// info, da fuck is the point of this except on gamexit from
// fullscreen?
}
}
// Get the drawing graphics of this ScreenManagers bufferstrategy
public Graphics2D getGraphics() {
Window frame = gd.getFullScreenWindow();
if (frame != null) {
BufferStrategy bufferStrategy = frame.getBufferStrategy();
return (Graphics2D) bufferStrategy.getDrawGraphics();
}
return null;
}
public void update() {
Window frame = gd.getFullScreenWindow();
if (frame != null) {
BufferStrategy bufferStrategy = frame.getBufferStrategy();
if (!bufferStrategy.contentsLost())
bufferStrategy.show();
}
Toolkit.getDefaultToolkit().sync();
}
// Display in readable format, eg 800x600x32@60
public String displayModeToString(DisplayMode dm) {
return dm.getWidth() + "x" + dm.getHeight() + "x" + dm.getBitDepth()
+ "@" + dm.getRefreshRate();
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame();
frame.setSize(800, 600);
ScreenManager sm = new ScreenManager(frame);
sm.setFullScreen(new DisplayMode(1680, 1050, 32, 60));
Thread.sleep(3000);
sm.setWindowed();
}
有趣的方法是 setWindowed 和 setFullScreen。
编辑:对于下面的评论,这个新的 main 在全屏缓冲区上绘制一个字符串,显示它,然后在退出全屏时它完全消失了,这不需要处理,也不需要担心装饰。考虑到我首先进入全屏模式并且全屏方法创建了一个附加到 JFrame 的缓冲区,所以这很奇怪,因此即使我离开全屏模式,JFrame 现在也附加了一个缓冲区策略。所以缓冲区内容在转换之间由于某种原因丢失了..
// Make windowed
public void setWindowed() {
// Windowed from fullscreen if fullscreen, otherwise we are probably
// windowed already
if (gd.getFullScreenWindow() != null) {
// gd.getFullScreenWindow().dispose();
gd.setFullScreenWindow(null);
// frame.setUndecorated(false);
frame.setVisible(true);
}
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame();
frame.setSize(800, 600);
ScreenManager sm = new ScreenManager(frame);
sm.setFullScreen(new DisplayMode(1680, 1050, 32, 60));
Graphics2D g2d = sm.getGraphics();
g2d.setColor(Color.red);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Font font = new Font("Serif", Font.PLAIN, 96);
g2d.setFont(font);
g2d.drawString("jade", 40, 120);
g2d.dispose();
sm.update();
Thread.sleep(3000);
sm.setWindowed();
}