Java ScreenManager,setVisible 不起作用,bufferstrategy 在全屏上丢失

标签 java swing jframe fullscreen

我正在为我的游戏设置屏幕管理器,但它没有按我想要的方式工作。我开发了在传递给此屏幕管理器的 JFrame 上在全屏和窗口之间切换的方法,但它给了我不应该出现的错误。为了获得独家全屏,我想通过 setUndecorated 删除框架上的装饰,这要求框架不可见。因此,我在任何 setUndecorated 之前应用 setVisible(false) 但它没有任何效果。当打印输出清楚地显示框架不可见时,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();


}

最佳答案

我创建了一些东西,在这个空间星座之外可以引发各种异常:-),很抱歉,setUndecorated(false) 也有同样的情况,但需要停止 ImageGnerator,然后等待所有事件在 EDT 上完成,然后更 retrofit 饰类型,........

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

public class FullScreen {

    private static final long serialVersionUID = 1L;
    private GraphicsDevice device;
    private JButton button = new JButton("Close Meeee");
    private JPanel myPanel = new JPanel();
    private JFrame frame = new JFrame();
    private JLabel imageLabel;
    private Dimension halfScreenSize;
    private Random random;
    private JProgressBar memory;
    private Dimension d;
    private Font bigFont = new Font("Arial", Font.BOLD, 30);
    private int count = 0;
    private int startMem = 0;
    private int maxMem = 0;
    private int peakMem = 0;
    private int useMem = 0;
    private javax.swing.Timer timer = null;

