FudgeMuffins
FudgeMuffins

Reputation: 313

JFrame too small and pack() doesn't seem to work

For some reason, the JFrame is too small when run, and using pack(); doesn't seem to fix the problem. Any ideas?

   public class Window {

    public Window(String title, Game game) {

        // Creates new JFrame
        JFrame frame = new JFrame(title);

        // Adds Game to window
        frame.add(game);
        frame.pack();   

        // Settings of Window
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

    }

}

Screenshot of the program.

The cyan background is supposed to be a 64 x 64 border in the bottom and right sides. The boxes drawn are correct, which I checked by resizing the window. However the window is too small and does not fit the canvas.

Game Class:

public class Game extends Canvas implements Runnable {

private Handler handler;

public Game() {

    // Create new window
    Window window = new Window("Horses Aren't Real", this);

    handler = new Handler();
    this.addKeyListener(new KeyInput(handler));

    handler.addObject(new Daanish(100, 100, ID.Player, handler));

}

public static void main (String args[]) {

    // Creates new game
    new Game();

}

public void draw() {

    // Creates a new BufferStrategy
    BufferStrategy bs = this.getBufferStrategy();

    if (bs == null) {

        // This allows the game to preload 3 frames in order to prevent choppy framrate
        this.createBufferStrategy(3);

        return;

    }

    // Create Graphics
    Graphics g = bs.getDrawGraphics();

    g.setColor(Color.cyan);
    g.fillRect(0, 0, 1024, 640);

    g.setColor(Color.black);
    g.fillRect(0, 0, 960, 576);

    handler.draw(g);

    // Remove frame from queue
    g.dispose();
    bs.show();

}

@Override
public Dimension getPreferredSize() {

    return new Dimension(1024, 640);

}

}

Upvotes: 0

Views: 1851

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347314

So you're running into a number of issues. The first been, the size of the window must also account for the frame decorations, this means that the available space for the content is the size of the window MINUS the size of the frame decorations.

Setting the size of the window directly is ill-advised.

pack asks the content of the frame for it's preferred size and uses that to wrap the window around it. So, instead of window size - decorations = content size, you have content size + decorations = window size

From the JavaDocs

Causes this Window to be sized to fit the preferred size and layouts of its subcomponents. The resulting width and height of the window are automatically enlarged if either of dimensions is less than the minimum size as specified by the previous call to the setMinimumSize method.

So, instead, override preferredSize of the Game class and return the amount of space you want, may be something like...

public class Game extends JPanel {
    //...
    @Override
    public Dimension getPreferredSize() {
        return new Dimension(800, 600);
    }
    //...
}

Your next problem is, Window extends from JFrame, but in the constructor, you're creating ANOTHER Frame ... so which one is actually doing what?

Remove the confusion. Avoid extending from top level containers like JFrame, you're not adding any new functionality to it

public class Window {

    public Window(String title, Game game) {

        // Creates new JFrame
        JFrame frame = new JFrame(title);

        // Adds Game to window
        frame.add(game);
        frame.pack();

        // Settings of Window
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

    }

}

Updated...

So, I took your "updated" code, modified it so it would run, ran and didn't have any issues...

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                Game game = new Game();
                Window window = new Window("Help", game);

                game.start();
            }
        });
    }

    public class Window {

        public Window(String title, Game game) {

            // Creates new JFrame
            JFrame frame = new JFrame(title);

            // Adds Game to window
            frame.add(game);
            frame.setResizable(false);
            frame.pack();

            // Settings of Window
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);

        }

    }

    public class Game extends Canvas { //implements Runnable {

//      private Handler handler;

        public Game() {
//
//          handler = new Handler();
//          this.addKeyListener(new KeyInput(handler));
//
//          handler.addObject(new Daanish(100, 100, ID.Player, handler));

        }

        public void start() {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        draw();
                        try {
                            Thread.sleep(40);
                        } catch (InterruptedException ex) {
                        }
                    }
                }
            });
            thread.start();
        }

        public void draw() {

            // Creates a new BufferStrategy
            BufferStrategy bs = this.getBufferStrategy();

            if (bs == null) {
                // This allows the game to preload 3 frames in order to prevent choppy framrate
                this.createBufferStrategy(3);
                return;
            }

            // Create Graphics
            Graphics g = bs.getDrawGraphics();

            g.setColor(Color.cyan);
            g.fillRect(0, 0, 1024, 640);

            g.setColor(Color.black);
            g.fillRect(0, 0, 960, 576);

//          handler.draw(g);

            // Remove frame from queue
            g.dispose();
            bs.show();

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(1024, 640);
        }

    }

}

However, I'm running on MacOS. There is a little known issue with setResizable I've run across on Windows, where the window decorations change size when setResizable is called.

The "basic" solution is to call setResziable BEFORE calling pack, so that the frame decorations are modified before the the API makes decisions about how to update the size of the window.

I had thought this was fixed in later (8+) versions of Java, but since I don't run Windows, it's impossible for me to test

See My JFrame always becomes a few pixels too big. for some more details.

Upvotes: 2

Mead
Mead

Reputation: 100

public class Window extends JFrame {

public Window(final int width, final int height, String title, Game game) {
    super(title);
    // Set dimensions
    Dimension d = new Dimension(width, height);
    game.setPreferredSize(d);

    // Adds Game to window
    add(game);
    // Settings of Window
    setResizable(false);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLocationRelativeTo(null);
    pack();
    setVisible(true);

}

}

When you use pack, the frame generaly resize to content size

Upvotes: 1

Related Questions