Just out of intellectual interest can you make a Canvas not flicker when doing a manual resize.
public class FlickerAWT extends Canvas {
public static void main(String[] args) {
Frame f = new Frame(str);
//this line change nothing
//JFrame f = new JFrame(str);
f.add(new FlickerAWT());
f.pack();
int frameWidth = f.getWidth();
int frameHeight = f.getHeight();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
f.setLocation(screenSize.width / 2 - frameWidth / 2, screenSize.height / 2 - frameHeight / 2);
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowDeiconified(WindowEvent e) {
}
public void windowIconified(WindowEvent e) {
}
});
}
private Color bgColor; private Color contentColor;
Font f = new Font("Georgia", Font.BOLD, 16);
static String str = "AWT Canvas Resize Flickering";
public FlickerAWT() {
Random r = new Random();
bgColor = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256));
contentColor = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256));
}
public Dimension getPreferredSize() {
FontMetrics fm = getFontMetrics(f);
return new Dimension(fm.stringWidth(str) + 20, fm.getHeight() + 10);
}
public void paint(java.awt.Graphics g) {
g.setColor(bgColor);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(contentColor);
g.setFont(f);
FontMetrics fm = g.getFontMetrics(f);
int dx = getWidth() / 2 - (fm.stringWidth(str) / 2);
int dy = getHeight() / 2 + (fm.getHeight() / 2);
g.drawString(str, dx, dy);
}
}
You can copy paste in a Java editor and run the example.
You can add this to the beginning of your main method to avoid the background flicker:
System.setProperty("sun.awt.noerasebackground", "true");
I know this question is ancient, but it came up during my search and I meanwhile found a solution:
There are two problems:
On the one hand, the update(...) method of java.awt.Container looks like the following:
public void update(Graphics g) {
if (isShowing()) {
if (! (peer instanceof LightweightPeer)) {
g.clearRect(0, 0, width, height);
}
paint(g);
}
}
I.e. it calls g.clearRect(...) to erase the current content before painting its children.
Therefore, you need to override update(...) in every descendant of java.awt.Container in your view-stack, that doesn't already do so, with something like:
public void update(Graphics g) {
if (isShowing()) paint(g);
}
Also, it seems that AWT or the JVM or whoever (haven't figured this out yet) also clears the background of the main window, independent of any Container's update-methods. To prevent this, follow #WhiteFang34's suggestion and add the following line to your code somewhere:
System.setProperty("sun.awt.noerasebackground", "true");
Only doing both of these things finally solved my flicker issues...
The key I believe is to use double buffering, and one way to possibly solve this is to use Swing which double buffers by default:
import java.awt.*;
import java.util.Random;
import javax.swing.*;
public class FlickerSwing extends JPanel {
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
private static void createAndShowGui() {
JFrame f = new JFrame(str);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new FlickerSwing());
f.setLocationRelativeTo(null);
f.pack();
f.setVisible(true);
}
private Color bgColor;
private Color contentColor;
Font f = new Font("Georgia", Font.BOLD, 16);
static String str = "Swing Resize Flickering";
public FlickerSwing() {
Random r = new Random();
bgColor = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256));
contentColor = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256));
setBackground(bgColor);
}
public Dimension getPreferredSize() {
FontMetrics fm = getFontMetrics(f);
return new Dimension(fm.stringWidth(str) + 20, fm.getHeight() + 10);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(contentColor);
g.setFont(f);
FontMetrics fm = g.getFontMetrics(f);
int dx = getWidth() / 2 - (fm.stringWidth(str) / 2);
int dy = getHeight() / 2 + (fm.getHeight() / 2);
g.drawString(str, dx, dy);
}
}
Related
I need to show an image in a java applet, with a text element (label) to move to a point chosen by the user. Is it possible by dragging and dropping the text over the image? What methods would I need to use?
I am looking for something similar to this.
Edit: Thanks you for your useful response. The code below works fine! But how to get a text position by x,y coordinates within the image?
public class MouseDragTest extends JPanel {
private static final String TITLE = "Drag me!";
private static final int W = 640;
private static final int H = 480;
private Point textPt = new Point(W / 2, H / 2);
private Point mousePt;
Image img;
public MouseDragTest() {
img = Toolkit.getDefaultToolkit().createImage("my_image.jpg");
this.setFont(new Font("Serif", Font.ITALIC + Font.BOLD, 32));
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
mousePt = e.getPoint();
repaint();
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
int dx = e.getX() - mousePt.x;
int dy = e.getY() - mousePt.y;
textPt.setLocation(textPt.x + dx, textPt.y + dy);
mousePt = e.getPoint();
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(W, H);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int w2 = g.getFontMetrics().stringWidth(TITLE) / 2;
g.drawImage(img, 0, 0, null);
g.drawString(TITLE, textPt.x - w2, textPt.y);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame(TITLE);
f.add(new MouseDragTest());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}
You can use drawImage() in paintComponent() to show your invoice, like they show here, and drag the text, like they show here. Another way is to use the The Glass Pane.
How to get a text position by x,y coordinates within the image?
It sounds like you want to edit the text and location repeatedly. When you're done dragging, textPt will be the point at which you want to draw the text when you next load that image. You can store the details in java.util.Preferences and restore them when you restart.
private static class AnnotatedImage {
File file;
List<String> notes;
List<Point> points;
}
As you are using createImage(), use this as the image observer when drawing.
g.drawImage(img, 0, 0, this);
I want to rotate a rectangle in a method but do not understand how to do it and tried as follows:
private void setBoundaryRotate(Rectangle b, int radio) {
AffineTransform transform = new AffineTransform();
transform.rotate(Math.toRadians(45), b.getX() + b.width/2, b.getY() + b.height/2);}
Thanks for all.
You need to call the transform() method on your transform object, passing in the co-ordinates of your rectangle in an array.
This is a little subjective, it all depends on what it is you want to achieve.
The following code uses an AffineTransform to rotate the rectangle, but in order to do so, I need to get a PathIterator and add it back to Path2D
public class SpinBox {
public static void main(String[] args) {
new SpinBox();
}
public SpinBox() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new SpinPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class SpinPane extends JPanel {
private Rectangle box = new Rectangle(0, 0, 100, 100);
private float angle = 0;
public SpinPane() {
Timer timer = new Timer(1000/60, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
angle += 1;
repaint();
}
});
timer.setRepeats(true);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth() - 1;
int height = getHeight() - 1;
int x = (width - box.width) / 2;
int y = (height - box.height) / 2;
Graphics2D g2d = (Graphics2D) g.create();
AffineTransform at = new AffineTransform();
at.rotate(Math.toRadians(angle), box.x + (box.width / 2), box.y + (box.height / 2));
PathIterator pi = box.getPathIterator(at);
Path2D path = new Path2D.Float();
path.append(pi, true);
g2d.translate(x, y);
g2d.draw(path);
g2d.dispose();
}
}
}
I'm trying to create a simple JFrame window in OS X and render a simple black square on it like so using Graphics2d:
public Start() {
running = true;
window = new JFrame("Finest Hour");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setPreferredSize(new Dimension(500, 500));
window.setSize(window.getPreferredSize());
FullScreenUtilities.setWindowCanFullScreen(window, true);
window.setIgnoreRepaint(true);
window.setVisible(true);
window.createBufferStrategy(2);
strategy = window.getBufferStrategy();
}
public static void main(String[] args) {
Start s = new Start();
s.loop();
}
public void loop() {
Random random = new Random();
while(running) {
Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
g.setColor(Color.black);
g.fillRect(20, 20, 40, 40);
strategy.show();
}
}
However the window doesyn't seem to have rounded corners at the bottom when I use strategy.show(); :
Rendering it without the buffer strategy, i.e: Graphics2D = (Graphics2D) window.getGraphics(); produces a window with rounded corners:
I know it's a really small problem but it's annoying none the less. Any way to fix this?
Works fine for me.
public class TestMacFrame extends JFrame {
public TestMacFrame() throws HeadlessException {
super("Testing");
setSize(200, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new BorderLayout());
add(new PaintPane());
setVisible(true);
}
protected class PaintPane extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth() - 1;
int height = getHeight() - 1;
g.setColor(Color.BLACK);
int blockWidth = width / 2;
int blockHeight = height / 2;
int x = (width - blockWidth) / 2;
int y = (height - blockHeight) / 2;
g.fillRect(x, y, blockWidth, blockHeight);
}
}
public static void main(String[] args) {
new TestMacFrame();
}
}
Now, I have no idea what it is you're trying to, but I can tell you this:
public void loop() {
Random random = new Random();
while(running) {
Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
g.setColor(Color.black);
g.fillRect(20, 20, 40, 40);
strategy.show();
}
}
Is a bad idea. Firstly as SoboLAN pointed out, you're trying to update a UI component out side the Event Dispatching Thread. Swing components are not Thread safe.
Secondly, this loop will eventually chew up your CPU cycles, making you application unusable as well as you overall system.
UPDATED with Animation
Here, try this. This is a really BASIC example ;)
public class TestMacFrame extends JFrame {
private float angel = 0;
private Timer timer;
public TestMacFrame() throws HeadlessException {
super("Testing");
setSize(200, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new BorderLayout());
add(new PaintPane());
setVisible(true);
timer = new Timer(25, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
angel += 1;
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.setInitialDelay(0);
timer.start();
}
protected class PaintPane extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int width = getWidth() - 1;
int height = getHeight() - 1;
g.setColor(Color.BLACK);
int blockWidth = width / 2;
int blockHeight = height / 2;
int x = (width - blockWidth) / 2;
int y = (height - blockHeight) / 2;
g2d.setTransform(AffineTransform.getRotateInstance(Math.toRadians(angel), width / 2, height / 2));
g2d.fillRect(x, y, blockWidth, blockHeight);
g2d.dispose();
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
new TestMacFrame();
}
}
Has anyone ever run into this issue before? Sometimes the string displays, sometimes half of it, sometimes none of it. The issue is worsened when using VolatileImage instead of BufferedImage as a backbuffer.
public class Game3D {
public static void main(String[] args) {
Game3D game = new Game3D();
game.start();
}
public Game3D() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
canv = new GameCanvas();
canv.setPreferredSize(new Dimension(800, 600));
frame.add(canv);
frame.pack();
frame.setVisible(true);
}
private JFrame frame;
private GameCanvas canv;
public void start() {
canv.createBuffer(canv.getPreferredSize());
loadingScreen("Loading", 10);
}
public void loadingScreen(String msg, int done) {
Graphics2D g = canv.img.createGraphics();
try {
g.setColor(Color.BLACK);
g.fillRect(0, 0, canv.getWidth(), canv.getHeight());
int sizeX = 400, sizeY = 50;
int loadX = canv.getWidth() / 2 - sizeX / 2;
int loadY = canv.getHeight() / 2 - sizeY / 2;
g.setColor(Color.RED);
g.drawRect(loadX, loadY, sizeX, sizeY);
g.fillRect(loadX + 2, loadY + 2, (int) (sizeX / 100F * done), sizeY - 3);
int textX = canv.getWidth() / 2 - g.getFontMetrics().stringWidth(msg) / 2;
int textY = canv.getHeight() / 2 - g.getFontMetrics().getHeight() / 2;
g.setColor(Color.WHITE);
g.setFont(canv.font);
g.drawString(msg, textX, textY);
} finally {
g.dispose();
}
}
}
class GameCanvas extends Canvas {
GameCanvas() {
}
BufferedImage img;
Font font;
void createBuffer(Dimension dim) {
img = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_ARGB);
font = new Font(Font.MONOSPACED, Font.PLAIN, 16);
}
#Override
public void paint(Graphics g) {
g.drawImage(img, 0, 0, null);
}
}
I think you may need to call frame.repaint(); in order to have what you draw show up properly though I'm not entirely certain. I just remember this being the cause of a few of my own problems when using Java GUIs.
The code needed to be ran in the SWING thread!
I have JPanel in a container of a JFrame called Box
public Box(){
add(new Ball());
}
public void paint(Graphics g){
g.setColor(Color.WHITE);
g.fillRect(OFFSET, OFFSET, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
g.drawRect(OFFSET, OFFSET, WIDTH, HEIGHT);
}
Ball extends Component and draws a ball
public class Ball extends Component{
...
public void paint(Graphics g){
g.setColor(Color.BLACK);
g.fillOval(xCoord, yCoord, radius, radius);
}
...
}
When I add a Box with a Ball to the container I can only ever see the Box. If I just add a Ball I can see the Ball.
Does anyone know why the Ball is not visible when added to a Box?
In addition to overriding paintComponent, use a LayoutManager to set bounds automatically. For testing purposes, you can set the LayoutManager of the Box instance to null and use setBounds on the Ball instance.
Do not mix heavyweight and lightweight components. You should be extending JComponent instead.
You should be overriding paintComponent(), not paint().
Does Ball have a size? If you haven't supplied Ball with a Dimension, it won't be visible.
In Swing, you should normally never override the paint method. Use paintComponent instead.
there are three possible mistake
1/ simpliest paint by using JLabel
2/ timing by javax.swing.Timer
3/ paintComponents instead of paint (for AWT Compoents and painting DefaultXxxUI)
and put that together, for example
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class AnimationJPanel extends JPanel {
private static final long serialVersionUID = 1L;
private int cx = 0;
private int cy = 150;
private int cw = 20;
private int ch = 20;
private int xinc = 1;
private int yinc = 1;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
AnimationJPanel panel = new AnimationJPanel();
panel.setPreferredSize(new Dimension(400, 300));
panel.animate();
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public AnimationJPanel() {
setLayout(new BorderLayout());
JLabel label = new JLabel("This is an AnimationJPanel");
label.setForeground(Color.RED);
label.setHorizontalAlignment(SwingConstants.CENTER);
add(label);
setBackground(Color.BLACK);
setForeground(Color.RED);
setOpaque(true);
}
public void animate() {
new Timer(15, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Rectangle oldCircle = new Rectangle(cx - 1, cy - 1, cw + 2, ch + 2);
cx += xinc;
cy += yinc;
if (cx >= getWidth() - cw || cx <= 0) {
xinc *= -1;
}
if (cy >= getHeight() - ch || cy <= 0) {
yinc *= -1;
}
repaint(oldCircle);
repaint(cx - 1, cy - 1, cw + 2, ch + 2);
}
}).start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(cx, cy, cw, ch);
}
}