    public FullScreen() {
        startMem = ((int) Runtime.getRuntime().freeMemory());
        maxMem = ((int) Runtime.getRuntime().freeMemory());
        peakMem = ((int) Runtime.getRuntime().freeMemory());
        d = Toolkit.getDefaultToolkit().getScreenSize();
        halfScreenSize = new Dimension(d.width, d.height);
        //halfScreenSize = new Dimension(d.width - 11, d.height - 51);
        random = new Random();
        imageLabel = new JLabel(new ImageIcon(convertToFromBytes(getImage())));
        memory = new JProgressBar(0, (int) Runtime.getRuntime().maxMemory());
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
        myPanel.setLayout(new BorderLayout(10, 10));
        myPanel.add(imageLabel, BorderLayout.CENTER);
        myPanel.setFocusable(true);
        myPanel.add(button, BorderLayout.NORTH);
        myPanel.add(memory, BorderLayout.SOUTH);
        frame.add(myPanel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setUndecorated(true);
        frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
                KeyStroke.getKeyStroke("ENTER"), "clickENTER");
        frame.getRootPane().getActionMap().put("clickENTER", new AbstractAction() {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                exitFullScreen();
            }
        });
        enterFullScreen();
        frame.setVisible(true);
        Runnable doRun = new Runnable() {
            @Override
            public void run() {
                System.out.println(frame.getBounds());
            }
        };
        SwingUtilities.invokeLater(doRun);
        Runnable r = new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        d = Toolkit.getDefaultToolkit().getScreenSize();
                        halfScreenSize = new Dimension(d.width, d.height);
                        imageLabel.setIcon(new ImageIcon(convertToFromBytes(getImage())));
                        memory.setValue((int) Runtime.getRuntime().freeMemory());
                        memory.setStringPainted(true);
                        useMem = ((int) Runtime.getRuntime().freeMemory());
                        Thread.sleep(500);
                    } catch (InterruptedException ex) {
                        //something with exception
                    } finally {
                        //alive that if required
                    }
                }
            }
        };
        Thread t = new Thread(r);
        t.start();
    }

    private void enterFullScreen() {
        GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
        device = graphicsEnvironment.getDefaultScreenDevice();
        if (device.isFullScreenSupported()) {
            device.setFullScreenWindow(frame);
            frame.validate();
        }
    }

    private void exitFullScreen() {
        startOne();
    }

    private void startOne() {
        timer = new javax.swing.Timer(70, setFullScreenWindowFalse());
        timer.start();
        timer.setRepeats(false);
    }

    public Action setFullScreenWindowFalse() {
        return new AbstractAction("setFullScreenWindowFalse") {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                device.setFullScreenWindow(null);
                startTwo();
            }
        };
    }

    private void startTwo() {
        timer = new javax.swing.Timer(70, hideJFrame());
        timer.start();
        timer.setRepeats(false);
    }

    public Action hideJFrame() {
        return new AbstractAction("hideJFrame") {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                frame.setVisible(false);
                startThree();
            }
        };
    }

    private void startThree() {
        timer = new javax.swing.Timer(250, showJFrame());
        timer.start();
        timer.setRepeats(false);
    }

    public Action showJFrame() {
        return new AbstractAction("showJFrame") {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                myPanel.setPreferredSize(new Dimension(400, 300));
                frame.pack();
                frame.setVisible(true);
            }
        };
    }

    private BufferedImage getImage() {
        GradientPaint gp = new GradientPaint(0f, 0f, new Color(127 + random.nextInt(128), 127 + random.nextInt(128), 127 + random.nextInt(128)),
                (float) halfScreenSize.width, (float) halfScreenSize.width, new Color(random.nextInt(128), random.nextInt(128), random.nextInt(128)));
        BufferedImage bi = new BufferedImage(halfScreenSize.width, halfScreenSize.height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = bi.createGraphics();
        g2d.setPaint(gp);
        g2d.fillRect(0, 0, halfScreenSize.width, halfScreenSize.height);
        g2d.setFont(bigFont);
        g2d.setColor(Color.BLACK);
        if (maxMem < ((int) Runtime.getRuntime().freeMemory())) {
            maxMem = ((int) Runtime.getRuntime().freeMemory());
        }
        if (peakMem > ((int) Runtime.getRuntime().freeMemory())) {
            peakMem = ((int) Runtime.getRuntime().freeMemory());
        }
        useMem = ((int) Runtime.getRuntime().freeMemory()) - useMem;
        g2d.drawString("" + ++count, 20, 100);
        g2d.drawString("JVM memory status --->  ", 20, 195);
        g2d.drawString("tot. memory --->  " + ((int) Runtime.getRuntime().totalMemory()), 20, 240);
        g2d.drawString("max. memory --->  " + ((int) Runtime.getRuntime().maxMemory()), 20, 270);
        g2d.drawString("free on startUp --->  " + startMem, 20, 300);
        g2d.drawString("max free memory --->  " + maxMem, 20, 350);
        g2d.drawString("min free memory --->  " + peakMem, 20, 380);
        g2d.drawString("act free memory --->  " + ((int) Runtime.getRuntime().freeMemory()), 20, 410);
        g2d.drawString("usage of memory --->  " + useMem, 20, 450);
        return bi;
    }

    private Image convertToFromBytes(BufferedImage image) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(image, "png", baos);
            return Toolkit.getDefaultToolkit().createImage(baos.toByteArray());
        } catch (Exception e) {
            return null;
        }
    }

    public static void main(String[] args) {
        Runnable doRun = new Runnable() {
            @Override
            public void run() {
                FullScreen fullScreen = new FullScreen();
            }
        };
        SwingUtilities.invokeLater(doRun);
    }
}

关于Java ScreenManager,setVisible 不起作用,bufferstrategy 在全屏上丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15501716/

相关文章:

Java Jlabel 更新文本

java - 在 JFrame 中绘制 JPanel

java - 卷轴不出现

java - 在 java 中维护唯一数组的 ArrayList

java - 数据库 Multi-Tenancy 和新线程

java - Maven 在使用 javax 时寻找 Jersey 依赖(调用接口(interface))

java - 从 Java 应用程序 POST 请求在 Apache NiFi 中记录 JSON 负载

java - 带勾号的 JRadioButtonMenuItem

java - 如何将类型光标自动放入 JEditorPane 中?

java - 更新 JTable