[java] How to toggle between fullscreen/window in jdk 1.5 ?

Started by
5 comments, last by tebriel 19 years, 1 month ago
Hi I'm writing little 2d game and want to have functionality that user can press a button (like F11) to toggle between window & fullscreen mode. I don't use any fancy api:s , just vanilla JFrame. When I startup I can choose 2 paths - either to start ordinary JFrame, or to start in Fullscreen mode through a "GraphicsDevice" object - that's the easy one. But my problem is how to toggle later on? Does it mean I have to save DisplayMode before I toggle to fullscreen (that would be the "desktop mode"), set that DisplayMode & then resize the window? Can I just exit the fullscreen window and resize the window (since I have the ref to it). Or what would be the way to do it? I have seen many examples how to setup fullscreen mode, but I'm not sure how to do change from fullscreen to window & vice versa. Any pointer to some resource or advice is welcome ... tia
Advertisement
Here's a rough (and I do mean rough) thingy that does basically what you're asking for... I'm sure there's other ways to do it. Probably better ones, even. I assume you want to change resolution, etc, too?

I just had to use mainScreenTurnOn() for you All Your Base fans, and it's sloppy as heck, but hey it worked....lol. I threw this together in a few minutes (since I'm planning on doing this in the future anyway)...but, hmm....now that I think about it--are you also asking how to use setUndecorated() so that you get a "true" fullscreen look? I think that complicates things a little more, since you can't call setUndecorated() after the frame is displayable.

Then again, if you don't need to have a standard "windows frame" in your "windowed" mode (to move it around and such), just call setUndecorated(false) on your frame object and be done with it. I'm not sure if there's a way around that, maybe someone else knows better, but I imagine you'd have to create a whole new JFrame object to go from the "decorated" windowed mode to the "undecorated" fullscreen mode.

If anything I've typed here sounds silly, it's 2:30 am here and I'm tired. :)

/* * fullscreenToggle.java * Created on Feb 14, 2005 */package fullscreenToggle;import java.awt.DisplayMode;import java.awt.GraphicsDevice;import java.awt.GraphicsEnvironment;public class fullscreenToggle {    public static void main(String[] args) {        GameViewManager g = new GameViewManager();    }}


Wow!
Ok for real, here's what you want I guess:

/* * GameViewManager.java * Created on Feb 14, 2005 */package fullscreenToggle;import java.awt.BorderLayout;import java.awt.DisplayMode;import java.awt.GraphicsDevice;import java.awt.GraphicsEnvironment;import java.awt.event.KeyEvent;import java.awt.event.KeyListener;import javax.swing.JButton;import javax.swing.JFrame;public class GameViewManager implements KeyListener {        GraphicsDevice[] devices;    DisplayMode oldDisplayMode;    JFrame frame;    boolean mainScreenOn;    JButton button;    public GameViewManager() {                GraphicsEnvironment ge =	        GraphicsEnvironment.getLocalGraphicsEnvironment();	    devices = ge.getScreenDevices();                frame = new JFrame(devices[0].getDefaultConfiguration());        frame.getContentPane().setLayout(new BorderLayout());                button = new JButton("All your base are belong to us");        frame.getContentPane().add(button);                button.addKeyListener(this);        frame.getContentPane().addKeyListener(this);                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        frame.setVisible(true);        frame.pack();    }        //Sorry, I just couldn't help putting this "all your base" reference in.    private void mainScreenTurnOn() {        //Save old display mode        oldDisplayMode = devices[0].getDisplayMode();        //Go fullscreen        if (devices[0].isFullScreenSupported()) {            devices[0].setFullScreenWindow(frame);            //Change resolution            DisplayMode dm = new DisplayMode(800, 600, 32, 60);            if (devices[0].isDisplayChangeSupported())                devices[0].setDisplayMode(dm);        }//end if    }        private void mainScreenTurnOff() {        devices[0].setDisplayMode(oldDisplayMode);        //Fix window size here or whatever etc etc.    }    public void keyPressed(KeyEvent e) {        if (e.getKeyCode() == e.VK_F11)         {            if (mainScreenOn)             {                mainScreenOn = false;                mainScreenTurnOff();            }            else             {                mainScreenTurnOn();                mainScreenOn = true;            }        }    }    public void keyReleased(KeyEvent arg0) {    }    public void keyTyped(KeyEvent arg0) {    }}
btw, this line may need to be 'tweaked'

DisplayMode dm = new DisplayMode(800, 600, 32, 60);

Fourth parameter is refresh rate. I'm not sure if you could specify a value that may damage your monitor with this function or not, but just be aware of it.
Oki - thnks for answer; I see you have implemented idea I outlined above. I was rather looking for better approach to that problem then for implementation (I had my own implementation of that idea that didn't worked great). However thnks for help. After some reading in java doc I found what I was doing wrong. To return from fullscreen window one should call GraphicDevice method "setFullScreenWindow" again with null as parameter. Unfortunately for some reason I get decorations in fullscreen mode, so to fix taht one one have to destroy content of the window with dispose() metod to be able to toggle decorations on/off. Disposing and creating a window causes some ugly flickering because desktop is redrawn between those calls.

I'm playing with some other idea of having two windows and 1 Graphics object and then changing graphics contents of those windows or rendering to and Image object and redrawing it in either one or another window. That would eliminate need of dispose() call and recreation of the window after, but I'm not sure if it would eliminate flicker when changing between. It may though be little bit faster (and more resource demanding) since 2 windows are always alive so to say.

Btw - I have tryed your code; it didn't worked very well - I dunno how much u have tested it, but try to change mode several times etc.

Here are some modifications to get it working as described above(just bare bones without anything unneccesary):
Quote:
import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

public class FrameTest implements KeyListener
{
GraphicsDevice device;
JFrame frame;
boolean fullscreen;

public FrameTest() {

GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
device = ge.getDefaultScreenDevice();

frame = new JFrame();
frame.addKeyListener(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800,600);
frame.setResizable(false);
frame.setVisible(true);
}

private void mainScreenTurnOn() {
frame.dispose();
frame.setUndecorated(true);
device.setFullScreenWindow(frame);
fullscreen = true;
}

private void mainScreenTurnOff() {
fullscreen = false;
device.setFullScreenWindow(null);
frame.dispose();
frame.setUndecorated(false);
frame.setVisible(true);
}

public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == e.VK_F11){
if(!fullscreen)
mainScreenTurnOn();
else
mainScreenTurnOff();
}
else System.out.println(e.getKeyCode()+"\n");
}

public void keyReleased(KeyEvent arg0) {
}

public void keyTyped(KeyEvent arg0) {
}

public static void main(String[] args) {
new FrameTest();
}
}


