if-statement inside of paintComponent makes it not paint

I'm trying to write a solitaire game. I would like to call repaint() when the game starts and paint the full deck once only the first time repaint is called, but when I add the if-statement it no longer paints. Here is the code with the if-statement:

private void paintInitialDeck(Graphics g, Card card){
    card.paintCard(g);               
}

public void paintComponent(Graphics g) {
    super.paintComponent(g);
    if (initialDrawing) {
        Card card;
        for (int i = 0; i < deck.size(); i++) {
            card = deck.get(i);
            card.setY((int) (50 + 0.2 * i));
            card.setX((int) (250 + 0.2 * i));

            paintInitialDeck(g, card);
        }
        initialDrawing = false;
    }
}  

It doesn't work, but if I remove the if statement and the initialDrawing = false then it works. Problem is, I need the if-statement. Anyone can help me understand this better?

ps.: initialDrawing is set to true to begin with. Also, it's really the initialDrawing = false that makes the whole thing not paint.

Answers


The straight-forward solution would be

if (initialDrawing) {
    Card card;
    for (int i = 0; i < deck.size(); i++) {
        card = deck.get(i);
        card.setY((int) (50 + 0.2 * i));
        card.setX((int) (250 + 0.2 * i));
    }
    initialDrawing = false;
}
for (Card card : deck) {
    card.paintCard(g);
}

This however suggests, that the initialisation should be done elsewhere, maybe in the constructor. In general painting code should do just painting and may be called several times.


What's happening is that with initial instantiation of that class with the paintComponent method, the paintComponent method is called once. So the paint will occur once, but after that, not again because the initiaDrawing is set to false after the first call to paintComponent in the initial instantiation. So a call to repaint() within the program would not work, as initialDrawing will be false after the first start up paint process.

I'm not sure if you see the paint occurring when you first start the program, but this is why, it won't allow you to paint again after the program has started.

A possible fix might be to initialize initialDrawing to false so it doesn't initially paint. Then whatever component calls the repaint() method, in the action, first set the inititialDrawing to true, then call repaint(). Disable that component so another call to repaint() cannot be made. (or something of this logical nature).

Here's an example

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class DisablePaint extends JPanel {

    ImagePanel panel;
    JButton button;
    boolean intialDraw = false;

    public DisablePaint() {
        button = new JButton("Paint Once");
        setLayout(new BorderLayout());
        panel = new ImagePanel();
        add(panel, BorderLayout.CENTER);
        add(button, BorderLayout.SOUTH);

        button.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e) {
                intialDraw = true;
                panel.repaint();
                button.setEnabled(false);
            }
        });
    }

    private class ImagePanel extends JPanel {

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (intialDraw) {
                g.setColor(Color.BLUE);
                g.fillRect(50, 50, 200, 200);
                            initialDraw = false;
            }
        }

        public Dimension getPreferredSize() {
            return new Dimension(300, 300);

        }
    }

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

    }

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

            }
        });
    }
}

You can see that initialDraw is first set to false, so it won't draw on initial start of program. I then make a call to repaint() in the actionPerformed, but first setting the intialDrawing to true. Then disable the button, not allowing a another initial painting


With the if statement your cards will only ever be drawn on the first call to paintComponent(). After that, the method will only invoke super.paintComponent() which erases any content that had previously been drawn on the component.

Since you don't have a lot of control over when paintComponent() is invoked it might be best to avoid including any behaviour related to it in your application's logic as you've done with the if-statement.

Here's an arbitrary block of code. Try compiling this example and see how many times "Repainted" is printed.

import javax.swing.*;
import java.awt.*;

public class Test {
    public static void main(String args[]) {
        JFrame frame = new JFrame();
        frame.add(new JPanel() {
            public void paintComponent(Graphics g)
            {
                super.paintComponents(g);
                System.out.println("Repainted");
            }
        });

        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setSize(200, 200);
        frame.setVisible(true);
    }
}

Need Your Help

Android : Creating GUI programmatically at run time in java

java android user-interface dynamic

I have to create number of buttons and textbox, etc. depending upon a certain number. For ex: if the number = 5, I need to create 5 buttons, and if its value is 10, I need to create 10 buttons.