Dynamic Graphics Object Painting

Dynamic Graphics Object Painting

There are various strategies you might pursue for this.

  1. If the objects are never removed from the drawing once done, use a BufferedImage, put it in a (ImageIcon in a) JLabel. When it comes time to update:

    1. Get the graphics instance of the image and draw the new element.
    2. Dispose of the graphics object.
    3. Call repaint() on the label.
  2. Keep a list of the drawn elements. In the paint method, paint them all. When a new element is added, call repaint() on the rendering component.

Here is an example of the 1st technique:

MyCanvas

import java.awt.image.BufferedImage;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;

public class MyCanvas
{
JLabel view;
BufferedImage surface;
Random random = new Random();

public MyCanvas()
{
surface = new BufferedImage(600,400,BufferedImage.TYPE_INT_RGB);
view = new JLabel(new ImageIcon(surface));
Graphics g = surface.getGraphics();
g.setColor(Color.ORANGE);
g.fillRect(0,0,600,400);
g.setColor(Color.BLACK);
// Keep this until I figured out if it's painted on load or not.
g.drawLine(10, 20, 350, 380);
g.dispose();

ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
addNewElement();
}
};
Timer timer = new Timer(200, listener);
timer.start();
}

public void addNewElement() {
boolean drawArc = random.nextBoolean();
int x = random.nextInt(60);
int y = random.nextInt(40);
Graphics g = surface.getGraphics();
if (drawArc) {
g.setColor(Color.BLUE);
int xx = random.nextInt(60);
int yy = random.nextInt(40);
drawArc(x,y,xx,yy,g);
} else {
drawNode(x,y,g);
}
g.dispose();
view.repaint();
}

public static void main(String[] args)
{
MyCanvas canvas = new MyCanvas();
JFrame frame = new JFrame();
int vertexes = 0;
// Change this next part later to be dynamic.
vertexes = 10;
int canvasSize = vertexes * vertexes;
frame.setSize(canvasSize, canvasSize);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(canvas.view);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}

public void drawNode(int x, int y, Graphics g)
{
// Treat each location as a 10x10 block. If position 1,1 then go to (5,5) - If position 3,5 then go to (25, 45) eg: (x*10)-5, (y*10)-5
int xLoc = (x*10) - 5;
int yLoc = (y*10) - 5;
g.setColor(Color.white);
g.fillOval(xLoc, yLoc, 8, 8);
g.drawOval(xLoc, yLoc, 8, 8);
}

public void drawArc(int x, int y, int xx, int yy, Graphics g)
{
int xLoc = (x*10) - 5;
int yLoc = (y*10) - 5;
int xxLoc = (xx*10) - 5;
int yyLoc = (yy*10) - 5;
g.drawLine(xLoc, yLoc, xxLoc, yyLoc);
}
}

Further tip

You might notice that the lines look quite 'jagged' & ugly. Both the BufferedImage or a JComponent has access to the more useful Graphics2D object (for the JComponent it is necessary to cast it in paintComponent()). A Graphics2D instance accepts rendering hints that can be used to smooth (dither) the elements drawn.

Swing custom painting: should `Graphic` object be disposed?

You should not dispose of the Graphics object unless your code creates the Graphics object.

The paint() method of JComponent will create a Graphics object and pass it to the three painting methods of each component.
See: A Closer Look at the Painting Mechanisn.

The paint() method will then dispose() of this temporary Graphics object when painting of the component is finished. Check out the code at: https://github.com/openjdk/jdk/blob/master/src/java.desktop/share/classes/javax/swing/JComponent.java

If you manually create a Graphics object then you should dispose it:

Graphics2D g2d = (Graphics2D)g.create();

// do custom painting

g2d.dispose();

Typically it is a good idea to create a copy of the passed Graphics object if you intend to alter the painting by adding an AffineTransform, for example, to the Graphics.

Using a paintComponent with layout

Another way to paint (besides custom painting) is to paint to a BufferedImage. The image can then be displayed in a JLabel.

Examples:

  • Painting in a BufferedImage inside Swing A fairly complicated one.
  • Dynamic Graphics Object Painting Another one.
  • Yet another one.

Dynamically Drawing

public class Triangle extends JPanel { 

This class should not extend a JComponent like JPanel.

Instead it should provide a draw(Graphics) method that will paint the triangle when needed. Then store a list (e.g. ArrayList) of those Triangle objects and have it within the scope of a custom painted JPanel that paints them all at the same time. The custom painted panel should also return a sensible dimension for preferred size (that takes into account the bounds of the entire list of triangles to be painted).

Auto calls to painting methods (Java) when I'm app-triggering (not interested in synchronously but async) in a loop

..this auto painting cleans the screen which makes me draw everything once again.

Draw it to a BufferedImage displayed in a JLabel. When the data (the image) updates call label.repaint().

E.G. as seen in:

  1. This answer to How to draw an image over another image?


  2. This answer to Dynamic Graphics Object Painting.

Components don't show up after painting

Because you don't invoke super.paint(g) the child components don't get painted.

Read the section from the Swing tutorial on A Closer Look at the Painting Mechanism for more information.

However you should NOT be overriding paint() anyway. Custom painting is done by overriding the paintComponent() method.

The code should be:

public void paintComponent(Graphics g)
{
super.paintComponent(...);
...

C# painting Graphics on Bitmap dynamically dillema

Well you need either two Bitmaps, one to use for overdrawing and one as the source or you need to create the result dynamically each time.

In any case you need to

  • keep the original graphics ready
  • dispose of the combination when done with it

I suggest to keep things simple and create a result image upon SelectionChanged:

Bitmap diplomaBackground = null;  // load upon startup
Bitmap result = null;

private void dataGridView1_SelectionChanged(object sender, EventArgs e)
{
if (result != null)
{
if (pb_preview.Image != null) pb_preview.Image = null;
result.Dispose();
}

if (dataGridView1.SelectedRows.Count > 0)
{
result = CreateNewDiploma(dataGridView1.SelectedRows[0].Index);
pb_preview.Image = result;
}
}

Bitmap CreateNewDiploma(int rowIndex)
{
Bitmap bmp = new Bitmap(diplomaBackground);

using (Graphics G = Graphics.FromImage(bmp))
{
// draw the data..
}
return bmp;
}

Set the preview box to zoom.

Dynamic graphic programming (Animation)

Here is how to make a growing rectangle:

public class MovingRectangle extends JPanel {
private Timer timer = new Timer(500, new ActionListener() {
public void actionPerformed(ActionEvent event) {
rectWidth += 100;
repaint();
}
};

private int rectWidth = 100;

public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(0, 0, 100. rectWidth);
}

public void start() {
timer.start();
}

public void stop() {
timer.stop();
}

public void reset() {
rectWidth = 100;
repaint();
}
}


Related Topics



Leave a reply



Submit