I am trying to rotate an animated gif stored in an ImageIcon using an AffineTransform. The result is that the image does not get drawn.
Here's my code:
AffineTransform trans = AffineTransform.getRotateInstance(imgYaw, img.getImage().getWidth(null) / 2, img.getImage().getHeight(null) / 2);
AffineTransformOp transo = new AffineTransformOp(trans, AffineTransformOp.TYPE_BILINEAR);
BufferedImage bufferedimg = new BufferedImage(img.getImage().getWidth(null), img.getImage().getHeight(null), BufferedImage.TYPE_4BYTE_ABGR);
img.setImage(atransO.filter(bufferedimg, null));
img.paintIcon(null, g, x, y);
Not so much an answer, but an example of simplified workflow...
Basically, what this does is applies a AffineTransform directly to the Graphics context and paints the IconImage to it...
Now, you could use the Graphics context from BufferedImage if that's what you need...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestImage {
public static void main(String[] args) {
new TestImage();
}
public static final String IMAGE_PATH = "C:\\Users\\shane\\Dropbox\\Ponies\\28490 - animated gif rainbow_dash_Small.gif";
public TestImage() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(1, 2));
frame.add(new JLabel(new ImageIcon(IMAGE_PATH)));
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private ImageIcon img;
private float degrees;
public TestPane() {
img = new ImageIcon(IMAGE_PATH);
Timer timer = new Timer(16, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
degrees += 1;
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(img.getIconWidth(), img.getIconHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int x = getWidth() / 2;
int y = getHeight() / 2;
g2d.setTransform(AffineTransform.getRotateInstance(Math.toRadians(degrees), x, y));
x = (getWidth() - img.getIconWidth()) / 2;
y = (getHeight() - img.getIconHeight()) / 2;
img.paintIcon(this, g2d, x, y);
g2d.dispose();
}
}
}
Related
So I am using a JFrame object to open up a window and add a bunch of graphics first I am adding an image then I am trying to add some lines, But it seems like the line start from the Y center of the previous image I would like for it to start at the top of the page
here is my code for the JFrame:
JFrame f = new JFrame();
JLabel trebeclef = new JLabel(new ImageIcon(getClass().getClassLoader().getResource("Some image")));
Draw d = new Draw();
f.add(trebeclef);
f.add(d);
f.setSize(1000,1000);
f.getContentPane().setBackground(Color.white);
f.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
f.pack();
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
here is the code for the Draw class
public void paint(Graphics g2) {
super.paintComponent(g2);
Graphics2D g = (Graphics2D) g2;
g.setStroke(new BasicStroke(2));
g.drawLine(0, 0, 100, 0);
}
it results in this
Any help appreciated, thanks
Trying to layout components like this isn't the easiest thing to to, especially when you consider the complexities of JLabel and the possibilities of other layout constraints.
If you have the image and you're drawing the lines via custom painting, I would just custom paint the whole thing
Starting with...
We can produce something like...
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public final class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new ClefWithLinesPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public class ClefWithLinesPane extends JPanel {
private BufferedImage trebbleClef;
public ClefWithLinesPane() throws IOException {
trebbleClef = ImageIO.read(getClass().getResource("/images/ClefLines.png"));
setBackground(Color.WHITE);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int x = 0;
int y = (getHeight() - trebbleClef.getHeight()) / 2;
g2d.drawImage(trebbleClef, x, y, this);
int[] lines = new int[] {
30, 60, 89, 120, 149
};
x = trebbleClef.getWidth();
g2d.setStroke(new BasicStroke(2));
for (int line = 0; line < lines.length; line++) {
y = lines[line];
g2d.drawLine(x, y, getWidth(), y);
}
g2d.dispose();
}
}
}
But... as you can see, the lines don't "quite" match up, now this is simply an issue with source image and you could spend some time cleaning it up, or, you could just dispense with the lines of the clef itself and do those you're self, for example...
Starting with...
We could produce something like...
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public final class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new ClefWithOutLinesPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public class ClefWithOutLinesPane extends JPanel {
private BufferedImage trebbleClef;
public ClefWithOutLinesPane() throws IOException {
trebbleClef = ImageIO.read(getClass().getResource("/images/Clef.png"));
setBackground(Color.WHITE);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int minLineY = 30;
int maxLineY = 150;
int lineSpacing = (maxLineY - minLineY) / 4;
int x = 10;
g2d.setStroke(new BasicStroke(8));
g2d.drawLine(x, minLineY + 3, x, maxLineY - 3);
int y = (getHeight() - trebbleClef.getHeight()) / 2;
g2d.drawImage(trebbleClef, x + 10, y, this);
g2d.setStroke(new BasicStroke(2));
for (int line = 0; line < 5; line++) {
y = minLineY + (lineSpacing * line);
g2d.drawLine(x, y, getWidth(), y);
}
g2d.dispose();
}
}
}
Adds after setLayout. One often uses an overloaded add with an extra parameter for a layout's specific constraint.
By default the content pane the frame's adds are done upon, has a BorderLayout with center, left and so on.
The horizontal "line" in a flow is vertically centered. Setting a preferred height ensures a line component is filled up.
d.setPreferredSize(new Dimension(100, 1000));
Of course an other layout might serve better; depending on what you want - just experiment.
The intention of my code is to create a rectangle when the button is clicked. The button works fine but the rectangle itself is not showing up on the screen, and there are no errors. Thank you for helping btw.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Tester {
static JButton button;
static JFrame frame;
static JPanel panel;
static Rectangle rec;
static void init(){
button = new JButton();
frame = new JFrame();
panel = new JPanel();
rec = new Rectangle(30,30,30,30);
button.setVisible(true);
panel.add(button);
frame.add(panel);
frame.setVisible(true);
panel.setVisible(true);
frame.setSize(200, 200);
button.setBackground(Color.GREEN);
button.setBounds(30, 30, 20, 20);
}
public static void main(String[] args) {
init();
ActionListener listener = new RectangleMover();
button.addActionListener(listener);
}
static class RectangleMover implements ActionListener{
#Override
public void actionPerformed(ActionEvent arg0) {
RectanglePainter r = new RectanglePainter();
r.add(rec);
}
}
static class RectanglePainter extends JPanel{
void add(Rectangle r){
rec = r;
repaint();
}
protected void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
Random r = new Random();
int i =r.nextInt(2);
if (i==1)
g2.setColor(Color.BLUE);
else
g2.setColor(Color.RED);
g2.fill(rec);
g2.draw(rec);
}
}
}
Your generally approach is slightly skewed, rather than using another JComponent to "act" as the shape, you should be using it to paint all the shapes through it's paintComponent method
From my "red rectangle" period...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Tester {
public static void main(String[] args) {
new Tester();
}
public Tester() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JPanel panel;
private JButton button;
private JLabel label;
private ShapePane shapePane;
public TestPane() {
setLayout(new BorderLayout());
button = new JButton("Rectangle");
panel = new JPanel();
label = new JLabel();
button.setVisible(true);
panel.add(button);
panel.add(label);
shapePane = new ShapePane();
add(shapePane);
add(panel, BorderLayout.SOUTH);
class ClickListener implements ActionListener {
private int X = 20;
private int Y = 20;
#Override
public void actionPerformed(ActionEvent arg0) {
int width = shapePane.getWidth();
int height = shapePane.getHeight();
int x = (int)(Math.random() * (width - 20)) + 10;
int y = (int)(Math.random() * (height - 20)) + 10;
int w = (int)(Math.random() * (width - x));
int h = (int)(Math.random() * (height - y));
shapePane.add(new Rectangle(x, y, w, h));
}
}
ActionListener listener = new ClickListener();
button.addActionListener(listener);
}
}
public class ShapePane extends JPanel {
private List<Shape> shapes;
public ShapePane() {
shapes = new ArrayList<>(25);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void add(Rectangle rectangle) {
shapes.add(rectangle);
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
for (Shape shape : shapes) {
g2.draw(shape);
}
}
}
}
As to answer your basic question, you could have tried calling revalidate and repaint, but because of the BorderLayout I doubt it would have worked as you would have basically been trying to replace the panel with your ShapeChanger component, and there are better ways to do that
what do you do to get a String to be rotated. (but not constantly rotating, just at an angle)?
I tried using Graphics2D but couldn't find a method for rotating. or will it require manually rotating it? Also if it's easier I can use LWJGL, but I am not experienced with that library at the moment. Thanks.
There a number of ways you might achieve this.
This example simply use an AffineTransform to alter the way that the graphics are drawn...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class AngleText {
public static void main(String[] args) {
new AngleText();
}
public AngleText() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
String text = "I don't see the problem";
FontMetrics fm = g2d.getFontMetrics();
int x = (getWidth() - fm.stringWidth(text)) / 2;
int y = ((getHeight() - fm.getHeight()) / 2) + fm.getDescent();
g2d.setTransform(AffineTransform.getRotateInstance(Math.toRadians(45), getWidth() / 2, getHeight() / 2));
g2d.drawString(text, x, y);
g2d.dispose();
}
}
}
For more details, you can take a look at Transforming Shapes, Text, and Images
I want to rotate a bitmap about its center point, and then draw it into a larger graphics context.
The bitmap is 40x40 pixels. The graphics context is 500x500 pixels. This is what I'm doing:
BufferedImage bi = new BufferedImage(500, 500, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
AffineTransform at = new AffineTransform();
at.quadrantRotate(1, -20, -20); // rotate 90 degrees around center point.
at.translate(100, 40); // I want to put its top-left corner at 100,40.
g.drawImage(smallerBitmap, at, null);
...
I'm probably using quadrantRotate() incorrectly - if I remove that line, my image gets drawn at position 100,40 correctly at least.
What am I doing wrong?
Thanks
The order of your transformation matters. Basically your example code is saying "rotate the image by 90 degrees AND then translate it...."
So, using your code (rotate, then translate) produces...
Switching the order (translate then rotate) produces
...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class TestRotation100 {
public static void main(String[] args) {
new TestRotation100();
}
public TestRotation100() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
final TestPane testPane = new TestPane();
final JSlider slider = new JSlider(0, 3);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
testPane.setQuad(slider.getValue());
}
});
slider.setValue(0);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(testPane);
frame.add(slider, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage img;
private int quad = 0;
public TestPane() {
try {
img = ImageIO.read(new File("/Users/swhitehead/Dropbox/MegaTokyo/Rampage_Small.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void setQuad(int quad) {
this.quad = quad;
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
AffineTransform at = new AffineTransform();
at.translate(100, 40);
at.quadrantRotate(quad, img.getWidth() / 2, img.getHeight() / 2);
g2d.drawImage(img, at, this);
g2d.dispose();
}
}
}
JLists don't offer a method for this, and that's very sad. Do you know how to do it?
Fixed Position List (ie the image is fixed, but you can scroll the list)...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class BackgroundList {
public static void main(String[] args) {
new BackgroundList();
}
public BackgroundList() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JList list;
private BufferedImage background;
public TestPane() {
setLayout(new BorderLayout());
try {
background = ImageIO.read(new File("C:\\Users\\shane\\Dropbox\\MegaTokyo\\_cg_836___Tilting_Windmills___by_Serena_Clearwater.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
int count = 50;
String[] values = new String[count];
for (int index = 0; index < count; index++) {
values[index] = "Testing " + (index + 1);
}
list = new JList(values);
list.setOpaque(false);
list.setBackground(new Color(0, 0, 0, 0));
list.setForeground(Color.WHITE);
JScrollPane scrollPane = new JScrollPane(list);
scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false);
add(scrollPane);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = getWidth() - background.getWidth();
int y = getHeight() - background.getHeight();
g2d.drawImage(background, x, y, this);
g2d.dispose();
}
}
}
}
Scrollable background...
Bascially, the image will "scroll" with the list....
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class BackgroundList {
public static void main(String[] args) {
new BackgroundList();
}
public BackgroundList() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JList list;
private BufferedImage background;
public TestPane() {
setLayout(new BorderLayout());
try {
background = ImageIO.read(new File("C:\\Users\\shane\\Dropbox\\MegaTokyo\\_cg_836___Tilting_Windmills___by_Serena_Clearwater.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
int count = 50;
String[] values = new String[count];
for (int index = 0; index < count; index++) {
values[index] = "Testing " + (index + 1);
}
list = new BackgroundImageList(values);
JScrollPane scrollPane = new JScrollPane(list);
scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false);
add(scrollPane);
}
}
public class BackgroundImageList extends JList {
private BufferedImage background;
public BackgroundImageList(Object[] values) {
super(values);
try {
background = ImageIO.read(new File("C:\\Users\\shane\\Dropbox\\MegaTokyo\\_cg_836___Tilting_Windmills___by_Serena_Clearwater.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
setOpaque(false);
setBackground(new Color(0, 0, 0, 0));
setForeground(Color.WHITE);
}
#Override
protected void paintComponent(Graphics g) {
if (background != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = getWidth() - background.getWidth();
int y = getHeight() - background.getHeight();
g2d.drawImage(background, x, y, this);
g2d.dispose();
}
super.paintComponent(g);
}
}
}