hugiuhjokol
hugiuhjokol

Reputation: 53

Drawing with a JPanel's getGraphics()?

I've run into a bit of a wall here. I read elsewhere while trying to fix this issue that you are never supposed to getGraphics(). The problem is, I can't use the provided Graphics context from the paint() / paintComponent() methods. I require it to only call my generate(Graphics g) function once, and I can not provide Graphics outside of the override functions.

Any tips? Trimmed for your convenience.

public class Main extends JPanel {

...
static JFrame displayFrame, inputFrame;

...
...

// Generator node list
ArrayList<Node> nodes = new ArrayList<Node>();

public static void main(String[] args) {
    // Set up the frame
    screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    displayFrame = new JFrame("City generator");
    displayFrame.setSize(screenSize.width / 3, screenSize.width / 3);
    displayFrame.setLocation(screenSize.width / 2 - displayFrame.getWidth()
            / 2, screenSize.height / 2 - displayFrame.getHeight() / 2);
    displayFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    displayFrame.add(new Main());
    // displayFrame.setUndecorated(true);

    displayFrame.setBackground(Color.lightGray);

    displayFrame.setVisible(true);

    displayFrame.addMouseMotionListener(new MouseAdapter() {
        public void mouseMoved(MouseEvent e) {
            // Mouse movement events here

        }
    });
}

// Override function
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    // Calls multiple times
    generate(g);
}

private void generate(Graphics g) {
............................

Upvotes: 0

Views: 1020

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347234

Instead of painting directly to the Graphics context, you could generate a BufferedImage image of what you want painted and paint to that instead...

private BufferedImage buffer;

public BufferedImage generate() {
    if (buffer == null) {
        buffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_IMAGE_ARGB);
        Graphics2D g2d = buffer.createGraphics();
        // Paint away...
        g2d.dispose();
    }
    return buffer;
}

Then you would paint the result within the paintComponent method...

public void paintComponent(Graphics g) {
    super.paintComponent(g);
    // Calls multiple times
    BufferedImage img = generate();
    g.drawImage(img, 0, 0, this);
}

As an example...

Upvotes: 1

Peter Quiring
Peter Quiring

Reputation: 1706

Why not just keep a boolean value to track if generate() has been called.

public boolean calledGenerate = false;

public void paintComponent(Graphics g) {
  super.paintComponent(g);
  if (!calledGenerate) generate(g);
}

void generate(Graphics g) {
  calledGenerate = true;
  ....
}

also you are calling AWT/Swing code outside of the EDT which is a bad idea.
In your main function you normally should call:

java.awt.EventQueue.invokeLater(new Runnable() {
  public void run() {
    //build your awt/swing objects here
  }
});

What does generate() do though? There is probably a better way to do it.

Upvotes: 0

Related Questions