Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java - JFrame, JPanel, Layout, and Clipping

I have three questions/problems. (NOTE - I don't have enough reputation to post pics, so I linked them. And I needed to obfuscate them...)

1) I created a panel that holds my game graphics (the player area). The panel is supposed to be 800x800 and clip everything that lies below and to the right. But when I add the graphics panel to a JFrame, it doesn't clip. So images go over on the right and left. This is a picture of how to game starts. Ideally, the graphics would start in this rectangle the whole time:

Picture #1: http://i.stack.imgur.com/idL8f.png

Now, here's what happens when I press play to start.

Picture #2: http://i.stack.imgur.com/dxtbe.png

How can I set the panel/frame so that the graphics only occupy 800x800 (like the first picture) and everything else is clipped?

2) I'm a bit confused about how I can set up the JFrame. This is how I want it to be layed out:

Picture #3: http://i.stack.imgur.com/ZyJS5.png

How would you lay the JFrame/Panels out? I was thinking BorderLayout, but I'm not certain it would work out.

3) For this game, my class that extends JFrame also contains main(). Is this bad practice?** Are you supposed to not extend JFrame on the main class?

like image 503
Dan James Avatar asked Oct 14 '22 23:10

Dan James


1 Answers

  1. The easiest way to get an 800x800 panel is to use setPreferredSize() and then pack() the JFrame that contains is. Conveniently, pack() "Causes this Window to be sized to fit the preferred size and layouts of its subcomponents."

2). See A Visual Guide to Layout Managers for layout suggestions. You can use nested panels to achieve your desired layout.

3). There's nothing wrong with extending JFrame, but there's little point unless you are modifying the behavior of JFrame. In contrast, JPanel is a convenient container for grouping components; it was designed to be extended. You might examine this example in that regard.

Addendum:

I don't want the panel to show anything but the 800 pixels in the x and y direction.

You can override paintComponent() and copy whatever portion of the image is desired. In the example below, g.drawImage(img, 0, 0, null) draws the top-left 800 pixels of the image, while g.drawImage(img, 0, 0, getWidth(), getHeight(), null) scales the image the panel's size. Note that f.setResizable(false) prevents changing the window's size.

Addendum: You can also copy arbitrary portions of the source image to arbitrary areas of the the destination panel, as shown below. Also consider overriding getPreferredSize(), as suggested here.

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

/** @see http://stackoverflow.com/q/3851847 */
public class MyPanel extends JPanel {

    private BufferedImage img;

    public MyPanel() {
        this.setPreferredSize(new Dimension(800, 800));
        try {
            img = ImageIO.read(new File("../scratch/image.png"));
        } catch (IOException ex) {
            ex.printStackTrace(System.err);
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
//        g.drawImage(img, 0, 0, 800, 800, null);
//        g.drawImage(img, 0, 0, getWidth(), getHeight(), null);
        g.drawImage(img, 0, 0, 800, 800, 0, 0, 800, 800, this);
    }

    private void display() {
        JFrame f = new JFrame("MyPanel");
//        f.setResizable(false);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new MyPanel().display();
            }
        });
    }
}
like image 155
trashgod Avatar answered Oct 18 '22 10:10

trashgod