JTextFields on top of active drawing on JPanel, threading problems
NewTest
extends JPanel
; but because you're not painting every pixel on each call to paintComponent()
, you need to invoke the super-class's method and erase the old drawing:
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int width = this.getWidth();
int height = this.getHeight();
g.setColor(Color.black);
g.fillRect(0, 0, width, height);
...
}
Addendum: As you note, setting the background color in the constructor precludes the need to fill the panel in paintComponent()
, while super.paintComponent()
allows the text field(s) to function correctly. As you observe, the proposed workaround is fragile. Instead, simplify the code and optimize as warranted. For example, you may not need the complication of insets, extra buffers and a component listener.
Addendum 2: Note that super.paintComponent()
calls the UI delegate's update()
method, "which fills the specified component with its background color (if its opaque property is true)." You can use setOpaque(false)
to preclude this.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;
/** @see http://stackoverflow.com/questions/3256941 */
public class AnimationTest extends JPanel implements ActionListener {
private static final int WIDE = 640;
private static final int HIGH = 480;
private static final int RADIUS = 25;
private static final int FRAMES = 24;
private final Timer timer = new Timer(20, this);
private final Rectangle rect = new Rectangle();
private BufferedImage background;
private int index;
private long totalTime;
private long averageTime;
private int frameCount;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new AnimationTest().create();
}
});
}
private void create() {
JFrame f = new JFrame("AnimationTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
timer.start();
}
public AnimationTest() {
super(true);
this.setOpaque(false);
this.setPreferredSize(new Dimension(WIDE, HIGH));
this.addMouseListener(new MouseHandler());
this.addComponentListener(new ComponentHandler());
}
@Override
protected void paintComponent(Graphics g) {
long start = System.nanoTime();
super.paintComponent(g);
int w = this.getWidth();
int h = this.getHeight();
g.drawImage(background, 0, 0, this);
double theta = 2 * Math.PI * index++ / 64;
g.setColor(Color.blue);
rect.setRect(
(int) (Math.sin(theta) * w / 3 + w / 2 - RADIUS),
(int) (Math.cos(theta) * h / 3 + h / 2 - RADIUS),
2 * RADIUS, 2 * RADIUS);
g.fillOval(rect.x, rect.y, rect.width, rect.height);
g.setColor(Color.white);
if (frameCount == FRAMES) {
averageTime = totalTime / FRAMES;
totalTime = 0; frameCount = 0;
} else {
totalTime += System.nanoTime() - start;
frameCount++;
}
String s = String.format("%1$5.3f", averageTime / 1000000d);
g.drawString(s, 5, 16);
}
@Override
public void actionPerformed(ActionEvent e) {
this.repaint();
}
private class MouseHandler extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
super.mousePressed(e);
JTextField field = new JTextField("test");
Dimension d = field.getPreferredSize();
field.setBounds(e.getX(), e.getY(), d.width, d.height);
add(field);
}
}
private class ComponentHandler extends ComponentAdapter {
private final GraphicsEnvironment ge =
GraphicsEnvironment.getLocalGraphicsEnvironment();
private final GraphicsConfiguration gc =
ge.getDefaultScreenDevice().getDefaultConfiguration();
private final Random r = new Random();
@Override
public void componentResized(ComponentEvent e) {
super.componentResized(e);
int w = getWidth();
int h = getHeight();
background = gc.createCompatibleImage(w, h, Transparency.OPAQUE);
Graphics2D g = background.createGraphics();
g.clearRect(0, 0, w, h);
g.setColor(Color.green.darker());
for (int i = 0; i < 128; i++) {
g.drawLine(w / 2, h / 2, r.nextInt(w), r.nextInt(h));
}
g.dispose();
System.out.println("Resized to " + w + " x " + h);
}
}
}
Adding JTextfield to JPanel over paint layer
Click anywhere on this AnimationTest
to add a text field. Note the use of invokeLater()
and the call to super.paintComponent(g)
. Resize the frame to see how the default layout works.
Drawing a rectangle in a JPanel, snapped to the nearest x pixels
Well, I assume you have two Point
objects (start, end), so you can create a little method to adjust the values.
Here is a simple example to get your started:
import java.awt.*;
public class Main
{
public static void main(String[] args) throws Exception
{
Point start = new Point(103, 105);
Point end = new Point(203, 205);
adjust(start, 4, true);
adjust(end, 4, false);
System.out.println(start);
System.out.println(end);
}
public static void adjust(Point p, int snap, boolean snapLower)
{
int modX = p.x % snap;
p.x = snapLower ? p.x - modX : p.x + snap - modX;
int modY = p.y % snap;
p.y = snapLower ? p.y - modY : p.y + snap - modY;
}
}
Java Swing: paint under components of a JPanel?
I think you want to override paintComponent()
not paint()
.
paint()
usually doesn't do any painting but delegates to paintComponent()
, paintBorder()
and paintChildren()
.
see javax.swing.JComponent.paint()
for more info
Example:
@Override
public void paintComponent(Graphics g) {
/* your draw code here */
}
You could call super.paintComponent(g); to draw the component as usual but can be omitted.
Swing active rendering efficiency or how to combine active rendering with gui widgets
I have a few observations:
Your improved
repaintDrawTime()
is very readable, but it is a micro-benchmark and subject to the vagaries of the host OS. I can't help wondering if the XP results are an artifact of that system's limited clock resolution. I see very different results on Windows 7 and Ubuntu 10.If you don't use a null layout, you won't need the extra panel; the default layout for
JPanel
isFlowLayout
, andf.add(this)
simply adds it to the center of the frame's defaultBorderLayout
.Repeated constructor invocations can be time consuming.
Consider replacing
g.setColor(new Color(0, 128, 0, 100));
with
private static final Color color = new Color(0, 128, 0, 100);
...
g.setColor(color);Alternatively, a simple color lookup table, may be useful, e.g.
private final Queue<Color> clut = new LinkedList<Color>();
Prevent JPanel from redrawing background on repaint() calls
I'd recommend to build your code upon the already existent code provided by the API instead of messing with it. Just store the image as BufferedImage
. This allows you to display it using an ImageIcon
, so it's an additional simplification. This allows you to update single pixels without any hassles with the API. If you absolutely insist on excluding the JPanel
from the repaint-routine, this question might help.
In general:
Follow the conventional use of the API. If you want to permanently store data of an image, us a BufferedImage
. JComponents
are supposed to be entirely overridden every time the frame is updated.
Related Topics
Getting a File'S Md5 Checksum in Java
How to Nicely Format Floating Numbers to String Without Unnecessary Decimal 0'S
Equals VS Arrays.Equals in Java
Resultset Exception - Before Start of Result Set
Socket Using in a Swing Applet
Why Is the Java Date API (Java.Util.Date, .Calendar) Such a Mess
What Is "String Args[]"? Parameter in Main Method Java
Syntax For Creating a Two-Dimensional Array in Java
What Is a Nosuchbeandefinitionexception and How to Fix It
Difference Between Wait() and Sleep()
What Is the Concept of Erasure in Generics in Java
How to Do a Deep Copy of a 2D Array in Java
Difference Between Volatile and Synchronized in Java
How Can a Java Program Get Its Own Process Id