I have a custom class which extends JPanel and overrides the paintComponent() method. Here's what that looks like:

@Override
protected void paintComponent(Graphics g)
{
    if(redrawRequested)
    {
        g.setColor(ETCH_BACKGROUND_COLOR);
        g.fillRect(0, 0, owner.getAppWidth(), owner.getAppHeight());
        redrawRequested = false;
    }

    g.setColor(Color.BLACK);
    g.fillRect(pointX, pointY, PIXEL_SIZE, PIXEL_SIZE);
}

The same custom class also implements KeyListener. I am listening for some keys, and more specifically Space which calls a method requestRepaint(). Here's what that method looks like:

public void requestRepaint()
{
    redrawRequested = true;
    revalidate();
    repaint();
}

My problem is, when the program starts, whats in the if block inside paintComponent get's fired but the fillRect doesn't work(?) or is not the right color. I have checked my custom color ETCH_BACKGROUND_COLOR and it isn't null and it carries the correct values. Also, the the redrawRequested boolean is true, like I said the if IS BEING FIRED.

I have tried forcing the panel to do a requestRepaint() after the frame is visible, I have tried doing it after a Thread.sleep() and neither accomplishes drawing the background color properly.
The ONLY way I have gotten this to work is when I use AWT's Robot and simulate a key press on the Space key.

Any ideas why this isn't working?

Have you checked owner.getAppWidth/Height? Maybe those values have not yet been initialised when the panel is painted for the very first time?

Edited 1 Year Ago by JamesCherrill

Yup, I did. They were the correct values.

I added some debug code for some output. Here's the new paintComponent():

@Override
protected void paintComponent(Graphics g)
{
    System.out.println("redrawRequested: " + redrawRequested);
    if(redrawRequested)
    {
        System.out.println("Color: [" + ETCH_BACKGROUND_COLOR.getRed() + ", " + ETCH_BACKGROUND_COLOR.getGreen() + ", " + ETCH_BACKGROUND_COLOR.getBlue() + "]");
        System.out.println("Width: " + owner.getAppWidth() + ", Height: " + owner.getAppHeight());
        g.setColor(ETCH_BACKGROUND_COLOR);
        g.fillRect(0, 0, owner.getAppWidth(), owner.getAppHeight());
        redrawRequested = false;
    }

    g.setColor(Color.BLACK);
    g.fillRect(pointX, pointY, PIXEL_SIZE, PIXEL_SIZE);
}

And here's the output I got:

redrawRequested: true
Color: [200, 200, 175]
Width: 1200, Height: 800
redrawRequested: false
redrawRequested: false

Process finished with exit code 0

Edited 1 Year Ago by Doogledude123: Added debug code

OK. Excellent!

So we would expect to see (some of?) a 1200x800 rectangle coloured in some kind of yucky pale grey/green. What do you actually see?

Edited 1 Year Ago by JamesCherrill

I tried to reproduce your problem I edited your code into a little class

    class MP extends JPanel {

        {
            setSize(400, 400);
        }
        boolean redrawRequested = true;
        Color ETCH_BACKGROUND_COLOR = new Color(200, 200, 175);

        @Override
        protected void paintComponent(Graphics g) {
            System.out.println("redrawRequested: " + redrawRequested);
            if (redrawRequested) {
                System.out.println("Color: [" + ETCH_BACKGROUND_COLOR.getRed() + ", " + ETCH_BACKGROUND_COLOR.getGreen() + ", " + ETCH_BACKGROUND_COLOR.getBlue() + "]");
                System.out.println("Width: " + 1200 + ", Height: " + 800);
                g.setColor(ETCH_BACKGROUND_COLOR);
                g.fillRect(0, 0, 1200, 800);
                redrawRequested = false;
            }
            g.setColor(Color.BLACK);
            g.fillRect(10, 10, 10, 10);
        }
    }

and added a new MP()to a JFrame and it displayed a black small square on a yucky grey/green background.

... which leads me to suspect we are looking in the wrong place?

Edited 1 Year Ago by JamesCherrill

Well, maybe it's an issue with adding it to the JFrame. Here's my application code that is called in the main method like this: new Etch(1200, 800);

private Etch(int initWidth, int initHeight)
{
    appWidth = initWidth;
    appHeight = initHeight;

    JFrame appFrame = new JFrame(APP_NAME + " - " + APP_VERSION);
    appFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    appFrame.setResizable(false);
    appFrame.setPreferredSize(new Dimension(appWidth, appHeight));

    sketchPanel = new SketchPanel(this);

    appFrame.add(sketchPanel);
    appFrame.addKeyListener(sketchPanel);

    appFrame.pack();

    appFrame.setLocationRelativeTo(null);
    appFrame.setVisible(true);

    /*try
    {
        Robot r = new Robot();
        r.keyPress(KeyEvent.VK_SPACE);
        r.keyRelease(KeyEvent.VK_SPACE);
    }
    catch(AWTException e)
    {
        e.printStackTrace();
    }*/
}