Well I "tested" it like...two or three times. It did work (although I know it reacts weird esp. with respect to the button I threw in there, was a layout issue I think, but didn't care...and I think there was a resizing issue I didn't bother with fixing.)...it was more just to show a way it might be done. Should I actually try doing this I might end up doing it different, too. (I actually was using setFullScreenWindow(null) but changed to this method for this example, I forget why! I think I had a reason..?)

You could try looking into actually creating and destroying entire JFrame objects to get rid of the "window decorations". The function to turn it off is setUndecorated() if it hasn't been mentioned already. There MAY be a way to call it again after the window has been "realized" (their stupid term not mine), but I haven't looked much into that (yet). But you're saying we can call dispose() to alter decorations? If it's possible to design around the premise of being able to recreate your application's actual display (JFrame etc), which I think it should be, I guess it's worth trying. (Make sure no persistent data or data that can't be quickly determined at runtime is stored in the display objects? i.e. Document/View concept?)

I'll have to see how it looks sometime, if it's just causing some odd flickering for a second but works otherwise, I don't see a problem with it...(Unless it's really bad.) Afterall toggling fullscreen mode isn't something done often, nor do most applications do a very "clean, fast and pretty" job of switching back and forth. Anyone toggling fullscreen I would hope should be thankful enough that the designers decided to include the feature at all IMO!
Quote:You could try looking into actually creating and destroying entire JFrame objects to get rid of the "window decorations".
Yepp - that's what u do when you call dispose() & then setVisible(true) again - take a look in that code I posted - that's exactly what is done (and what I described in prevous post).
Quote: The function to turn it off is setUndecorated() if it hasn't been mentioned already.
Yepp - and that's what is used in the code above - take a look at it.
Problem is you can call that function only untill the windows is in non-displayable state. For. example you can't call it once your windows has been displayed - I dunno if it's limitation in win32 api or jdk - but that's the fact. Hence the need to call dispose() to destroy the window, then set undecorated state & then create it again.
Quote:I'll have to see how it looks sometime, if it's just causing some odd flickering for a second but works otherwise, I don't see a problem with it...

According to jdk docs if setVisible(true) is called after dispose() the window will be recreated with all it's resources it had before - but in dispose it actually returns all it's native resources to the OS - so doing it just for toggling decorations on/off is costly operation - so I was hoping for some better suggestion. It isn't done very often so that cost can indeed be ignored as u suggest - but actually I thaught that there might be some "standard" way of doing this that I don't know about & that is better then killing/recreating window for this purpose. I haven't seen any tutorial on this issue in java so that's why I asked.

Again thnks for your implementation & consideration.
Ahhhh, I see what you're asking now. It sounds like you've looked into the topic more than I have, anyway. I still have the same opinion though: since it's not done very often (if at all), the performance hit probably isn't going to be big of a deal to anyone. Unless there's something specific about what you're working on that requires toggling back and forth alot of course.

So nope, I don't know of a better way than what you're doing, but it seems fine to me if it works for you!

This topic is closed to new replies.

Advertisement