arynaq
arynaq

Reputation: 6870

Java ScreenManager, setVisible not working, bufferstrategy lost on fullscreen

I am setting up a screenmanager for my game and it is not working as I want it to. I developed methods for toggling between fullscreen and windowed on a JFrame that is passed to this screenmanager but it gives me bugs that should not be present. In order to get exclusive fullscreen I want to remove the decoration on the frame via setUndecorated and this requires the frame to not be visible. So I apply setVisible(false) right before any setUndecorated yet it has no effect. SetUndecorated still complains about visibility when the printout clearly shows the frame is NOT visible.

Edit: On discussions with the helpful commenter below, I discovered that my bufferstrategys content is completely lost when toggling out of fullscreen, how do you avoid this?

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

The current iteration of my screenmanager:

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();


}

The interesting methods are setWindowed and setFullScreen.

Edit: To the comment below, this new main draws a string on the fullscreen buffer, displays it, then when exiting fullscreen it is completely gone, this is without disposing and not worrying about decorations. This is quite odd considering that I go into fullscreen first and the fullscreen method creates a buffer that is attached to the JFrame so even if I leave fullscreen the JFrame now has a bufferstrategy attached to it. So the buffercontent is lost for some reason between the transitions..

// 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();


}

Upvotes: 1

Views: 1261

Answers (1)

mKorbel
mKorbel

Reputation: 109815

I created something that out of this space constalations can fired various exceptions :-), and big sorry there is the same with setUndecorated(false), but required to stopping ImageGnerator, then waiting for all events are done on EDT, then to change decorations type, .........

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);
    }
}

Upvotes: 1

Related Questions