Rof
Rof

Reputation: 53

graphics.setColor(color); not working

I'm trying to create a little tower defense game with colors but the colors aren't working here's how I draw rects do graphics.

public static void fill(GridLocation loc, Color c){
    Main.frame.getGraphics().setColor(c);
    Main.frame.getGraphics().fillRect(loc.toFrameLocation().x, loc.toFrameLocation().y, 20, 20);
    Main.frame.getGraphics().dispose();
}

and and this is how I call/create the JFrame

public static void main(String[] args) {
    frame = new JFrame("Tower defense");
    frame.setSize(1000, 700);
    frame.setVisible(true);
    frame.setLayout(null);
    frame.setLocationRelativeTo(null);
    frame.setResizable(false);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    while (frame.isVisible()){
        Grid.fill(new GridLocation(1,1), new Color(1F,0F,0F));
        Grid.fill(new GridLocation(2,1), Color.gray);
        Grid.drawGrid();
        Grid.fill(new GridLocation(3,1), Color.green);
    }
}

My problem: the rectangles are always black?

Upvotes: 3

Views: 7747

Answers (1)

Note that if you use getGraphics() on a component to get your Graphics context, the graphics thus obtained will not persist. For example in the code below, you'll see that if the button is pressed, a blue rectangle appears, but it then disappears if the GUI is minimized and later resized.

Also, as per my comments:

  1. Draw in the paintComponent method of a JPanel.
  2. Use a Swing Timer not a while (true) loop.
  3. Within that Timer, change the state of the drawing JPanel (change its fields), and then call repaint().
  4. Then have the paintComponent method use the fields to tell it how to draw.
  5. Don't forget to call the super's painting method within your override.

For example:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import javax.swing.*;

@SuppressWarnings("serial")
public class UnstableStableGraphics extends JPanel {
    private static final int PREF_W = 800;
    private static final int PREF_H = 400;
    private static final int GAP = 20;

    public UnstableStableGraphics() {
        add(new JButton(new DrawBlueRectAction()));
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.RED);
        int w = PREF_W / 2 - 2 * GAP;
        int h = PREF_H - 2 * GAP;
        g.fillRect(GAP, GAP, w, h);     
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(PREF_W, PREF_H);
    }

    private class DrawBlueRectAction extends AbstractAction {
        public DrawBlueRectAction() {
            super("Draw Unstable Blue Rectangle");
        }

        @Override
        public void actionPerformed(ActionEvent arg0) {
            Graphics g = getGraphics();
            g.setColor(Color.BLUE);
            int x = PREF_W / 2 + GAP;
            int w = PREF_W / 2 - 2 * GAP;
            int h = PREF_H - 2 * GAP;
            g.fillRect(x, GAP, w, h);
            g.dispose();
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }

    private static void createAndShowGui() {
        UnstableStableGraphics mainPanel = new UnstableStableGraphics();
        JFrame frame = new JFrame("UnstableStableGraphics");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(mainPanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
}

Having said that, it is perfectly fine to use a Graphics object obtained via getGraphics() called on a BufferedImage (as long as you dispose of the Graphics object when done, to conserve resources when done), and then display that image in the paintComponent method, often as a background image. Usually, however, I call createGraphics() on the BufferedImage since that returns the more powerful Graphics2D object, and not a Graphics object.

For example, including use of a background image, a sprite image and a Swing Timer:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

import javax.swing.*;

@SuppressWarnings("serial")
public class BackgroundExample extends JPanel {
    private static final int PREF_W = 600;
    private static final int PREF_H = PREF_W;
    private static final int SPRITE_W = 20;
    private static final Color SPRITE_COLOR = Color.RED;
    private static final int TIMER_DELAY = 20;
    private Image background = null;
    private Image sprite = null;
    private int spriteX = 0;
    private int spriteY = 0;

    public BackgroundExample() {
        background = createBackground();
        sprite = createSprite();

        new Timer(TIMER_DELAY, new TimerListener()).start();
    }

    private Image createSprite() {
        BufferedImage img = new BufferedImage(SPRITE_W, SPRITE_W, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = img.createGraphics();
        g2.setColor(SPRITE_COLOR);
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        int x = 1;
        int y = 1;
        int width = SPRITE_W -2;
        int height = SPRITE_W - 2;
        g2.fillOval(x, y, width, height);
        g2.dispose();
        return img;
    }

    private Image createBackground() {
        BufferedImage img = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = img.createGraphics();
        g2.setColor(Color.GREEN);
        g2.fillRect(0, 0, PREF_W, PREF_H);
        g2.setColor(Color.GRAY);
        int x = 0;
        int y = 0;
        g2.fillRect(x, y, 2 * SPRITE_W, 2 * SPRITE_W);
        x = PREF_W - 2 * SPRITE_W;
        g2.fillRect(x, y, 2 * SPRITE_W, 2 * SPRITE_W);
        y = PREF_H - 2 * SPRITE_W;
        g2.fillRect(x, y, 2 * SPRITE_W, 2 * SPRITE_W);
        x = 0;
        g2.fillRect(x, y, 2 * SPRITE_W, 2 * SPRITE_W);
        g2.dispose();
        return img;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (background != null) {
            g.drawImage(background, 0, 0, this);
        }
        if (sprite != null) {
            g.drawImage(sprite, spriteX, spriteY, this);
        }
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        } else {
            return new Dimension(PREF_W, PREF_H); 
        }
    }

    private class TimerListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            spriteX++;
            spriteY++;
            repaint();
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }

    private static void createAndShowGui() {
        BackgroundExample mainPanel = new BackgroundExample();
        JFrame frame = new JFrame("BackgroundExample");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

Upvotes: 6

Related Questions