This is my first post in this forum so excuse me in advance if I make a mistake in formatting or posting etiquette here.

I am fairly new to programming in Java Swing and I've been trying to create simple tower defense game for a personal project yet I'm running into trouble with drawing images onto my application. I've looked around in many of the java tutorials both on this forum and on Oracle but I've never been able to find a solution that helped fix this so I'm resorting to asking for myself.

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

public DotO()
{
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            createAndShowGUI();             
        }
    });
}

private void createAndShowGUI()
{
    backgroundPanel = new JPanel();
    setBorder(BorderFactory.createLineBorder(Color.black));
    loadBackground();  
    setBackground(Color.white);  

    //1. Create the frame.
    JFrame frame = new JFrame("Defense Of The Origin");

    //2. Optional: What happens when the frame closes?
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    //4. Size the frame.
    frame.setSize(SIZEX, SIZEY);

    //5. Show it.
    frame.setVisible(true);

    //3. Add Background Panel
    frame.add(backgroundPanel);  
}

private void loadBackground()  
{  
    String fileName = "resources/Background.jpg";  
    try  
    {  
        URL url = getClass().getResource(fileName);  
        backgroundImage = ImageIO.read(url);  
    }  
    catch(MalformedURLException mue)  
    {  
        System.out.println("url: " + mue.getMessage());  
    }  
    catch(IOException ioe)  
    {  
        System.out.println("read: " + ioe.getMessage());  
    }
}

@Override
protected void paintComponent(Graphics g)  
{  
    System.out.println("painted");
    super.paintComponent(g);  
    int w = getWidth();  
    int h = getHeight();
    g.drawImage(backgroundImage, 0, 0, w, h, this);  
    System.out.println("it's working");
}

The frame does open with no trouble at the preferred size but nothing is drawn on the frame. All I see is a gray space and when I put a System.out.print inside the paintComponent method, it doesn't show in the console so I know the application never actually runs the paintComponent method. Any advice would be greatly appreciated!

有帮助吗?

解决方案

This obviously belongs into a class

class DotO extends JPanel { ... }

However, in your createAndShowGUI method, you are creating a new panel and adding this panel to the frame. In this panel, the paintComponent method is not overridden.

On the other hand, you are never creating a "visible" instance of DotO. You are only creating an instance of DotO, but never adding it to a frame or so.

One solution would be to omit the backgroundPanel, and instead of

frame.add(backgroundPanel);

you could call

// Add "this" to the panel. "this" is the DotO instance
// where the `paintComponent` method is overridden
frame.add(this);

You should consider pulling the GUI creation out of the DotO class, and do the creation of the frame in the main method, like this:

public static void main(String[] args) 
{
    SwingUtilities.invokeLater(new Runnable() 
    {
        public void run() 
        {
            createAndShowGUI();             
        }
    });
}

private static void createAndShowGUI() 
{
    //1. Create the frame.
    JFrame frame = new JFrame("Defense Of The Origin");

    //2. Optional: What happens when the frame closes?
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    //4. Size the frame.
    frame.setSize(SIZEX, SIZEY);

    //5. Show it.
    frame.setVisible(true);

    // Here, create an instance of "DotO", and add it to the frame!
    frame.add(new DotO());
}

// In the DotO constructor, only do what has to be done
// specifically for this DotO instance:
public DotO()
{
    setBorder(BorderFactory.createLineBorder(Color.black));
    loadBackground();  
    setBackground(Color.white);  
}

But that may be considered as a detail now.


EDIT in response to the comment:

In order to paint multiple images, you can just load and paint them like the background image (but after the background image, for obvious reasons).

One could give many further recommendations here. Although strictly speaking, this is not the purpose of a Question+Answer site, but should be accomplished by reading tutorials and code samples.

So the Q&A purists: Please leave now, some non-answer stuff ahead:


I know that Swing is a "sweet poison": With few lines of code, you have your first frame with some image in it. But this does not mean that you dont have to plan and think ahead when creating a game. You can not just "write more code" and hope that "something nice" will come out.

Thus, I'd recommend you to first think about how the structure of your game should be. Which classes will you have? What should be the responsibility of each class, in terms of fields and methods that the class will have?

It's certainly not wrong to write "test snippets" for certain functionalities. For example, a test snippet for loading and displaying a background image ;-) But you can not create a game by only writing lots of code from scratch into a single class.

A guideline here occasionally is to describe in Words what you want to achieve. As an example (very "compressed", to illustrate the point) :

I want a tower that has a certain range and can shoot and can be painted on the screen

This can help to roughly derive a structure:

  • Nouns are Classes
  • Adjectives/Attributes are Fields
  • Verbs are methods

yielding a class like

class Tower {
    float range;
    void shoot() {...}
    void paintInto(Graphics g) {...}
}

(This is really only a very rough guideline!)

Additionally, there will be many details to consider. For example, you'll then notice that it might be beneficial to change your loadBackground() method into something like a

private void loadImage(String fileName)  
{  
    ...
}

method that can be called as

background = loadImage("resources/Background.jpg");
tower = loadImage("resources/Tower.jpg");

But again: These are things that you can learn from tutorials and code samples (and that you'll (hopefully) do automatically sooner or later)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top