Painted content invisible while resizing in Java
Okay, I finally fixed it.
Instead of redrawing it every time in the paint(Graphics g)
-method, you need to buffer the output and only redraw that image (I kinda hoped Java would be already doing that, just like Obj-C).
public BufferedImage buffer;
public void redraw() {
buffer = new BufferedImage(
200, // height
300, // width
BufferedImage.TYPE_4BYTE_ABGR); // ABGR = RGBA, 4-byte (r, g, b, a) per pixel
Graphics g = buffer.getGraphics();
// do your drawing here
if (this.getGraphics()) {
// 'this' is already shown, so it needs a redraw
this.paint(this.getGraphics()); // little hack
}
}
public void update(Graphics g) {
this.paint(g);
}
public void paint(Graphics g) {
g.drawImage(buffer, 0, 0, this);
}
Now, when you minimize the window and maximize it again, the paintings remain. Only, the window's flickering now for .1-second or so, but I don't really care about that.
no repaint while resizing when using .setPaint(gradient)
I put together a test and found that the GradientPaint
has woeful performance. Taking an average render time from 1.2 seconds (at 400x400 pixles) out to 20+ seconds.
I changed the GradientPaint
for a LinearGradientPaint
and found that the render time was around 1.3 seconds instead.
LinearGradientPaint lgp = new LinearGradientPaint(
new Point2D.Float(0, minY),
new Point2D.Float(0, maxY),
new float[] {0f, 0.5f, 1f},
new Color[] {Color.BLUE, Color.RED, Color.BLUE}
);
g2d.setPaint(lgp);
// Render all your samples, don't reapply or change you paint...
Sorry, my sample isn't very exciting...
You may find it better to render to a backing buffer in a background thread instead and paint the whole image to the screen once it's complete. This will stop the screen from becoming "paused"
Panel visible only after resizing [Java]
public void classAttitudes() {
variables.classesTitleLabel.setVisible(false);
variables.classesTitlePanel.setVisible(false);
variables.continueClassPanel.setVisible(false);
variables.titleAttitudePanel = new JPanel();
variables.titleAttitudePanel.setBounds(50, 50, 100, 100);
variables.con.add(variables.titleAttitudePanel);
// ADD MANUAL REPAINT TO THE FRAME !!!
variables.window.repaint();
}
P.S. When you resize you manin window (i.e. JFrame
) an action is thrown and at the end of this action repaint()
is invoke to repaint this frame with all content from UI thread (I do not remember it's name)
Keeping a circle centered when the frame is resized
This example centers the circle and adjusts the size to the smaller dimension, but you can make d
constant. The essential step is to render relative to the panel's current size. Resize the enclosing frame to see the effect. Adding RenderingHints
, seen here, makes the drawing smother.
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Dimension size = this.getSize();
int d = 200;
int x = (size.width - d) / 2;
int y = (size.height - d) / 2;
g.fillOval(x, y, d, d);
g.setColor(Color.blue);
g.drawOval(x, y, d, d);
}
Changes to the example:
$ diff OldSwingPaint.java SwingPaint.java
38a39,41
> Graphics2D g2d = (Graphics2D) g;
> g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
> RenderingHints.VALUE_ANTIALIAS_ON);
40c43
< int d = Math.min(size.width, size.height) - 10;
---
> int d = 200;
AWT paints only last-added Canvas
You neglect to pack()
the enclosing Window
. Note the characteristic symptom in your original code: resizing the frame, which generates an update, causes elypse2
to appear.
Addendum: You can see both Elypse
instances by using a layout such as GridLayout
.
testFrame.setLayout(new GridLayout(0, 1));
As tested:
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Point;
public class Test {
public static void main(String[] args) {
Frame testFrame = new Frame("Grafx-Test");
testFrame.setAlwaysOnTop(true);
Elypse elypse = new Elypse(new Point(70, 80), 30, 30, Color.BLUE, false);
testFrame.add(elypse);
Elypse elypse2 = new Elypse(new Point(70, 50), 50, 30, Color.BLUE, true);
testFrame.add(elypse2);
testFrame.pack();
testFrame.setVisible(true);
}
private static class Elypse extends Canvas {
private Point start;
private int width;
private int height;
private Color c;
private boolean filled;
public Elypse(Point start, int width, int height, Color c, boolean filled) {
this.start = start;
this.width = width;
this.height = height;
this.c = c;
this.filled = filled;
}
@Override
public void paint(Graphics g) {
g.setColor(c);
if (filled) {
g.fillOval(start.x, start.y, width, height);
} else {
g.drawOval(start.x, start.y, width, height);
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
}
}
JComponents only appear after resizing
By default the size of all components is (0, 0), so there is nothing to paint.
Components need to be added to the frame BEFORE the setVisible() method. Then when the frame is made visible the layout manager is invoked and components are given a size/location.
Related Topics
Finding Number of Cores in Java
Why Is Java.Util.Observable Not an Abstract Class
Printing Even and Odd Using Two Threads in Java
Which Concurrent Queue Implementation Should I Use in Java
Converting a Jfreechart Timeseries Series with Day Data to Week or Month Data
Why Does My Spring Boot App Always Shutdown Immediately After Starting
Why Should I Use Deque Over Stack
Java Equivalent to #Region in C#
How to Clear or Empty a Stringbuilder
How I Save and Retrieve an Image on My Server in a Java Webapp
What Determines Kafka Consumer Offset
Correct Way of Throwing Exceptions with Reactor
How Does Java Store Strings and How Does Substring Work Internally
Convert Arraylist into 2D Array Containing Varying Lengths of Arrays