public int getAppWidth()
{
return appWidth;
}

public int getAppHeight()
{
return appHeight;
}

Here's the full SketchPanel class.

package com.geodox.etch;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

/**
 * Panel which controls drawing and handles key events
 *
 * Created by GeoDoX on 2015-10-05.
 */
public class SketchPanel extends JPanel implements KeyListener
{
    private static final int PIXEL_SIZE = 6;
    private static final Color ETCH_BACKGROUND_COLOR = new Color(200, 200, 175);

    private static final int ARROW_UP = KeyEvent.VK_UP;
    private static final int ARROW_LEFT = KeyEvent.VK_LEFT;
    private static final int ARROW_DOWN = KeyEvent.VK_DOWN;
    private static final int ARROW_RIGHT = KeyEvent.VK_RIGHT;
    private static final int W = KeyEvent.VK_W;
    private static final int A = KeyEvent.VK_A;
    private static final int S = KeyEvent.VK_S;
    private static final int D = KeyEvent.VK_D;
    private static final int CLEAR = KeyEvent.VK_SPACE;

    private EtchASketch owner;

    private int pointX, pointY;
    private boolean redrawRequested;

    protected SketchPanel(EtchASketch owner)
    {
        this.owner = owner;
        redrawRequested = true;

        pointX = 0;
        pointY = 0;
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        System.out.println("redrawRequested: " + redrawRequested);
        if(redrawRequested)
        {
            System.out.println("Color: [" + ETCH_BACKGROUND_COLOR.getRed() + ", " + ETCH_BACKGROUND_COLOR.getGreen() + ", " + ETCH_BACKGROUND_COLOR.getBlue() + "]");
            System.out.println("Width: " + owner.getAppWidth() + ", Height: " + owner.getAppHeight());
            g.setColor(ETCH_BACKGROUND_COLOR);
            g.fillRect(0, 0, owner.getAppWidth(), owner.getAppHeight());
            redrawRequested = false;
        }

        g.setColor(Color.BLACK);
        g.fillRect(pointX, pointY, PIXEL_SIZE, PIXEL_SIZE);
    }

    @Override
    public void keyPressed(KeyEvent e)
    {
        int tempX = pointX, tempY = pointY;

        switch (e.getKeyCode())
        {
            case ARROW_UP:
            case W:
                if(isInBounds(pointX, pointY - PIXEL_SIZE))
                    pointY -= PIXEL_SIZE;
                break;
            case ARROW_LEFT:
            case A:
                if(isInBounds(pointX - PIXEL_SIZE, pointY))
                    pointX -= PIXEL_SIZE;
                break;
            case ARROW_DOWN:
            case S:
                if(isInBounds(pointX, pointY + PIXEL_SIZE))
                    pointY += PIXEL_SIZE;
                break;
            case ARROW_RIGHT:
            case D:
                if(isInBounds(pointX + PIXEL_SIZE, pointY))
                    pointX += PIXEL_SIZE;
                break;
            case CLEAR:
                requestRepaint();
                break;
        }

        if(tempX != pointX || tempY != pointY || redrawRequested)
            requestRepaint();
    }

    @Override
    public void keyReleased(KeyEvent e)
    {

    }

    @Override
    public void keyTyped(KeyEvent e)
    {

    }

    public void requestRepaint()
    {
        redrawRequested = true;
        revalidate();
        repaint();
    }

    private boolean isInBounds(int x, int y)
    {
        return x >= 0 && x <= owner.getAppWidth() && (y >= 0 && y <= owner.getAppHeight());
    }
}

No, sorry, can't see any problems their either. This is baffling!

ps: I see you are defining local constrants to save typing KeyEvent. All the time
Do you know about import static?

import static java.awt.event.KeyEvent.*;

Then you can just use the public static members from that class without needing to qualify them. eg case VK_UP;

It's not just the save of time/space. You shoiuld assume that somene treading yur code knows the relevant Java, so VK_SPACE will be recognised but CLEAR could be anything.

Comments
Nice tip with the static, I do know it so I'm not sure why I didn't bother using it.

Just another long-shot guess...

Try setting the size of the SketchPanel in its constructor - JPanels tend to be 0,0 size until you put something in them or use a parent's layout manager that sets their size.

What makes this all the more annoying is that your code is so beautifully written and presented. Anything that professional really should work!

Could it possibly be that I'm setting the sketchpanel to be the JFrames KeyListener, and also adding it as a component?

This article has been dead for over six months. Start a new discussion instead.