I am trying to create an extended JPanel that acts as a way to highlight some region of the screen. I have taken some code from this SO answer but would like to extend it further though I am not sure how to go about it.
I would like to be able to have my JPanel (MatchAreaPanel below) disappear after a given timeout is reached. That is the JPanel sets its visible property to false and subsequently disposes of itself.
What would be the best way to go about doing this?
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class MatchAreaPanel extends JPanel
{
public MatchAreaPanel()
{
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(new Color(128, 128, 128, 64));
g2d.fillRect(0, 0, getWidth(), getHeight());
float dash1[] = {10.0f};
BasicStroke dashed = new BasicStroke(3.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f);
g2d.setColor(Color.BLACK);
g2d.setStroke(dashed);
g2d.drawRect(0, 0, getWidth() - 3, getHeight() - 3);
g2d.dispose();
}
}
You could use a Swing Timer to simply schedule a callback after a given delay and close the associated window or hide the component based on your needs, for example...
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
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.util.Random;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
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();
}
Rectangle bounds = getVirtualBounds();
Random rnd = new Random();
int x = bounds.x + (rnd.nextInt(bounds.width) - 100);
int y = bounds.y + (rnd.nextInt(bounds.height) - 100);
MatchAreaPanel pane = new MatchAreaPanel();
JWindow frame = new JWindow();
frame.setBackground(new Color(0, 0, 0, 0));
frame.add(pane);
frame.setBounds(x, y, 100, 100);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
pane.start();
}
});
}
public static Rectangle getVirtualBounds() {
Rectangle bounds = new Rectangle(0, 0, 0, 0);
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
bounds.add(gd.getDefaultConfiguration().getBounds());
return bounds;
}
public class MatchAreaPanel extends JPanel {
public MatchAreaPanel() {
setOpaque(false);
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
SwingUtilities.windowForComponent(MatchAreaPanel.this).dispose();
}
});
}
public void start() {
Timer timer = new Timer(5000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.windowForComponent(MatchAreaPanel.this).dispose();
}
});
timer.start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(new Color(128, 128, 128, 64));
g2d.fillRect(0, 0, getWidth(), getHeight());
float dash1[] = {10.0f};
BasicStroke dashed = new BasicStroke(3.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f);
g2d.setColor(Color.BLACK);
g2d.setStroke(dashed);
g2d.drawRect(0, 0, getWidth() - 3, getHeight() - 3);
g2d.dispose();
}
}
}
See How to use Swing Timers for more details
Updated...
Now, simply "hiding" the panel is, boring, it's also possible for the user to miss the panel, as suddenly showing up is no guarantee that the user will see it, so instead, you could add in a fade out effect.
In this example, you can fade the panel out by clicking it (but I did this as part of my testing, so you don't need it) or after the specified time out...
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
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.util.Random;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
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();
}
Rectangle bounds = getVirtualBounds();
Random rnd = new Random();
int x = bounds.x + (rnd.nextInt(bounds.width) - 100);
int y = bounds.y + (rnd.nextInt(bounds.height) - 100);
MatchAreaPanel pane = new MatchAreaPanel();
JWindow frame = new JWindow();
frame.setBackground(new Color(0, 0, 0, 0));
frame.add(pane);
frame.setBounds(x, y, 100, 100);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
pane.start();
}
});
}
public static Rectangle getVirtualBounds() {
Rectangle bounds = new Rectangle(0, 0, 0, 0);
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
bounds.add(gd.getDefaultConfiguration().getBounds());
return bounds;
}
public static class MatchAreaPanel extends JPanel {
protected static final long FADE_OUT_TIME = 2500;
private float alpha = 1f;
private long fadeStartAt;
private Timer fadeTimer;
private Timer waitTimer;
public MatchAreaPanel() {
setOpaque(false);
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
fadeOut();
}
});
fadeTimer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
long runTime = System.currentTimeMillis() - fadeStartAt;
float progress = 0f;
if (runTime >= FADE_OUT_TIME) {
progress = 1f;
} else {
progress = (float) runTime / (float) FADE_OUT_TIME;
if (progress > 1f) {
progress = 1f;
}
}
alpha = 1f - progress;
if (progress >= 1f) {
((Timer) e.getSource()).stop();
SwingUtilities.windowForComponent(MatchAreaPanel.this).dispose();
}
repaint();
}
});
waitTimer = new Timer(5000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
((Timer) e.getSource()).stop();
fadeOut();
}
});
}
protected void fadeOut() {
waitTimer.stop();
fadeStartAt = System.currentTimeMillis();
fadeTimer.start();
}
public void start() {
if (!waitTimer.isRunning() && !fadeTimer.isRunning()) {
waitTimer.start();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(alpha));
g2d.setColor(new Color(128, 128, 128, 64));
g2d.fillRect(0, 0, getWidth(), getHeight());
float dash1[] = {10.0f};
BasicStroke dashed = new BasicStroke(3.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f);
g2d.setColor(Color.BLACK);
g2d.setStroke(dashed);
g2d.drawRect(0, 0, getWidth() - 3, getHeight() - 3);
g2d.dispose();
}
}
}
Related
I have this code. I need to make this square flexible when I resize JFrame. The size of square should change in percentage. this.getWidth(),this.getHeight() returns (0,0);
super.getWidth(), super.getHeight() returns (0,0);
getWidth(), getHeight() returns (0,0);
No examples found by me. I have nothing more to add. Thank you very much!
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.event.ComponentEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Parker {
public static void main(String[] args) {
new Parker();
}
public Parker() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new ControlPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ControlPane extends JPanel {
private JSlider slider;
private DrawPane myPanel;
public ControlPane() {
setLayout(new BorderLayout());
myPanel = new DrawPane();
myPanel.setBackground(Color.WHITE);
Dimension dim = myPanel.getSize();
slider = new JSlider(SwingConstants.HORIZONTAL,0,100,20);
slider.setMajorTickSpacing(20);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.setValue(0);
slider.setBorder(
BorderFactory.createCompoundBorder(
BorderFactory.createTitledBorder("Slider"),
BorderFactory.createEmptyBorder(15,10,15,10)
)
);
slider.addChangeListener(
new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
myPanel.setScale(slider.getValue());
}
}
);
add(slider,BorderLayout.SOUTH);
add(myPanel,BorderLayout.CENTER);
}
}
public class DrawPane extends JPanel {
double scale = 1;
double angle = 0;
//here i tried different methods to find current size of frame, you can
//set some int values like 10 or 100 to watch that everything works
//properly
int rectWidth = ;
int rectHeight = ;
public void componentResized(ComponentEvent e) {
Dimension newSize = e.getComponent().getBounds().getSize();
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
int originX = getWidth() / 2;
int originY = getHeight() / 2;
int xOffset = -(rectWidth / 2);
int yOffset = -(rectHeight / 2);
g.setColor(Color.BLACK);
Graphics2D g2d = (Graphics2D) g.create();
g2d.translate(originX, originY);
g2d.scale(scale, scale);
g2d.fill(new Rectangle2D.Double(xOffset, yOffset, rectWidth, rectHeight));
g2d.dispose();
g.setColor(Color.RED);
g.drawRect(originX + xOffset, originY + yOffset, rectWidth, rectWidth);
}
public void setScale(int scale) {
this.scale = (scale / 100d);
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 200);
}
}
}
you should register a ComponentListener to your ControlPanel which is the main content pane of your JFrame for listening resize event's (also listens for initial resizing) and make the rectangle resize,
try this:
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.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.geom.Rectangle2D;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Parker {
public static void main(String[] args) {
new Parker();
}
public Parker() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new ControlPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ControlPane extends JPanel {
private JSlider slider;
private DrawPane myPanel;
public ControlPane() {
setLayout(new BorderLayout());
myPanel = new DrawPane();
myPanel.setBackground(Color.WHITE);
Dimension dim = myPanel.getSize();
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
Dimension dim = e.getComponent().getSize();
myPanel.resizeRectangle(dim.width / 2, dim.height / 2);
}
});
slider = new JSlider(SwingConstants.HORIZONTAL, 0, 100, 20);
slider.setMajorTickSpacing(20);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.setValue(0);
slider.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder("Slider"),
BorderFactory.createEmptyBorder(15, 10, 15, 10)));
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
myPanel.setScale(slider.getValue());
}
});
add(slider, BorderLayout.SOUTH);
add(myPanel, BorderLayout.CENTER);
}
}
public class DrawPane extends JPanel {
double scale = 1;
double angle = 0;
int rectWidth = 50;
int rectHeight = 50;
public void componentResized(ComponentEvent e) {
Dimension newSize = e.getComponent().getBounds().getSize();
}
public void resizeRectangle(int width, int height) {
rectWidth = width;
rectHeight = height;
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int originX = getWidth() / 2;
int originY = getHeight() / 2;
int xOffset = -(rectWidth / 2);
int yOffset = -(rectHeight / 2);
g.setColor(Color.BLACK);
Graphics2D g2d = (Graphics2D) g.create();
g2d.translate(originX, originY);
g2d.scale(scale, scale);
g2d.fill(new Rectangle2D.Double(xOffset, yOffset, rectWidth, rectHeight));
g2d.dispose();
g.setColor(Color.RED);
g.drawRect(originX + xOffset, originY + yOffset, rectWidth, rectWidth);
}
public void setScale(int scale) {
this.scale = (scale / 100d);
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 200);
}
}
}
I have a JSlider that specifies the thickness of a line drawn on a JPanel. I added a ChangeListener to it, so when the slider is changed, it should also change the thickness of the line. But when I do that, the thickness doesn't change and instead, I'm given a faded out line. When I don't have the ChangeListener, the initial color is a purple line. I don't understand what's going on.
This is in my main GUI class, it includes the JSlider and the ChangeListener:
final JSlider slider = new JSlider(SwingConstants.HORIZONTAL, 0, 20, 1);
slider.setMajorTickSpacing(5);
slider.setMinorTickSpacing(1);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.addChangeListener(new ChangeListener() {
public void stateChanged(final ChangeEvent theEvent) {
final int stroke = slider.getValue();
myDrawPanel.setStroke(stroke);
myDrawPanel.repaint();
}
});
And this is in another class where the line is being drawn:
public void setStroke(final int theStroke) {
myStroke = theStroke;
}
public void paintComponent(final Graphics theGraphics) {
super.paintComponent(theGraphics);
final Graphics2D g2d = (Graphics2D) theGraphics;
// for better graphics display
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(new Color(51, 0, 111));
g2d.setStroke(new BasicStroke(myStroke));
g2d.draw(new Line2D.Double(myX, myY, myXEnd, myYEnd));
for (Line2D l : myLines) {
g2d.draw(l);
}
}
And this is the outcome:
And this is what the line originally looked like when I hardcoded a line thickness number in my paintComponent method:
Seems to work okay for me, I guess the problem is somewhere else in the code you're not showing us
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
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 Example {
public static void main(String[] args) {
new Example();
}
public Example() {
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 ControlPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ControlPane extends JPanel {
public ControlPane() {
setLayout(new BorderLayout());
DrawPane pane = new DrawPane();
add(pane);
JSlider slider = new JSlider(0, 20, 1);
add(slider, BorderLayout.SOUTH);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
pane.setStroke(slider.getValue());
}
});
slider.setValue(1);
}
}
public class DrawPane extends JPanel {
private int myStroke = 1;
public DrawPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void setStroke(int myStroke) {
this.myStroke = myStroke;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setStroke(new BasicStroke(myStroke));
g2d.drawLine(0, 0, getWidth(), getHeight());
g2d.dispose();
}
}
}
Consider providing a runnable example which demonstrates your problem. This is not a code dump, but an example of what you are doing which highlights the problem you are having. This will result in less confusion and better responses
I am trying to make a portion of my screen appear blurry. I grab pixel colors out of a BufferedImage where I saved a capture of the screen and draw the pixels again as bigger squares. But this only works when the paint method is called the first time, after that the affected pixels always stay the same even when the content of the screen updates. So it seems that even though the canvas is refreshed at the beginning of the paint method, the robot still sees the screen as it was previously...
#Override public void paintComponent(Graphics g) {
super.paintComponent(g);
screen = robot.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
int gap = 10; int width = 1920;
for (int r = 120; r <= 420; r += gap) {
for (int c = 500; c <= width - 500; c += gap) {
g.setColor(new Color(screen.getRGB(c, r)));
g.fillRect(c, r, gap, gap);
}
}
}
I tried clearing the painted area using clearRect() and sleeping the Thread at different positions, but it didn't work. Where do I need to put the createScreenCapture() so the painting actually updates?
This is the whole class:
import java.awt.AWTException;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Transparent extends JPanel implements Runnable {
private JFrame frame;
private Robot robot;
private BufferedImage screen;
public static void main(String[] args) {
new Transparent();
}
public Transparent() {
try {
robot = new Robot();
} catch (AWTException ex) {
ex.printStackTrace();
}
frame = new JFrame();
init();
frame.add(this);
frame.setUndecorated(true);
frame.setBackground(new Color(0, true));
frame.setAlwaysOnTop(true);
frame.setSize(1920, 1080);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
new Thread(this).start();
}
public void init() {
setBackground(new Color(0, true));
setOpaque(false);
}
#Override public void paintComponent(Graphics g) {
super.paintComponent(g);
screen = robot.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
int gap = 5; int width = 1920;
for (int r = 120; r <= 420; r += gap) {
for (int c = 500; c <= width - 500; c += gap) {
g.setColor(new Color(screen.getRGB(c, r)));
g.fillRect(c, r, gap, gap);
}
}
}
#Override public void run() {
while (true) {
repaint();
try {
Thread.sleep(10);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
A number of things pop out at me...
You seem to be capturing the who screen, but are't taking into account were the window may actually be positioned and what area it might be covering
When you capture the screen, you component is going to be on it...
Now, this is a very simple example. I demonstrates how to convert the area of your panel to the screen coordinates and capture only that area. It does this by first hiding the window and then taking a snap shot of it before re-showing the window and painting the resulting snap-shot...
import com.jhlabs.image.GaussianFilter;
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Transparency;
import java.awt.Window;
import java.awt.event.HierarchyBoundsAdapter;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
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 {
JPanel outter = new JPanel(new BorderLayout());
outter.setBorder(new EmptyBorder(20, 20, 20, 20));
outter.add(new TestPane());
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(outter);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (AWTException | HeadlessException exp) {
exp.printStackTrace();
}
}
});
}
public class TestPane extends JPanel {
private Robot bot;
private BufferedImage snapShot;
private Point lastSnapShot;
public TestPane() throws AWTException {
bot = new Robot();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void updateSnapshot() {
Rectangle bounds = getBounds();
Point p = new Point(0, 0);
SwingUtilities.convertPointToScreen(p, this);
bounds.setLocation(p);
if (lastSnapShot == null || !lastSnapShot.equals(p)) {
lastSnapShot = p;
Window window = SwingUtilities.getWindowAncestor(this);
window.addHierarchyListener(new HierarchyListener() {
#Override
public void hierarchyChanged(HierarchyEvent e) {
if (!window.isVisible()) {
e.getComponent().removeHierarchyListener(this);
snapShot = bot.createScreenCapture(bounds);
snapShot = generateBlur(snapShot, 10);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
window.setVisible(true);
}
});
}
}
});
window.setVisible(false);
}
}
public BufferedImage generateBlur(BufferedImage imgSource, int size) {
GaussianFilter filter = new GaussianFilter(size);
int imgWidth = imgSource.getWidth();
int imgHeight = imgSource.getHeight();
BufferedImage imgBlur = createCompatibleImage(imgWidth, imgHeight, Transparency.OPAQUE);
Graphics2D g2 = imgBlur.createGraphics();
g2.drawImage(imgSource, 0, 0, null);
g2.dispose();
imgBlur = filter.filter(imgBlur, null);
return imgBlur;
}
public BufferedImage createCompatibleImage(int width, int height, int transparency) {
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
BufferedImage image = gc.createCompatibleImage(width, height, transparency);
image.coerceData(true);
return image;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (snapShot == null) {
updateSnapshot();
}
int x = 0;
int y = 0;
g2d.drawImage(snapShot, 0, 0, this);
g2d.dispose();
}
}
}
This example takes advantage of JH Lab's Filters, cause I'm to lazy to create my own...
I borrowed the class below to make a selection area tool for a project. But it has a issue when I try to make a selection when the content is not aligned at top-left, it get my mouse coordinates related to the ScrollPane, but draws over the image - See this SS for better understanding:
sscce:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
/** Getting a Rectangle of interest on the screen.
Requires the MotivatedEndUser API - sold separately. */
public class ScreenCaptureRectangle {
Rectangle captureRect;
ScreenCaptureRectangle(final BufferedImage screen) {
final BufferedImage screenCopy = new BufferedImage(screen.getWidth(), screen.getHeight(), screen.getType());
final JLabel screenLabel = new JLabel(new ImageIcon(screenCopy));
JScrollPane screenScroll = new JScrollPane(screenLabel);
screenScroll.setPreferredSize(new Dimension((int)(screen.getWidth()*2), (int)(screen.getHeight()*2)));
JPanel panel = new JPanel(new BorderLayout());
panel.add(screenScroll, BorderLayout.CENTER);
final JLabel selectionLabel = new JLabel("Drag a rectangle in the screen shot!");
panel.add(selectionLabel, BorderLayout.SOUTH);
repaint(screen, screenCopy);
screenLabel.repaint();
screenLabel.addMouseMotionListener(new MouseMotionAdapter() {
Point start = new Point();
#Override
public void mouseMoved(MouseEvent me) {
start = me.getPoint();
repaint(screen, screenCopy);
selectionLabel.setText("Start Point: " + start);
screenLabel.repaint();
}
#Override
public void mouseDragged(MouseEvent me) {
Point end = me.getPoint();
captureRect = new Rectangle(start, new Dimension(end.x-start.x, end.y-start.y));
repaint(screen, screenCopy);
screenLabel.repaint();
selectionLabel.setText("Rectangle: " + captureRect);
}
});
JOptionPane.showMessageDialog(null, panel);
System.out.println("Rectangle of interest: " + captureRect);
}
public void repaint(BufferedImage orig, BufferedImage copy) {
Graphics2D g = copy.createGraphics();
g.drawImage(orig,0,0, null);
if (captureRect!=null) {
g.setColor(Color.RED);
g.draw(captureRect);
g.setColor(new Color(255,255,255,150));
g.fill(captureRect);
}
g.dispose();
}
public static void main(String[] args) throws Exception {
Robot robot = new Robot();
final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
final BufferedImage screen = robot.createScreenCapture(new Rectangle(300,0,300,300));
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ScreenCaptureRectangle(screen);
}
});
}
}
I think you have problems because you are attempting to center the image in the panel.
The easiest solution is to make sure the image is painted from the top/left of the panel:
final JLabel screenLabel = new JLabel(new ImageIcon(screenCopy));
screenLabel.setHorizontalAlignment(JLabel.LEFT);
screenLabel.setVerticalAlignment(JLabel.TOP);
Basically, what's happening, is you are drawing directly to the image surface (which is held by the JLabel), so while, you drag at 2x2x36x36 on the screen, this then draws on the rectangle RELATIVE to the image itself
So even though the image is centered within the context of the JLabel, you are still rendering to the local context of the image (0x0), hence the disconnection between the two.
Depending on what it is you want to achieve, you change the way the painting works and take more direct control, for example...
import java.awt.AWTException;
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.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DrawimgExample {
public static void main(String[] args) {
try {
Robot robot = new Robot();
final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
final BufferedImage screen = robot.createScreenCapture(new Rectangle(300, 0, 300, 300));
new DrawimgExample(screen);
} catch (AWTException exp) {
exp.printStackTrace();
}
}
public DrawimgExample(final BufferedImage screen) {
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 DrawingPane(screen));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DrawingPane extends JPanel {
private BufferedImage img;
private Rectangle drawRect;
public DrawingPane(BufferedImage img) {
this.img = img;
MouseAdapter mouseHandler = new MouseAdapter() {
private Point startPoint;
#Override
public void mousePressed(MouseEvent e) {
startPoint = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e) {
Point endPoint = e.getPoint();
int startX = Math.min(startPoint.x, endPoint.x);
int startY = Math.min(startPoint.y, endPoint.y);
int width = Math.max(startPoint.x, endPoint.x) - startX;
int height = Math.max(startPoint.y, endPoint.y) - startY;
drawRect = new Rectangle(
startX,
startY,
width,
height
);
repaint();
}
};
addMouseListener(mouseHandler);
addMouseMotionListener(mouseHandler);
}
#Override
public Dimension getPreferredSize() {
return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
if (drawRect != null) {
g2d.setColor(Color.RED);
g2d.draw(drawRect);
g2d.setColor(new Color(255, 255, 255, 150));
g2d.fill(drawRect);
}
g2d.dispose();
}
}
}
Having said that, where possible, you should avoid painting images directly, as JLabel already does a good job, but sometimes, if it doesn't meet your needs, you might need to take more direct control
I know how to draw a rounded rectangle but I want to define roundness for each corner separately and draw something like the image below :
There's probably a few ways to achieve this, but the easiest I can think of would be to, as Andrew has already hinted, would be to define your own Shape
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class SimpleShape {
public static void main(String[] args) {
new SimpleShape();
}
public SimpleShape() {
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 RightEnd rightEnd;
public TestPane() {
rightEnd = new RightEnd(100, 100, 40);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = (getWidth() - 100) / 2;
int y = (getHeight()- 100) / 2;
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.translate(x, y);
g2d.fill(rightEnd);
g2d.dispose();
}
}
public class RightEnd extends Path2D.Float {
public RightEnd(float width, float height, float radius) {
moveTo(0, 0);
lineTo(width - radius, 0);
curveTo(width, 0, width, 0, width, radius);
lineTo(width, height - radius);
curveTo(width, height, width, height, width - radius, height);
lineTo(0, height);
closePath();
}
}
}