I am trying to write a paint app that has a use of layers. I currently have 4 layers, the bottom one is white color and all other are transparent. Meanwhile I have only the 3rd(top) layer drawing to the buffered image, others for some reason only show preview but do not commit to the image. Also even though I implemented the transparency of the layers, it does not take affect. All the layers are black. The good part is that is shows the top most layer at all times. Please help
public class Canvas extends JComponent implements MouseWheelListener {
private static final long serialVersionUID = 1L;
private final List<BufferedImage> images;
private DrawListenerInterface listenerInterface;
private int activeLayer;
private final Color color;
private final Paint frame;
public Canvas(Paint frame) {
this.frame = frame;
this.images = new ArrayList<BufferedImage>();
this.activeLayer = 0;
this.color = Color.red;
for (int i = 0; i < 4; i++) {
images.add(new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB));
setLayers(i);
}
this.addMouseWheelListener(this);
}
public class Canvas extends JComponent implements MouseWheelListener {
private static final long serialVersionUID = 1L;
private final List<BufferedImage> images;
private DrawListenerInterface listenerInterface;
private int activeLayer;
private final Color color;
private final Paint frame;
public Canvas(Paint frame) {
this.frame = frame;
this.images = new ArrayList<BufferedImage>();
this.activeLayer = 0;
this.color = Color.red;
for (int i = 0; i < 4; i++) {
images.add(new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB));
setLayers(i);
}
this.addMouseWheelListener(this);
}
public void setListeners(DrawListenerInterface listener) {
if (listenerInterface != null) {
this.removeMouseListener(listenerInterface);
this.removeMouseMotionListener(listenerInterface);
}
this.listenerInterface = listener;
this.addMouseMotionListener(listenerInterface);
this.addMouseListener(listenerInterface);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// defaultSettings((Graphics2D) g);
final Iterator<BufferedImage> iter = images.iterator();
while (iter.hasNext()) {
// g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
g.drawImage(iter.next(), 0, 0, null);
this.repaint();
}
listenerInterface.preview((Graphics2D) g);
this.repaint();
// g2.drawImage(images.get(activeLayer), 0, 0, null);
// }
// g2.setColor(color);
}
public BufferedImage getImage() {
return images.get(activeLayer);
}
public int getActiveLayer() {
return activeLayer;
}
public void setActiveLayer(int activeLayer) {
this.activeLayer = activeLayer;
}
public void setLayers(int layerNumber) {
// System.out.println(layer);
if (layerNumber == 0) {
final Graphics2D g = (Graphics2D) images.get(0).getGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, 800, 600);
} else {
BufferedImage img = images.get(layerNumber);
img = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);
final Graphics2D graphics = (Graphics2D) img.getGraphics();
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
graphics.fillRect(0, 0, 800, 600);
// reset composite
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
}
repaint();
}
#Override
public void mouseWheelMoved(MouseWheelEvent arg0) {
// TODO Auto-generated method stub
}
public class DrawListener implements DrawListenerInterface {
private final Canvas canvas;
private int x, y;
private int x2;
private int y2;
private final Paint frame;
public DrawListener(Canvas canvas, Paint frame) {
this.canvas = canvas;
this.frame = frame;
}
#Override
public void mouseMoved(MouseEvent e) {
}
#Override
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
this.x2 = e.getX();
this.y2 = e.getY();
final Graphics2D g2 = (Graphics2D) canvas.getImage().getGraphics();
draw(g2);
canvas.repaint();
x = x2;
y = y2;
}
#Override
public void draw(Graphics2D g2) {
// TODO Auto-generated method stub
g2.drawLine(x, y, x2, y2);
}
#Override
public void mouseClicked(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
x = e.getX();
x2 = e.getX();
y = e.getY();
y2 = e.getY();
final Graphics2D g2 = (Graphics2D) canvas.getImage().getGraphics();
draw(g2);
canvas.repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void preview(Graphics2D g2) {
// TODO Auto-generated method stub
}
public class LayerPanel extends JPanel {
private final JButton layer0, layer1, layer2, layer3;
private final Canvas canvas;
public LayerPanel(Canvas canvas, Paint paint) {
this.canvas = canvas;
this.setSize(new Dimension(200, 400));
this.layer0 = new JButton("Layer 0");
this.layer1 = new JButton("Layer 1");
this.layer2 = new JButton("Layer 2");
this.layer3 = new JButton("Layer 3");
this.layer0.addActionListener(new ButtonListener());
this.layer1.addActionListener(new ButtonListener());
this.layer2.addActionListener(new ButtonListener());
this.layer3.addActionListener(new ButtonListener());
this.setLayout(new GridLayout(4, 1));
this.add(layer3);
this.add(layer2);
this.add(layer1);
this.add(layer0);
}
private class ButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
layer0.setBackground(Color.gray);
layer1.setBackground(Color.gray);
layer2.setBackground(Color.gray);
layer3.setBackground(Color.gray);
if (e.getSource().equals(layer0)) {
canvas.setActiveLayer(0);
final JButton b = (JButton) e.getSource();
b.setBackground(Color.yellow);
} else if (e.getSource().equals(layer1)) {
canvas.setActiveLayer(1);
final JButton b = (JButton) e.getSource();
b.setBackground(Color.yellow);
} else if (e.getSource().equals(layer2)) {
canvas.setActiveLayer(2);
final JButton b = (JButton) e.getSource();
b.setBackground(Color.yellow);
} else if (e.getSource().equals(layer3)) {
canvas.setActiveLayer(3);
final JButton b = (JButton) e.getSource();
b.setBackground(Color.yellow);
}
}
}
public interface DrawListenerInterface extends MouseListener, MouseMotionListener {
public void draw(Graphics2D g2);
public void preview(Graphics2D g2);
Your call to super.paintComponent(g) in Canvas indirectly calls ComponentUI.update(..):
public void update(Graphics g, JComponent c) {
if (c.isOpaque()) {
g.setColor(c.getBackground());
g.fillRect(0, 0, c.getWidth(),c.getHeight());
}
paint(g, c);
}
So unless you call setOpaque(false) on the component at some point, you are always filling g with the background color.
I'd try setting opaque to false or remove the super.paintComponent(g) call.
There seem to be other issues with the code as well.
The images you create in the Canvas constructor are all TYPE_INT_RGB, i.e. they do not support an alpha channel/transparency.
But then later in setLayers() for layers other than 0, you retrieve the image img and then overwrite it with a new, transparency-supporting image, that you never stored anywhere:
BufferedImage img = images.get(layerNumber);
img = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);
img is lost right after you leave the corresponding block.
It's hard to understand what you are actually asking, but:
BufferedImage img = images.get(layerNumber);
img = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);
final Graphics2D graphics = (Graphics2D) img.getGraphics();
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
graphics.fillRect(0, 0, 800, 600);
// reset composite
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
You are not storing the img anywhere, even though you create a new instance for it. Also there's no point in getting it from the images and then right after setting it to something else.
Related
I'm trying to make it when you click the cameraButton, the graphics show, but when clicked again, it closes.
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int camButtonWidth = 500;
int camButtonHeight = 33;
int camButtonX = (width - camButtonWidth) / 2;
int camButtonY = (height - camButtonHeight) - 5;
int camWidth = width - 50;
int camHeight = (height - (camButtonHeight * 2)) - 10;
int camX = (width - camWidth) / 2;
int camY = ((height - camHeight) - camButtonHeight) / 2;
Graphics2D g1 = (Graphics2D) g;
Graphics2D g2 = (Graphics2D) g;
Graphics2D g3 = (Graphics2D) g;
RoundRectangle2D camButton = new RoundRectangle2D.Double(camButtonX, camButtonY, camButtonWidth, camButtonHeight, 25, 25);
RoundRectangle2D cameras = new RoundRectangle2D.Double(camX, camY, camWidth, camHeight, 25, 25);
// Background
g1.setColor(Color.BLACK);
g1.fillRect(0, 0, width, height);
addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
if (camButton.contains(e.getPoint())) {
camUp = !camUp;
repaint();
}
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
});
// Camera Button
g2.setColor(camColor);
g2.fill(camButton);
paintCameras = camUp;
// Cameras
g3.setColor(camColor);
if (paintCameras) {
g3.fill(cameras);
}
repaint();
}
Try to change make it when you click the camera button, a graphics object shows, but when clicked again, it closes.
To get this sort of program to work you should:
Create your MouseListener in code that is only called once, such as within a constructor
Create an instance field in the class to represent the camera button, such as a Rectangle or RoundRectangle2D and give it a viable object reference
In the mouse listener, toggle the state of a boolean variable if a click occurs within the shape that represents the camera button, e.g., camUp = !camUp; as you're doing
And then call repaint().
In the paintComponent method, check the state of the boolearn variable with an if statement, and if true, draw the image inside the if statement.
Keep the mouse listener and the painting code separate and in separate methods (or constructor).
Never call repaint() within a painting method as that will cause an uncontrolled animation. If you need a Swing animation, then use a Swing Timer so that you can fully control it. I don't see the need for it here.
For example:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class GraphicsExample extends JPanel {
private static final int IMG_WIDTH = 400;
private static final int PREF_W = (3 * IMG_WIDTH) / 2;
private static final int PREF_H = PREF_W;
private static final Color BTN_COLOR = Color.RED;
private static final Color HOVER_COLOR = new Color(255, 100, 100);
private static final Color BTN_CLK_COLOR = new Color(180, 0, 0);
private static final int IMG_X = IMG_WIDTH / 2;
private static final int IMG_Y = IMG_X;
private double camX = 10;
private double camY = camX;
private double camWidth = 200;
private double camHeight = 80;
private Color buttonColor = Color.RED;
private RoundRectangle2D cameraButton = new RoundRectangle2D.Double(camX, camY, camWidth, camHeight, 25, 25);
private Image img;
private boolean showImage = false;
private JCheckBox toggleModeChkBox = new JCheckBox("Toggle Mode");
// private boolean toggleMode = true;
public GraphicsExample() {
add(toggleModeChkBox);
setPreferredSize(new Dimension(PREF_W, PREF_H));
img = createMyImage();
MouseAdapt mouseAdapt = new MouseAdapt();
addMouseListener(mouseAdapt);
addMouseMotionListener(mouseAdapt);
}
private Image createMyImage() {
BufferedImage img = new BufferedImage(IMG_WIDTH, IMG_WIDTH, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setPaint(new GradientPaint(0, 0, Color.RED, 100, 100, Color.BLUE, true));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int gap = 10;
g2.fillOval(gap, gap, IMG_WIDTH - 2 * gap, IMG_WIDTH - 2 * gap);
g2.dispose();
return img;
}
private class MouseAdapt extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
if (cameraButton.contains(e.getPoint())) {
buttonColor = BTN_CLK_COLOR;
if (toggleModeChkBox.isSelected()) {
showImage = !showImage;
} else {
showImage = true;
}
} else {
buttonColor = BTN_COLOR;
}
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
if (cameraButton.contains(e.getPoint())) {
buttonColor = HOVER_COLOR;
} else {
buttonColor = Color.RED;
}
if (!toggleModeChkBox.isSelected()) {
showImage = false;
}
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
if (cameraButton.contains(e.getPoint())) {
buttonColor = HOVER_COLOR;
} else {
buttonColor = Color.RED;
}
if (!toggleModeChkBox.isSelected()) {
showImage = false;
}
repaint();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(buttonColor);
g2.fill(cameraButton);
if (showImage) {
int x = (getWidth() - IMG_WIDTH) / 2;
int y = (getHeight() - IMG_WIDTH) / 2;
g2.drawImage(img, x, y, this);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
GraphicsExample mainPanel = new GraphicsExample();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
Currently, I'm working on my first Java application with which a user can look through photos, cut them and rotate. I have an issue with clipping an image. What I want to achieve is the following:
User clicks on the "Cut" option
Rectangle shape called by repaint method appears on the image
By stretching the rectangle user chooses the area for cutting
When the user releases the mouse(which stops stretching the rectangle) the area that is surrounded with the rectangle is left and all the rest of the image is cut.
As of for now I have several issues:
My image is centralized on JLabel which in its turn is added to JPanel and the last is added to JFrame, so now, when I want to add a rectangle above JLable (so it is to be located on the picture) it's invisible and is added only on JPanel directly.
I drew an image with paintComponent but can't figure out how to move and stretch it and repaint the rectangle again.
Below is the part of my code which (I hope) will describe my problems more precisely:
public class GraphicalUserInterface {
static JPanel background;
static JLabel labelIcon;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new GraphicalUserInterface().go();
}
});
}
public void go() {
buildGui();
}
public void buildGui() {
frame = new JFrame("PicMove");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BorderLayout layout = new BorderLayout();
background = new JPanel(layout);
/**To center picture on the background**/
labelIcon = new JLabel();
labelIcon.setHorizontalAlignment(JLabel.CENTER);
labelIcon.setVerticalAlignment(JLabel.CENTER);
background.add(BorderLayout.SOUTH, bottom);
background.add(BorderLayout.PAGE_START, bar);
background.add(BorderLayout.CENTER, labelIcon);
background.add(BorderLayout.EAST, chatPanel);
frame.getContentPane().add(BorderLayout.CENTER, background);
frame.setJMenuBar(menuBar);
frame.setVisible(true);
frame.setSize(1300, 1200);}
static class CutImage extends JPanel implements Runnable {
boolean clip;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
if (clip) {
BasicStroke bs = new BasicStroke(50, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
10, null, 0);
g2d.setStroke(bs);
QuadCurve2D.Float qc = new QuadCurve2D.Float(20, 50, 100, 140, 460, 170);
g2d.setClip(qc);
}
BasicStroke bs = new BasicStroke(5, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
10, new float[]{10}, 0);
g2d.setStroke(bs);
g2d.drawRect(260, 50, 80, 120);
}
#Override
public void run() {
CutImage cutPanel = new CutImage();
GraphicalUserInterface.background.add(cutPanel).repaint();
}
}
public class PicChanges implements Runnable{
static BufferedImage newImage;
static File [] selectedFile;
static int currentImage;
FileNameExtensionFilter filter;
JFileChooser fileChooser;
public void openPic() {
currentImage = 0;
try {
fileChooser = new JFileChooser();
fileChooser.setCurrentDirectory(new java.io.File((System.getProperty("user.home"))));
filter = new FileNameExtensionFilter("*.images", "jpg", "gif", "png");
fileChooser.addChoosableFileFilter(filter);
fileChooser.setMultiSelectionEnabled(true);
int result = fileChooser.showOpenDialog(null);
if (result == JFileChooser.OPEN_DIALOG) {
selectedFile = fileChooser.getSelectedFiles();
for (File image : selectedFile) {
if ((image.isFile()) && (selectedFile.length > 0)){
newImage = ImageIO.read(selectedFile[0]);
GraphicalUserInterface.labelIcon.setIcon(new ImageIcon(
new ImageIcon(newImage).getImage().getScaledInstance(
450, 620, Image.SCALE_DEFAULT)));
} else if (result == JFileChooser.CANCEL_OPTION) {
System.out.println("No Pics Selected");
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
Thread.currentThread().interrupt();
openPic();
}
public static void nextPic() {
currentImage++;
try {
newImage = ImageIO.read(selectedFile[currentImage]);
} catch (IOException e) {
e.printStackTrace();
System.out.println("No pictures left");
System.out.println("next"+currentImage);
}
GraphicalUserInterface.labelIcon.setIcon(new ImageIcon(
new ImageIcon(newImage).getImage().getScaledInstance(
450, 620, Image.SCALE_DEFAULT)));
}
static class NextPicture implements Runnable{
#Override
public void run() {
Thread.currentThread().interrupt();
nextPic();
}
}
public static void previousPic () {
currentImage--;
try {
newImage = ImageIO.read(selectedFile[currentImage]);
} catch (IOException e) {
e.printStackTrace();
System.out.println("previous "+currentImage);
}
GraphicalUserInterface.labelIcon.setIcon(new ImageIcon(
new ImageIcon(newImage).getImage().getScaledInstance(
450, 620, Image.SCALE_DEFAULT)));
}
static class PreviousPic implements Runnable{
#Override
public void run() {
Thread.currentThread().interrupt();
previousPic();
}
}
}
My idea was to add MouseListeners but can I add it to the shape created with Graphics2D?
I would be greatful for the help :)
Thank you
Being in search of finding a solution to this question I've asked two more questions(maybe it will be helpful for someone) :
1) Why BufferedImage is not cut according to the drawn in paintComponent method rectangle(its height is calculated wrong)?
2) Repaint() method doesn't invoke paint() & paintComponent() methods one by one, only paintComponent () method is working
that further helped me to find out the way.
My solution is to create a separate frame for displaying copied BufferedImage in it and on this frame to draw a rectangle with the help of MouseListeners. This is the piece of code:
public class ImageScreenShot extends JFrame implements MouseListener, MouseMotionListener {
#Override
public Dimension getPreferredSize() {
return super.getPreferredSize();
}
private static Thread screenShotThread;
public static Thread getScreenShotThread() {
return screenShotThread;
}
public static void setScreenShotThread(Thread screenShot) {
ImageScreenShot.screenShotThread = screenShot;
}
private int drag_status = 0, c1, c2, c3, c4;
public int getC1() {
return c1;
}
public int getC2() {
return c2;
}
public int getC3() {
return c3;
}
public int getC4() {
return c4;
}
class AdditionalPanel extends JLabel {
private BufferedImage img;
public BufferedImage getImg() {
return img;
}
public AdditionalPanel(BufferedImage img) {
this.img = img;
setPreferredSize(new Dimension(2560, 1600));
getPreferredSize();
setLayout(null);
}
#Override
public Dimension getPreferredSize() {
return super.getPreferredSize();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, 0, 0, null);
System.out.println("Additional panel class paint method was invoked");
}
}
public void cut() {
AdditionalPanel apanel = new AdditionalPanel(PicChanges.getNewImage());
JScrollPane scrollPane = new JScrollPane(apanel);
scrollPane.addMouseMotionListener(this);
scrollPane.addMouseListener(this);
getContentPane().add(scrollPane, BorderLayout.CENTER);
setPreferredSize(new Dimension(2560, 1600));
getPreferredSize();
pack();
setVisible(true);
}
private void draggedScreen() throws Exception {
int w = c1 - c3;
int h = c2 - c4;
w = w * -1;
h = h * -1;
Robot robot = new Robot();
BufferedImage img = robot.createScreenCapture(new Rectangle(c1, c2, w, h));
File save_path = new File("screen1.jpg");
ImageIO.write(img, "JPG", save_path);
GraphicalUserInterface.getLabelIcon().setIcon(new ImageIcon(new ImageIcon(img).getImage().getScaledInstance(img.getWidth(), img.getHeight(), Image.SCALE_SMOOTH)));
JOptionPane.showConfirmDialog(this, "Would you like to save your cropped Pic?");
System.out.println("Cropped image saved successfully.");
}
#Override
public void mouseClicked(MouseEvent arg0) {
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
repaint();
c1 = arg0.getXOnScreen();
c2 = arg0.getYOnScreen();
System.out.println("pressed");
}
#Override
public void mouseReleased(MouseEvent arg0) {
repaint();
if (drag_status == 1) {
c3 = arg0.getXOnScreen();
c4 = arg0.getYOnScreen();
try {
repaint();
draggedScreen();
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public void mouseDragged(MouseEvent arg0) {
repaint();
drag_status = 1;
c3 = arg0.getXOnScreen();
c4 = arg0.getYOnScreen();
}
#Override
public void mouseMoved(MouseEvent arg0) {
}
#Override
public void paint(Graphics g) {
super.paint(g);
int w = c1 - c3;
int h = c2 - c4;
w = w * -1;
h = h * -1;
if (w < 0)
w = w * -1;
g.setColor(Color.RED);
g.drawRect(c1, c2, w, h);
System.out.println("Paint component was invoked in imagescreenshot class");
}
P.S. I know that adding JFrame is not the best solution but I'm still in search for the best way to implement it so do not hesitate to comment on my code and tell what is wrong or what is good)
I am attempting to have an image show up through file path. I have the image in my src folder, and I've tried maybe 5 different types of code.
Ignore the commented out code, those are just shapes i was drawing to test
I've tried it with both file path and file name and nothing has worked. Its not giving me any errors or anything either.
public void ImagePanel() {
try {
image = ImageIO.read(new File("BMan.jpg"));
} catch (IOException ex) {
System.out.println(ex);
}
}
public static void main(String[] args) {
JPanel panel = new MyPanel();
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
//g.setColor(Color.RED);
//g.fillOval(CircleX, CircleY, CircleH, CircleW);
//g.setColor(Color.GREEN);
//g.fillRect(SquareX, SquareY, SquareW, SquareH);
g.drawImage(image, 50, 50, this);
}
Here is my implementation of the component:
public class ImageView extends JComponent
implements ComponentListener {
private static final long serialVersionUID = 3761966077344495154L;
private BufferedImage image;
private int imageX;
private int imageY;
private int imageWidth;
private int imageHeight;
/** Creates a new instance of ImageView */
public ImageView() {
addComponentListener(this);
}
public BufferedImage getImage() {
return image;
}
public Rectangle getImageBounds() {
if (image == null) {
return null;
} else {
return new Rectangle(imageX, imageY, imageWidth, imageHeight);
}
}
public void setImage(final BufferedImage newValue) {
image = newValue;
computeBounds();
repaint();
}
#Override
public void paint(Graphics g) {
long tm = System.currentTimeMillis();
if (isOpaque()) {
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}
BufferedImage img = image;
if (img != null) {
g.drawImage(img, imageX, imageY, imageWidth, imageHeight, null);
}
tm = System.currentTimeMillis()-tm;
}
public void componentResized(ComponentEvent e) {
computeBounds();
}
public void componentMoved(ComponentEvent e) {
}
public void componentShown(ComponentEvent e) {
computeBounds();
}
public void componentHidden(ComponentEvent e) {
}
private void computeBounds() {
BufferedImage img = image;
if (img != null) {
int width = this.getWidth();
int height = this.getHeight();
int wi = img.getWidth();
int hi = img.getHeight();
imageWidth = width;
imageHeight = height;
imageX = 0;
imageY = 0;
if (wi*height < hi*width) {
imageWidth = wi*height/hi;
imageX = (width-imageWidth)/2;
} else {
imageHeight = hi*width/wi;
imageY = (height-imageHeight)/2;
}
}
}
You need to create a JFrame where you will put the panel:
public static void main(String[] args) {
JFrame frame = new JFrame("title");
frame.setSize(400,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//all the other things for the jframe
JPanel panel = new MyPanel();
frame.add(panel);
frame.setVisible(true);
frame.repaint();
}
outputImage
Everything works fine but when i scroll while the graphics is being generated, the scrolled portion graphics disappears
MainApp.java
public abstract class MainApp implements ActionListener{
//Just Listing the method that triggers Canvas(extends JPanel and starts painting)
public void startGeneration(){
String rule = (String) cb.getSelectedItem();
Jexception.setVisible(false);
Jexception1.setVisible(false);
if(genNum > 0){
cgs = new CAGenerationSet(genNum, rule);
cAGenList = new ArrayList<>();
cAGenList = cgs.run(cgs);
if(sp!= null) {
frame.remove(sp);
if(canvas!=null) sp.remove(canvas);
}
//initializing canvas and adding it to the JScrollPane
canvas = new Canvas(cAGenList);
sp = new JScrollPane();
splitPane.setDividerLocation(80);
splitPane.setRightComponent(sp);
sp.setVisible(true);
EventQueue.invokeLater(new Runnable() {
public void run() {
sp.setViewportView(canvas);
sp.revalidate();
}
});
}
else {
Jexception.setVisible(false);
Jexception1.setVisible(true);
}
}
}
Canvas extends JPanel. Here I am overriding the paintComponent() and calling the draw method that triggers the SwingWorker to draw the graphics.
Canvas.java
public class Canvas extends JPanel {
ArrayList<CAGeneration> cAGenList;
private int y,x;
private Thread t;
public static SwingWorker<Void, Void> worker;
private int count = 0;
private boolean check = false;
public CACanvas(ArrayList<CAGeneration> cAGenList) {
this.cAGenList = cAGenList;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 800);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
revalidate();
if(!check){
drawCA(g, this.cAGenList);
}
}
private void drawCA(Graphics g, ArrayList<CAGeneration> cAGenList ) {
worker = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
Graphics2D g2d = (Graphics2D) g;
check = true;
y= 10;
count = 0;
synchronized (cAGenList) {
for(CAGeneration cg: cAGenList){
count++;
y = y+10;
x = 0;
if(!isCancelled()){
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
for(int i=0; i<cg.getcACell().length; i++){
x = x+10;
if (cg.getcACell()[i] == 0) {
paintRect(g2d, x, y, 9, Color.WHITE);
}
if (cg.getcACell()[i] == 1) {
paintRect(g2d, x, y, 9, Color.GRAY);
}
if (cg.getcACell()[i] == 2) {
paintRect(g2d, x, y, 9, Color.BLACK);
}
}
}
}
}
check = false;
return null;
}
};
ExecutorService threadPool = Executors.newSingleThreadExecutor();
threadPool.submit(worker);
}
private void paintRect(Graphics2D g2D, int x, int y, int size, Color color){
if(g2D!=null) g2D = (Graphics2D) getGraphics();
g2D.setColor(color);
g2D.fillRect(x, y, size, size);
}
}
I need to draw shapes (circle or free line) over an image that is shown in a JLabel of a JPanel.
I based my code on the questions How to draw thin line with no gap while dragging the cursor? and Draw a circle using 2 mouse clicks.
The code is bellow. The problem is that when I start drawing the image disappears and only reappears after I stop.
If I comment the line super.paintComponent(g); that doesnt happen but when I draw the circle it maintains a path of the previous positions.
public static void main(String args[]) {
try {
URL url = new URL("http://www.senhoritatours.com/wp-content/uploads/2014/05/Porto-.jpg");
backgroundImage = ImageIO.read(url);
} catch (Exception e) {
e.printStackTrace();
}
loadAnnotation();
loadBackground();
JFrame f;
f = new JFrame();
f.setLayout(new BorderLayout());
f.add(mp);
f.pack();
f.setVisible(true);
}
/* Layer 0:
* Load background picture */
public static void loadBackground() {
JLabel lbImg = new JLabel();
lbImg.setBounds(0, 0, new ImageIcon(backgroundImage).getIconWidth(), new ImageIcon(backgroundImage).getIconHeight());
lbImg.setIcon(new ImageIcon(backgroundImage));
mp = new JPanel(new BorderLayout());
btnCircle.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
if(btnCircle.isEnabled())
{
btnCircle.setEnabled(false);
btnLine.setEnabled(true);
}
}
});
btnLine.setEnabled(true);
btnCircle.setEnabled(false);
btnLine.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
if(btnLine.isEnabled())
{
btnLine.setEnabled(false);
btnCircle.setEnabled(true);
}
}
});
mp.add(btnCircle);
mp.add(btnLine);
mp.add(lbImg);
mp.add(p);
}
/* Layer 1:
* Annotation: Draw on top of background picture anything! */
public static void loadAnnotation() {
p = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setColor(Color.RED);
if (_bufImage == null) {
int w = this.getWidth();
int h = this.getHeight();
_bufImage = new BufferedImage(1024,600, BufferedImage.TRANSLUCENT);
Graphics2D gc = _bufImage.createGraphics();
}
g2.drawImage(_bufImage, null, 0, 0);
if (_state == State.DRAGGING) {
if (!btnLine.isEnabled())
{
g.drawLine(_start.x, _start.y, _end.x , _end.y);
}
}
if (!btnCircle.isEnabled())
{
g.drawOval(x, y, width, height);
}
}
public Dimension getPreferredSize() {
return new Dimension(1024, 600);
}
};
p.setLayout(new OverlayLayout(p));
p.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent me) {
}
#Override
public void mousePressed(MouseEvent me) {
last = me.getPoint();
dragging = isInsideEllipse(last);
if (!dragging) {
x = last.x;
y = last.y;
width = 0;
height = 0;
}
p.repaint();
}
#Override
public void mouseReleased(MouseEvent me) {
//_state = State.IDLE;
last = null;
dragging = false;
_state = State.IDLE;
p.repaint();
}
#Override
public void mouseEntered(MouseEvent me) {
}
#Override
public void mouseExited(MouseEvent me) {
}
});
p.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent me) {
if(!btnLine.isEnabled())
{
_state = State.DRAGGING;
_end = me.getPoint();
if (_state == State.DRAGGING) {
Graphics2D g2 = _bufImage.createGraphics();
g2.setColor(Color.red);
g2.setStroke(new BasicStroke(2));
g2.drawLine(_start.x, _start.y, _end.x, _end.y);
p.repaint();
//
}
_start = _end;
}
else
{
int dx = me.getX() - last.x;
int dy = me.getY() - last.y;
if (dragging) {
x += dx;
y += dy;
} else {
width += dx;
height += dy;
}
last = me.getPoint();
p.repaint();
}
}
#Override
public void mouseMoved(MouseEvent me) {
//System.out.println("move");
_start = me.getPoint();
}
});
}
Either
Display the image in the same paintComponent method that you're doing your drawing in, via Graphics#drawImage(...). You would call this immediately after the super.paintComponent(g) call.
Or do your drawing in the paintComponent(...) method of your JLabel, the one displaying the image.
For example:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class DrawingPanel extends JPanel {
private final static String PATH = "https://upload.wikimedia.org/wikipedia/commons/"
+ "thumb/7/7c/Thomas_Hicks_-_Leopold_Grozelier_-_Presidential_Candidate_"
+ "Abraham_Lincoln_1860_-_cropped_to_lithographic_plate.jpg/"
+ "463px-Thomas_Hicks_-_Leopold_Grozelier_-_Presidential_Candidate_"
+ "Abraham_Lincoln_1860_-_cropped_to_lithographic_plate.jpg";
private static final Color DRAWING_COLOR = new Color(255, 100, 200);
private static final Color FINAL_DRAWING_COLOR = Color.red;
private BufferedImage backgroundImg;
private Point startPt = null;
private Point endPt = null;
private Point currentPt = null;
private int prefW;
private int prefH;
public DrawingPanel() throws IOException {
URL imgUrl = new URL(PATH);
BufferedImage bImg = ImageIO.read(imgUrl);
prefW = bImg.getWidth();
prefH = bImg.getHeight();
backgroundImg = new BufferedImage(prefW, prefH,
BufferedImage.TYPE_INT_ARGB);
Graphics g = backgroundImg.getGraphics();
g.drawImage(bImg, 0, 0, this);
g.dispose();
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseMotionListener(myMouseAdapter);
addMouseListener(myMouseAdapter);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (backgroundImg != null) {
g.drawImage(backgroundImg, 0, 0, this);
}
if (startPt != null && currentPt != null) {
g.setColor(DRAWING_COLOR);
int x = Math.min(startPt.x, currentPt.x);
int y = Math.min(startPt.y, currentPt.y);
int width = Math.abs(startPt.x - currentPt.x);
int height = Math.abs(startPt.y - currentPt.y);
g.drawRect(x, y, width, height);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(prefW, prefH);
}
public void drawToBackground() {
Graphics g = backgroundImg.getGraphics();
g.setColor(FINAL_DRAWING_COLOR);
int x = Math.min(startPt.x, endPt.x);
int y = Math.min(startPt.y, endPt.y);
int width = Math.abs(startPt.x - endPt.x);
int height = Math.abs(startPt.y - endPt.y);
g.drawRect(x, y, width, height);
g.dispose();
startPt = null;
repaint();
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mouseDragged(MouseEvent mEvt) {
currentPt = mEvt.getPoint();
DrawingPanel.this.repaint();
}
#Override
public void mouseReleased(MouseEvent mEvt) {
endPt = mEvt.getPoint();
currentPt = null;
drawToBackground();
}
#Override
public void mousePressed(MouseEvent mEvt) {
startPt = mEvt.getPoint();
}
}
private static void createAndShowGui() {
DrawingPanel mainPanel = null;
try {
mainPanel = new DrawingPanel();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
JFrame frame = new JFrame("Drawing Panel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}