ゲーム用にスクリーンマネージャーをセットアップしていますが、思い通りに動作しません。このスクリーンマネージャーに渡される 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 です。
編集: 以下のコメントに対して、この新しいメインはフルスクリーン バッファに文字列を描画して表示し、フルスクリーンを終了すると完全に消えます。これは破棄せず、装飾を心配する必要もありません。最初にフルスクリーンに移行し、フルスクリーン メソッドが 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();
}