Dynamic Graphics Object Painting
There are various strategies you might pursue for this.
- 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:- Get the graphics instance of the image and draw the new element.
- Dispose of the graphics object.
- Call
repaint()
on the label.
- 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:
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:
- This answer to How to draw an image over another image?
- 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
How to Use .Jar Files in Netbeans
How to Speed Up the Gwt Compiler
How Do Different Retention Policies Affect My Annotations
Spring Boot @Responsebody Doesn't Serialize Entity Id
Does Java Have Built in Libraries for Audio _Synthesis_
Using Itextpdf to Trim a Page's Whitespace
How to Create an Instance of an Interface in Java
Increase the Java Heap Size Permanently
Looking for an Example for Inserting Content into the Response Using a Servlet Filter
Can "This" Ever Be Null in Java
Why Does Gson Use Fields and Not Getters/Setters
How to Check That a String Is Parseable to a Double
Why Is My Uri Not Hierarchical
Varargs and the '...' Argument
How to Deploy Javafx Application, Create Jar and Self-Contained Applications and Native Installers