I am trying to make a piece of a JPanel transparent, but I cannot quite get it to work. Is it possible to do this?
import java.awt.*;
import javax.swing.*;
public class ClearPanel extends JPanel{
public static void main(String[] args) {
ClearPanel c = new ClearPanel();
c.setPreferredSize(new Dimension(200, 200));
c.setOpaque(false);
JPanel backPanel = new JPanel();
backPanel.setBackground(Color.CYAN);
backPanel.add(c);
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(backPanel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillOval(0, 0, 200, 200);
g.clearRect(45, 45, 50, 50);
Graphics2D g2 = (Graphics2D) g;
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.0f));
g2.fillRect(75, 75, 50, 50);
}
}
The oval should be opaque, but the rectangles I would like to be transparent. By transparent, I mean that I should be able to see the panel behind the ClearPanel.
Going off of MadProgrammer's answer, is there any way to make that gray box draw where it is outside of the area, but remain transparent where it is in the area?
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle fill = new Rectangle(getWidth(), getHeight());
Graphics2D g2d = (Graphics2D) g.create();
Rectangle hole = new Rectangle(0, 0, 100, 100);
Area area = new Area(fill);
area.subtract(new Area(hole));
g2d.setColor(getBackground());
g2d.fill(area);
g2d.setColor(Color.RED);
g2d.setComposite(AlphaComposite.SrcOver.derive(0.0f));
g2d.fill(hole);
g2d.setComposite(AlphaComposite.SrcOver.derive(1.0f));
g2d.setColor(Color.DARK_GRAY);
if(area.contains(0,0,100,200))
g2d.fillRect(0, 0, 100, 200);
g2d.dispose();
}
The problem you have is, by default, JPanel is opaque, meaning that the repaint will NOT paint anything under it.
You need to set the the panel to transparent and then take over the painting of the background.
Now, the real trick begins. If you simply fill the component and then try and paint transparent section over the top of it, you will simply be painting a transparent section over a opaque background...not very helpful.
What you need to do is not fill the area you want to remain transparent.
You can accomplish this by using a Area shape, which has a neat trick of been able to append/add and remove shapes from it.
import java.awt.AlphaComposite;
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.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
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;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TransparentPane {
public static void main(String[] args) {
new TransparentPane();
}
public TransparentPane() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
BackgroundPane backgroundPane = new BackgroundPane();
backgroundPane.setBackground(Color.RED);
backgroundPane.setLayout(new BorderLayout());
backgroundPane.add(new TranslucentPane());
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(backgroundPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class BackgroundPane extends JPanel {
private BufferedImage bg;
public BackgroundPane() {
try {
bg = ImageIO.read(new File("/path/to/your/image.jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return bg == null ? super.getPreferredSize() : new Dimension(bg.getWidth(), bg.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (bg != null) {
int width = getWidth() - 1;
int height = getHeight() - 1;
int x = (width - bg.getWidth()) / 2;
int y = (height - bg.getHeight()) / 2;
g.drawImage(bg, x, y, this);
}
}
}
public class TranslucentPane extends JPanel {
public TranslucentPane() {
setOpaque(false);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle fill = new Rectangle(getWidth(), getHeight());
Graphics2D g2d = (Graphics2D) g.create();
int width = getWidth() - 1;
int height = getHeight() - 1;
int radius = Math.min(width, height) / 2;
int x = (width - radius) / 2;
int y = (height - radius) / 2;
Ellipse2D hole = new Ellipse2D.Float(x, y, radius, radius);
Area area = new Area(fill);
area.subtract(new Area(hole));
g2d.setColor(getBackground());
g2d.fill(area);
g2d.setColor(Color.RED);
g2d.setComposite(AlphaComposite.SrcOver.derive(0.25f));
g2d.fill(hole);
g2d.dispose();
}
}
}
Update
Well, that took a little longer the I expected...
Basically, we need to create a mask of the shape that subtracts the hole from the rectangle we want to display, then subtract that result from the rectangle we want to diplay
import java.awt.AlphaComposite;
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.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
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;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TransparentPane {
public static void main(String[] args) {
new TransparentPane();
}
public TransparentPane() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
BackgroundPane backgroundPane = new BackgroundPane();
backgroundPane.setBackground(Color.RED);
backgroundPane.setLayout(new BorderLayout());
backgroundPane.add(new TranslucentPane());
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(backgroundPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class BackgroundPane extends JPanel {
private BufferedImage bg;
public BackgroundPane() {
try {
bg = ImageIO.read(new File("/Users/swhitehead/Dropbox/MegaTokyo/Evil_Small.jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return bg == null ? super.getPreferredSize() : new Dimension(bg.getWidth(), bg.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (bg != null) {
int width = getWidth() - 1;
int height = getHeight() - 1;
int x = (width - bg.getWidth()) / 2;
int y = (height - bg.getHeight()) / 2;
g.drawImage(bg, x, y, this);
}
}
}
public class TranslucentPane extends JPanel {
public TranslucentPane() {
setOpaque(false);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle fill = new Rectangle(getWidth(), getHeight());
Graphics2D g2d = (Graphics2D) g.create();
int width = getWidth() - 1;
int height = getHeight() - 1;
int radius = Math.min(width, height) / 2;
int x = (width - radius) / 2;
int y = (height - radius) / 2;
Ellipse2D hole = new Ellipse2D.Float(x, y, radius, radius);
Area area = new Area(fill);
area.subtract(new Area(hole));
g2d.setColor(getBackground());
g2d.fill(area);
g2d.setColor(Color.RED);
g2d.setComposite(AlphaComposite.SrcOver.derive(0.0f));
g2d.fill(hole);
g2d.dispose();
g2d = (Graphics2D) g.create();
// Basically, we create an area that is subtraction of the window/rectangle
// from the whole. This leaves us with a rectangle (with a hole in it)
// that doesn't include the area where the whole is...
Rectangle win = new Rectangle(
x + (radius / 2),
y + (radius / 2), radius, (radius / 4));
area = new Area(win);
area.subtract(new Area(hole));
// Then we create a area that is a subtraction of the original rectangle
// from the one with a "hole" in it...
Area actual = new Area(win);
actual.subtract(area);
g2d.setColor(Color.BLUE);
g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
g2d.fill(actual);
g2d.dispose();
}
}
}
Related
Hi Everyone I want to draw lines to Jlabel Icon with DrawLines() class but the program isn't drawing .When I use to frame.add(m) the program is drawing lines to frame .....
DrawLine m = new DrawLine();
frame.add(m);
but when I use to label.add(m) method .The program isn't working .I need to figure out this problem Why can't I draw lines to jlabelIcon and How can I fix this ?
This is my DrawLine Class
package com.company;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Line2D;
public class DrawLine extends JComponent {
public void paint(Graphics g) {
super.paintComponents(g);
g.drawLine(300, 152, 63, 185);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
g.drawLine(63, 185, 120, 198);
}
}
This is my main class
package com.company;
import com.sun.source.tree.Tree;
import jdk.swing.interop.SwingInterOpUtils;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.awt.geom.Line2D;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
public class Main extends JFrame {
public static void main(String[] args) {
JFrame frame = new JFrame("Display Image");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = (JPanel) frame.getContentPane();
frame.setSize(1000,560);
JLabel label = new JLabel();
label.setSize(1000,560);
label.setIcon(new ImageIcon("myimage path"));
DrawLine m = new DrawLine();
label.add(m);
panel.add(label);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
If your goal is to draw lines and images together, then your best bet for the money is to get rid of ImageIcon and JLabel and instead is to draw them all within a single paintComponent. The images can be drawn as image sprite, and the lines as lines by calling Graphics#drawLine(...) or as Line2D objects as you have using Graphics2D#draw(...)
For example, say we had two BufferedImage objects, upImg and dnImg, and two Point objects that determined the location of these sprites, upPt and dnPt
public class Foo01 extends JPanel {
// .....
private Point upPt = new Point(300, 100);
private Point dnPt = new Point(700, 650);
private BufferedImage upImg, dnImg;
And say we wanted to draw a line that connected the two image sprites, then these could all be draw within the paintComponent method like so:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // tell the JPanel to do its house-keeping painting
// make sure that neither image is null
if (upImg != null && dnImg != null) {
// draw both images at their respective locations
g.drawImage(upImg, upPt.x, upPt.y, this);
g.drawImage(dnImg, dnPt.x, dnPt.y, this);
// to get a smooth line, use rendering hiints
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// to give the line some thickness
g2.setStroke(new BasicStroke(5f));
// calculate the end-points of the line
int x1 = upPt.x + upImg.getWidth() / 2;
int y1 = upPt.y + upImg.getHeight() / 2;
int x2 = dnPt.x + dnImg.getWidth() / 2;
int y2 = dnPt.y + dnImg.getHeight() / 2;
// and then draw it
g.drawLine(x1, y1, x2, y2);
}
}
Here is an example program that does just this -- draws two images with a line connecting. I've also added a MouseAdapter to allow the user to move the first image, the green up-arrow, showing that the line will move as well, since it is calculated within the painting method:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.net.URL;
import java.io.IOException;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
public class Foo01 extends JPanel {
private static final String UP_IMG_PATH = "https://upload.wikimedia.org/wikipedia/commons/7/7d/Green_circle_icon.jpg";
private static final String DN_IMG_PATH = "https://upload.wikimedia.org/wikipedia/commons/b/bc/Red_circle_icon.jpg";
private static final int GUI_W = 1000;
private static final int GUI_H = 800;
private Point upPt = new Point(300, 100);
private Point dnPt = new Point(700, 650);
private BufferedImage upImg, dnImg;
public Foo01() {
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
setBackground(Color.WHITE);
try {
URL url = new URL(UP_IMG_PATH);
upImg = ImageIO.read(url);
url = new URL(DN_IMG_PATH);
dnImg = ImageIO.read(url);
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(GUI_W, GUI_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (upImg != null && dnImg != null) {
g.drawImage(upImg, upPt.x, upPt.y, this);
g.drawImage(dnImg, dnPt.x, dnPt.y, this);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(5f));
int x1 = upPt.x + upImg.getWidth() / 2;
int y1 = upPt.y + upImg.getHeight() / 2;
int x2 = dnPt.x + dnImg.getWidth() / 2;
int y2 = dnPt.y + dnImg.getHeight() / 2;
g.drawLine(x1, y1, x2, y2);
}
}
private class MyMouse extends MouseAdapter {
private Point p1 = null;
#Override
public void mousePressed(MouseEvent e) {
if (e.getX() < upPt.x || e.getX() > upPt.x + upImg.getWidth()) {
return;
}
if (e.getY() < upPt.y || e.getY() > upPt.y + upImg.getHeight()) {
return;
}
p1 = new Point(e.getX(), e.getY());
}
#Override
public void mouseReleased(MouseEvent e) {
if (p1 != null) {
moveSprite(e);
p1 = null;
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (p1 != null) {
moveSprite(e);
}
}
private void moveSprite(MouseEvent e) {
Point p2 = new Point(e.getX(), e.getY());
int x = upPt.x + p2.x - p1.x;
int y = upPt.y + p2.y - p1.y;
upPt = new Point(x, y);
p1 = p2;
repaint();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(()-> {
Foo01 foo01 = new Foo01();
JFrame frame = new JFrame("Draw Sprites");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(foo01);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
If the need is to add custom painting to a JLabel you can override its paintComponent:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
public class Main extends JFrame {
private static final String BUG = "https://www.growtopiagame.com/forums/attachment.php?attachmentid=141847&d=1477126665";
public static void main(String[] args) throws MalformedURLException {
JFrame frame = new JFrame("Display Image");
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DrawLine m = new DrawLine("A crossed bug", new ImageIcon(new URL(BUG)));
frame.add(m);
frame.pack();
frame.setVisible(true);
}
}
class DrawLine extends JLabel {
DrawLine(String text, Icon icon) {
super(text, icon, SwingConstants.CENTER);
setVerticalTextPosition(SwingConstants.BOTTOM);
setHorizontalTextPosition(SwingConstants.CENTER);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.YELLOW);
g2d.setStroke(new BasicStroke(10));
int w = getWidth(); int h = getHeight();
g2d.drawLine(0, 0, w, h); //draw right to left diagonal
g2d.drawLine(0, h, w, 0); //draw left to right diagonal
}
}
Swing is a single Thread library. All painting tasks are executed in the Event Dispatcher Thread (EDT).
Running long processes (such as sleep) on the EDT makes keeps this thread busy, so it does not do other things like updating the gui. The gui becomes unresponsive (freezes).
If you want to add a line after a certain delay, use swing Timer for the job:
public class Main extends JFrame {
private static final String BUG = "https://www.growtopiagame.com/forums/attachment.php?attachmentid=141847&d=1477126665";
public static void main(String[] args) throws MalformedURLException {
JFrame frame = new JFrame("Display Image");
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DrawLine m = new DrawLine("A crossed bug", new ImageIcon(new URL(BUG)));
frame.add(m);
frame.pack();
frame.setVisible(true);
}
}
class DrawLine extends JLabel {
private static final int DELAY = 1500; //millies
private boolean isDrawSecondDialgonal = false;
DrawLine(String text, Icon icon) {
super(text, icon, SwingConstants.CENTER);
setVerticalTextPosition(SwingConstants.BOTTOM);
setHorizontalTextPosition(SwingConstants.CENTER);
//use timer to enable painting of a second diagonal
javax.swing.Timer timer = new javax.swing.Timer(DELAY, e-> {
isDrawSecondDialgonal = true;
repaint();
});
timer.setRepeats(false);
timer.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.YELLOW);
g2d.setStroke(new BasicStroke(10));
int w = getWidth(); int h = getHeight();
g2d.drawLine(0, 0, w, h); //draw right to left diagonal
if(isDrawSecondDialgonal) {
g2d.drawLine(0, h, w, 0);//draw left to right diagonal
}
}
}
I am trying to rotating a BufferedImage in Java without changing size.
width = 232 height = 174
width = 232 height = 174
I using this code but my image don`t rotate:
AffineTransform at = new AffineTransform();
at.translate(four2.getWidth() / 2, four2.getHeight() / 2);
at.rotate(Math.PI/2);
at.scale(0.5, 0.5);
at.translate(-four2.getWidth()/2, -four2.getHeight()/2);
Graphics2D g2d = (Graphics2D) four2.getGraphics();
g2d.drawImage(four2, at, null);
g2d.dispose();
Rotating a non-square image within the same boundaries will crop the image.
You could change the Graphics clipping bounds, but this is dangerous, as you could actually end up painting outside of the visible bounds available to the Graphics context, which results in some very weird and generally not welcomed results.
A simpler solution might be to just generate a new image from the original and rotate it within it's own confines, for example...
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.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
try {
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException iOException) {
iOException.printStackTrace();
}
}
});
}
public class TestPane extends JPanel {
private BufferedImage master;
private BufferedImage rotated;
public TestPane() throws IOException {
master = ImageIO.read(new File("/Volumes/Disk02/Dropbox/MegaTokyo/issue142.jpg"));
rotated = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = rotated.createGraphics();
AffineTransform at = new AffineTransform();
at.rotate(Math.PI / 2, master.getWidth() / 2, master.getHeight() / 2);
g2d.setTransform(at);
g2d.drawImage(master, 0, 0, this);
g2d.dispose();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(master.getWidth() * 2, master.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - (master.getWidth() * 2)) / 2;
int y = (getHeight() - master.getHeight()) / 2;
g2d.drawImage(master, x, y, this);
g2d.drawImage(rotated, x + master.getWidth(), y, this);
g2d.dispose();
}
}
}
class DrawIma extends JPanel{
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i=0;i<20;i++){
for (int j=0;j<20;j++) {
g.drawImage(BuArr[i*20+j], 20*i, 20*j, 20, 20, null);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
In this part, BuArr are the 400 blocks divided from a BufferedImage, now i want them to be draw one by one, but the method can not draw the blocks separately, how can i do this?
Swing is single thread and not thread safe.
This means that you should not perform any long running or blocking (Thread.sleep) operations within the IU thread (the Event Dispatching Thread). It also means that you can not update, modify or create UI elements outside of the EDT context.
Instead, use a Swing Timer to generate a repeated callback at a specified interval and render the portions of the image to something like a BufferedImage, which you can the paint to the component via its paintComponent method...
See Concurrency in Swing and How to use Swing Timers for more details
Because it was a good time waster
This generates a List of Rectangles which represent the individual blocks I want to paint, I then randomise the List and run the Timer, picking the top most Rectangle off the List and using BufferedImage#getSubImage to draw it from the master to the buffer, which gets painted to the screen...
import java.awt.AlphaComposite;
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.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
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 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.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage master;
private BufferedImage copy;
private List<Rectangle> blocks;
public TestPane() {
setBackground(Color.BLACK);
try {
master = ImageIO.read(new File("..."));
copy = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = copy.createGraphics();
AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f);
g2d.setComposite(composite);
g2d.setColor(new Color(0, 0, 0, 0));
g2d.fillRect(0, 0, master.getWidth(), master.getHeight());
g2d.dispose();
int blockSize = 40;
int width = master.getWidth();
int height = master.getHeight();
float aspect = Math.min(width, height) / (float) Math.max(width, height);
int blockHeight = blockSize;
blocks = new ArrayList<>(blockSize * 2);
for (int y = 0; y < master.getHeight(); y += blockHeight) {
if (y + blockHeight > master.getHeight()) {
blockHeight = master.getHeight() - y;
}
int blockWidth = blockSize;
for (int x = 0; x < master.getWidth(); x += blockWidth) {
if (x + blockWidth > master.getWidth()) {
blockWidth = master.getWidth() - x;
}
Rectangle block = new Rectangle(x, y, blockWidth, blockHeight);
blocks.add(block);
}
}
Collections.shuffle(blocks);
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (blocks.isEmpty()) {
((Timer) e.getSource()).stop();
} else {
Graphics2D g2d = copy.createGraphics();
Rectangle block = blocks.remove(0);
g2d.drawImage(master.getSubimage(block.x, block.y, block.width, block.height), block.x, block.y, TestPane.this);
g2d.dispose();
repaint();
}
}
});
timer.start();
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return master == null ? new Dimension(200, 200) : new Dimension(master.getWidth(), master.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (copy != null) {
int x = (getWidth() - copy.getWidth()) / 2;
int y = (getHeight() - copy.getHeight()) / 2;
g2d.drawImage(copy, x, y, this);
}
g2d.dispose();
}
}
}
I got a class with a resizable background. There are paintings over that background(using a paint method and Java2D).
How can i delete everything that was drawn every time that the background gets a resize? (To eventually draw again in the correct places) Is there any sort of transform i can do on the already-drawn objects(like scaling to fit the image again)?
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
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.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Background extends JLabel implements ChangeListener {
private ImageIcon background;
private BufferedImage image;
public Background(JPanel parent){
super();
parent.add(this);
try {
image = ImageIO.read(new File("/example/background"));
} catch (IOException e) {
e.printStackTrace();
}
this.background = new ImageIcon(image);
this.setIcon(background);
}
public void stateChanged(ChangeEvent e) {
int value = ((JSlider) e.getSource()).getValue();
double scale = value / 100.0;
BufferedImage scaled = getScaledImage(scale);
this.setIcon(new ImageIcon(scaled));
this.revalidate();
}
private BufferedImage getScaledImage(double scale) {
int w = (int) (scale * image.getWidth());
int h = (int) (scale * image.getHeight());
BufferedImage bi = new BufferedImage(w, h, image.getType());
Graphics2D g2 = bi.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BICUBIC);
AffineTransform at = AffineTransform.getScaleInstance(scale, scale);
g2.drawRenderedImage(image, at);
g2.dispose();
return bi;
}
#Override
public void paint(Graphics g){
super.paint(g);
Graphics2D graphObj = (Graphics2D) g;
RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);rh.put(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
graphObj.setRenderingHints(rh);
graphObj.fillOval(500, 500, 20, 20);
graphObj.finalize();
}
}
Consider:
Drawing in a paintComponent(...) override, not a paint(...) override.
Save a List<Point> where each Point is normalized, say to a 1000 by 1000 size.
Then in the paintComponent method, iterate through each Point in a for loop, scaling it to the current component size, and drawing it.
You'll want to scale any image drawn in the component in a ComponentListener, and then call repaint().
Or perhaps even better, scale the image drawn using the Graphics#drawImage(...) overload that takes width and height parameters.
e.g.,
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class MyBackground extends JPanel {
private BufferedImage img;
public MyBackground(BufferedImage img) {
this.img = img;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
}
}
private static void createAndShowGui() {
String comfyChair = "https://duke.kenai.com/comfyChair/ComfyChairRad.png";
BufferedImage img;
try {
URL url = new URL(comfyChair);
img = ImageIO.read(url);
MyBackground mainPanel = new MyBackground(img);
JFrame frame = new JFrame("MyBackground");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
example 2:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;
public class MyBackground extends JPanel {
public static final double NORM_CONST = 1.0;
private BufferedImage img;
private List<List<Point2D>> normalizedPoints = new ArrayList<List<Point2D>>();
private List<Point2D> pointSubList;
public MyBackground(BufferedImage img) {
this.img = img;
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
}
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (List<Point2D> pointList : normalizedPoints) {
if (pointList.size() > 1) {
for (int i = 1; i < pointList.size(); i++) {
Point p1 = deNormalize(pointList.get(i - 1));
Point p2 = deNormalize(pointList.get(i));
g2.drawLine(p1.x, p1.y, p2.x, p2.y);
}
}
}
if (pointSubList != null && pointSubList.size() > 1) {
for (int i = 1; i < pointSubList.size(); i++) {
Point p1 = deNormalize(pointSubList.get(i - 1));
Point p2 = deNormalize(pointSubList.get(i));
g2.drawLine(p1.x, p1.y, p2.x, p2.y);
}
}
}
private Point deNormalize(Point2D p2d) {
int x = (int) (p2d.getX() * getWidth() / NORM_CONST);
int y = (int) (p2d.getY() * getHeight() / NORM_CONST);
return new Point(x, y);
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
Point2D p = normalizePoint(e.getPoint());
pointSubList = new ArrayList<>();
pointSubList.add(p);
}
#Override
public void mouseReleased(MouseEvent e) {
Point2D p = normalizePoint(e.getPoint());
pointSubList.add(p);
normalizedPoints.add(pointSubList);
pointSubList = null;
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
Point2D p = normalizePoint(e.getPoint());
pointSubList.add(p);
repaint();
}
private Point2D normalizePoint(Point point) {
double x = (NORM_CONST * point.x) / getWidth();
double y = (NORM_CONST * point.y) / getHeight();
Point2D result = new Point2D.Double(x, y);
return result;
}
}
private static void createAndShowGui() {
String comfyChair = "https://duke.kenai.com/comfyChair/ComfyChairRad.png";
BufferedImage img;
try {
URL url = new URL(comfyChair);
img = ImageIO.read(url);
MyBackground mainPanel = new MyBackground(img);
JFrame frame = new JFrame("MyBackground");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
I'm creating an animated slide transition in Java, and it is choppy on my current model MacBook Pro and on my year-old iMac, on Java 6, 7, and 8.
What can I do to make this animation appear smoother to the user on Mac OS X?
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ScratchSpace {
public static void main(String[] args) {
AnimatedPanel panel = new AnimatedPanel();
JFrame frame = new JFrame();
frame.setContentPane(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
panel.animate();
}
public static class AnimatedPanel extends JPanel {
private float progress = 0.0f; // a number between 0.0 and 1.0
public AnimatedPanel() {
setPreferredSize(new Dimension(800, 600));
setOpaque(true);
}
public void animate() {
final int animationTime = 1000;
int framesPerSecond = 30;
int delay = 1000 / framesPerSecond;
final long start = System.currentTimeMillis();
final Timer timer = new Timer(delay, null);
timer.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
final long now = System.currentTimeMillis();
final long elapsed = now - start;
progress = (float) elapsed / animationTime;
repaint();
if (elapsed >= animationTime) {
timer.stop();
}
}
});
timer.start();
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
int width = getWidth();
int progressWidth = (int) (width * progress);
g2d.setColor(Color.BLUE);
g2d.fillRect(0, 0, progressWidth, getHeight());
g2d.setColor(Color.RED);
g2d.fillRect(progressWidth, 0, width-progressWidth, getHeight());
}
}
}
A lot depends on what it is you ultimately want to achieve.
Remember, animation is the illusion of movement...
I changed
the framesPerSecond to 60 which seems to have helped.
Reduced the overall height of the printable area
Calculated the area of change and simple called repaint(Rectangle) passing in only that area which has changed.
The other problem is your animation has a large area to cover in a very short period of time. Increasing the amount of time will also make it smoother (or reducing the width and/or height)
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.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ScratchSpace {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
AnimatedPanel panel = new AnimatedPanel();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
panel.animate();
}
});
}
public static class AnimatedPanel extends JPanel {
private float progress = 0.0f; // a number between 0.0 and 1.0
public AnimatedPanel() {
setPreferredSize(new Dimension(800, 100));
}
public void animate() {
final int animationTime = 1000;
int framesPerSecond = 60;
int delay = 1000 / framesPerSecond;
final long start = System.currentTimeMillis();
final Timer timer = new Timer(delay, null);
timer.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
final long now = System.currentTimeMillis();
final long elapsed = now - start;
int width = getWidth();
int height = getHeight();
int oldWidth = (int) (width * progress);
progress = (float) elapsed / animationTime;
int newWidth = (int) (width * progress);
repaint(new Rectangle(oldWidth, 0, newWidth - oldWidth, height));
if (elapsed >= animationTime) {
timer.stop();
}
}
});
timer.start();
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
int width = getWidth();
int progressWidth = (int) (width * progress);
g2d.setColor(Color.BLUE);
g2d.fillRect(0, 0, progressWidth, getHeight());
g2d.setColor(Color.RED);
g2d.fillRect(progressWidth, 0, width - progressWidth, getHeight());
}
}
}
Alternativly, you could generate you own backing buffer and update it...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ScratchSpace {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
AnimatedPanel panel = new AnimatedPanel();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
panel.animate();
}
});
}
public static class AnimatedPanel extends JPanel {
private float progress = 0.0f; // a number between 0.0 and 1.0
private BufferedImage buffer;
public AnimatedPanel() {
setPreferredSize(new Dimension(800, 600));
// setOpaque(true);
}
public void animate() {
final int animationTime = 1000;
int framesPerSecond = 60;
int delay = 1000 / framesPerSecond;
final long start = System.currentTimeMillis();
final Timer timer = new Timer(delay, null);
timer.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
final long now = System.currentTimeMillis();
final long elapsed = now - start;
int width = getWidth();
progress = (float) elapsed / animationTime;
updateBuffer();
repaint();
if (elapsed >= animationTime) {
timer.stop();
}
}
});
timer.start();
}
#Override
public void invalidate() {
buffer = null;
updateBuffer();
super.invalidate();
}
protected void updateBuffer() {
if (getWidth() > 0 && getHeight() > 0) {
if (buffer == null) {
buffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
}
Graphics2D g2d = buffer.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
int width = getWidth();
int height = getHeight();
float progressWidth = width * progress;
g2d.setColor(Color.BLUE);
g2d.fill(new Rectangle2D.Float(0, 0, progressWidth, height));
g2d.setColor(Color.RED);
g2d.fill(new Rectangle2D.Float(progressWidth, 0, width - progressWidth, height));
g2d.dispose();
}
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
if (buffer != null) {
g2d.drawImage(buffer, 0, 0, this);
}
// int width = getWidth();
// int progressWidth = (int) (width * progress);
// g2d.setColor(Color.BLUE);
// g2d.fillRect(0, 0, progressWidth, getHeight());
// g2d.setColor(Color.RED);
// g2d.fillRect(progressWidth, 0, width - progressWidth, getHeight());
}
}
}
The major problem you have is basically the area you are trying to paint is to large for the time you want to paint it.
Another Alternatively
You could create a BufferedImage that represents the progress bar and move as the progress updates. This update creates a compatible buffered image, which should make it faster to renderer
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.RenderingHints;
import java.awt.Transparency;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ScratchSpace {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
AnimatedPanel panel = new AnimatedPanel();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
panel.animate();
}
});
}
public static class AnimatedPanel extends JPanel {
private float progress = 0.0f; // a number between 0.0 and 1.0
private BufferedImage buffer;
public AnimatedPanel() {
setPreferredSize(new Dimension(800, 600));
// setOpaque(true);
}
public void animate() {
final int animationTime = 1000;
int framesPerSecond = 60;
int delay = 1000 / framesPerSecond;
final long start = System.currentTimeMillis();
final Timer timer = new Timer(delay, null);
timer.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
final long now = System.currentTimeMillis();
final long elapsed = now - start;
progress = (float) elapsed / animationTime;
repaint();
if (elapsed >= animationTime) {
timer.stop();
}
}
});
timer.start();
}
#Override
public void invalidate() {
buffer = null;
updateBuffer();
super.invalidate();
}
protected void updateBuffer() {
if (getWidth() > 0 && getHeight() > 0) {
if (buffer == null) {
GraphicsConfiguration config = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
buffer = config.createCompatibleImage(getWidth(), getHeight(), Transparency.TRANSLUCENT);
buffer.coerceData(true);
Graphics2D g2d = buffer.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
int width = getWidth();
int height = getHeight();
g2d.setColor(Color.BLUE);
g2d.fill(new Rectangle2D.Float(0, 0, width, height));
g2d.dispose();
}
}
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
int width = getWidth();
int progressWidth = (int) (width * progress);
int x = (progressWidth - width);
System.out.println(progressWidth + "; " + x);
// g2d.setColor(Color.BLUE);
// g2d.fillRect(0, 0, progressWidth, getHeight());
g2d.setColor(Color.RED);
g2d.fillRect(progressWidth, 0, width - progressWidth, getHeight());
g2d.drawImage(buffer, x, 0, this);
}
}
}