Draw shapes on scrollable JPanel - java

I'm trying to draw rectangles on fairly large images in order to get the pixel coordinates of objects within the image. I am able to display the image and make it scrollable, or display the image and be able to draw rectangles on top of it....but not both.
It's obvious that I'm drawing the image on top of the canvas that I'm trying to draw the rectangles on, but I can't for the life of me figure out how to make it all coexist.
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
public class DrawRect extends JPanel {
int x, y, x2, y2;
private static final long serialVersionUID = 1L;
private BufferedImage image;
private JPanel canvas;
public static void main(String[] args) {
JPanel p = new DrawRect();
JFrame f = new JFrame();
f.setContentPane(p);
f.setSize(400, 300);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
DrawRect() {
x = y = x2 = y2 = 0; //
MyMouseListener listener = new MyMouseListener();
addMouseListener(listener);
addMouseMotionListener(listener);
try {
this.image = ImageIO.read(new URL("https://previews.123rf.com/images/victoroancea/victoroancea1201/victoroancea120100059/12055848-tv-color-test-pattern-test-card-for-pal-and-ntsc.jpg"));
}catch(IOException ex) {
Logger.getLogger(DrawRect.class.getName()).log(Level.SEVERE, null, ex);
}
this.canvas = new JPanel() {
private static final long serialVersionUID = 1L;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
}
};
canvas.setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
JScrollPane sp = new JScrollPane(canvas);
setLayout(new BorderLayout());
add(sp, BorderLayout.CENTER);
}
public void setStartPoint(int x, int y) {
this.x = x;
this.y = y;
}
public void setEndPoint(int x, int y) {
x2 = (x);
y2 = (y);
}
public void drawRect(Graphics g, int x, int y, int x2, int y2) {
int px = Math.min(x,x2);
int py = Math.min(y,y2);
int pw=Math.abs(x-x2);
int ph=Math.abs(y-y2);
g.drawRect(px, py, pw, ph);
}
class MyMouseListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
setStartPoint(e.getX(), e.getY());
}
public void mouseDragged(MouseEvent e) {
setEndPoint(e.getX(), e.getY());
repaint();
}
public void mouseReleased(MouseEvent e) {
setEndPoint(e.getX(), e.getY());
repaint();
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
drawRect(g, x, y, x2, y2);
}
}

Your image-drawing JPanel must be the same JPanel that draws the rectangle and that has the MouseAdapter added to it. For instance:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Image;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
#SuppressWarnings("serial")
public class DrawRect2 extends JPanel {
public static final String IMG_PATH = "https://previews.123rf.com/images/victoroancea"
+ "/victoroancea1201/victoroancea120100059"
+ "/12055848-tv-color-test-pattern-test-card-for-pal-and-ntsc.jpg";
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private DrawingPanel drawingPanel;
public DrawRect2(Image img) {
drawingPanel = new DrawingPanel(img);
JScrollPane scrollPane = new JScrollPane(drawingPanel);
MyMouse myMouse = new MyMouse();
drawingPanel.addMouseListener(myMouse);
drawingPanel.addMouseMotionListener(myMouse);
setLayout(new BorderLayout());
add(scrollPane);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
Image img = null;
try {
URL url = new URL(IMG_PATH);
img = ImageIO.read(url);
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
DrawRect2 mainPanel = new DrawRect2(img);
JFrame frame = new JFrame("DrawRect2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class DrawingPanel extends JPanel {
private Image img;
private Rectangle rectangle;
public DrawingPanel(Image img) {
this.img = img;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
if (rectangle != null) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setXORMode(Color.WHITE);
g2.draw(rectangle);
g2.dispose(); // since we created this object
}
}
#Override
public Dimension getPreferredSize() {
Dimension superSize = super.getPreferredSize();
if (img == null) {
return super.getPreferredSize();
} else {
int w = img.getWidth(this);
int h = img.getHeight(this);
return new Dimension(w, h);
}
}
public void setRectangle(Rectangle rectangle) {
this.rectangle = rectangle;
}
}
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class MyMouse extends MouseAdapter {
private Point p1;
#Override
public void mousePressed(MouseEvent e) {
p1 = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e) {
if (p1 != null) {
createRect(e);
}
}
private void createRect(MouseEvent e) {
Point p2 = e.getPoint();
int x = Math.min(p1.x, p2.x);
int y = Math.min(p1.y, p2.y);
int width = Math.abs(p1.x - p2.x);
int height = Math.abs(p1.y - p2.y);
Rectangle r = new Rectangle(x, y, width, height);
((DrawingPanel) e.getSource()).setRectangle(r);
((DrawingPanel) e.getSource()).repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
if (p1 != null) {
createRect(e);
}
p1 = null;
}
}
So in this paintComponent method, I draw both the image and the Rectangle, using Graphics2D XOR mode to help show the lines regardless of the background color:
#SuppressWarnings("serial")
public class DrawingPanel extends JPanel {
private Image img;
private Rectangle rectangle;
public DrawingPanel(Image img) {
this.img = img;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
if (rectangle != null) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setXORMode(Color.WHITE);
g2.draw(rectangle);
g2.dispose(); // since we created this object
}
}
I also have this method:
public void setRectangle(Rectangle rectangle) {
this.rectangle = rectangle;
}
To allow the MouseListener/Adapter to pass in the Rectangle into this JPanel.
Rectangle r = new Rectangle(x, y, width, height);
((DrawingPanel) e.getSource()).setRectangle(r);
((DrawingPanel) e.getSource()).repaint();

Related

Issues with paint after zooming in and zooming out of JPanel

I have a scrollable JPanel, with some number drawn through the "drawString" method. When I click the zoom in button, the repaint method is invoked and the number becomes larger, as expected. But when I try to scroll to the right, part of the number is either missing or is painted in its original size instead of the new zoomed size. Below is the minimal reproducible code.
package sometest;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
public class SomeTest implements Runnable
{
public static JButton in;
public static JButton out;
public static void main(String[] args)
{
SomeTest st = new SomeTest();
st.run();
}
#Override
public void run()
{
JMenuBar mb = new JMenuBar();
in = new JButton("Zoom In");
out = new JButton("Zoom Out");
JFrame f = new JFrame("Example");
Visualization v = new Visualization();
JScrollPane sp = new JScrollPane(v);
MouseAdapter mouseAdapter = new MouseAdapter()
{
private Point origin;
#Override
public void mousePressed(MouseEvent e)
{
origin = new Point(e.getPoint());
}
#Override
public void mouseDragged(MouseEvent e)
{
JViewport vp = null;
if (origin != null)
{
vp = sp.getViewport();
}
if (vp != null)
{
int deltaX = origin.x - e.getX();
int deltaY = origin.y - e.getY();
Rectangle view = vp.getViewRect();
view.x += deltaX;
view.y += deltaY;
v.scrollRectToVisible(view);
}
}
};
sp.getViewport().addMouseListener(mouseAdapter);
sp.getViewport().addMouseMotionListener(mouseAdapter);
f.add(sp);
f.setJMenuBar(mb);
mb.add(in);
mb.add(out);
f.setContentPane(sp);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
package sometest;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
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.geom.AffineTransform;
import javax.swing.JPanel;
import javax.swing.Scrollable;
import javax.swing.SwingUtilities;
import static sometest.SomeTest.in;
import static sometest.SomeTest.out;
public class Visualization extends JPanel implements Scrollable, ActionListener
{
private double zoomFactor = 1;
private double prevZoomFactor = 1;
private boolean zoomer;
private double xOffset = 0;
private double yOffset = 0;
public Visualization()
{
in.addActionListener(this);
out.addActionListener(this);
Font currentFont = getFont();
Font newFont = currentFont.deriveFont(currentFont.getSize() * 18F);
setFont(newFont);
setBackground(Color.WHITE);
}
#Override
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==in)
{
zoomer = true;
zoomFactor *= 1.1;
repaint();
}
if(e.getSource()==out)
{
zoomer = true;
zoomFactor /= 1.1;
repaint();
}
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if(zoomer)
{
AffineTransform at = new AffineTransform();
Dimension center = getPreferredScrollableViewportSize();
Double xRel = center.getWidth()/2;
Double yRel = center.getHeight()/2;
double zoomDiv = zoomFactor / prevZoomFactor;
xOffset = (zoomDiv) * (xOffset) + (1 - zoomDiv) * xRel;
yOffset = (zoomDiv) * (yOffset) + (1 - zoomDiv) * yRel;
at.translate(xOffset, yOffset);
at.scale(zoomFactor, zoomFactor);
prevZoomFactor = zoomFactor;
g2d.transform(at);
zoomer = false;
}
g2d.drawString("1234567890", 500, 200);
g2d.dispose();
}
#Override
public Dimension getPreferredSize()
{
if(zoomer)
{
return new Dimension((int)(2000*zoomFactor), (int)(750*zoomFactor));
}
else
{
return new Dimension(2000, 750);
}
}
#Override
public Dimension getPreferredScrollableViewportSize()
{
return new Dimension(1550, 750);
}
#Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction)
{
return 32;
}
#Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction)
{
return 32;
}
#Override
public boolean getScrollableTracksViewportWidth()
{
return false;
}
#Override
public boolean getScrollableTracksViewportHeight()
{
return false;
}
}
When I zoom in and scroll, I'm expecting the drawn number to remain the same size. As far as I know, the repaint method is supposed to automatically handle cases such as when scrolling or resizing. Have I misused the repaint method or is my problem something entirely different?
It might be better to use the AffineTransform#concatenate(AffineTransform) method to combine the AffineTransform for zoom and the AffineTransform for translation.
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
AffineTransform scrollTransform = g2d.getTransform();
scrollTransform.concatenate(zoomTransform);
g2d.setTransform(scrollTransform);
g2d.drawString("1234567890", 500, 200);
g2d.dispose();
}
SomeTest2.java
// package sometest;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.AffineTransform;
import javax.swing.*;
public class SomeTest2 {
public JComponent makeUI() {
Visualization v = new Visualization();
MouseAdapter mouseAdapter = new DragScrollListener();
v.addMouseListener(mouseAdapter);
v.addMouseMotionListener(mouseAdapter);
JButton in = new JButton("Zoom In");
in.addActionListener(e -> v.setZoomFactor(1.1));
JButton out = new JButton("Zoom Out");
out.addActionListener(e -> v.setZoomFactor(1 / 1.1));
JMenuBar mb = new JMenuBar();
mb.add(in);
mb.add(out);
EventQueue.invokeLater(() -> v.getRootPane().setJMenuBar(mb));
return new JScrollPane(v);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new SomeTest2().makeUI());
f.setSize(640, 480);
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
class Visualization extends JPanel {
private final AffineTransform zoomTransform = new AffineTransform();
private final Rectangle rect = new Rectangle(2000, 750);
public Visualization() {
Font currentFont = getFont();
Font newFont = currentFont.deriveFont(currentFont.getSize() * 18F);
setFont(newFont);
setBackground(Color.WHITE);
}
public void setZoomFactor(double zoomFactor) {
zoomTransform.scale(zoomFactor, zoomFactor);
revalidate();
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
AffineTransform scrollTransform = g2d.getTransform();
scrollTransform.concatenate(zoomTransform);
g2d.setTransform(scrollTransform);
g2d.drawString("1234567890", 500, 200);
g2d.dispose();
}
#Override
public Dimension getPreferredSize() {
Rectangle r = zoomTransform.createTransformedShape(rect).getBounds();
return new Dimension(r.width, r.height);
}
}
class DragScrollListener extends MouseAdapter {
private final Point origin = new Point();
#Override
public void mouseDragged(MouseEvent e) {
Component c = e.getComponent();
Container p = SwingUtilities.getUnwrappedParent(c);
if (p instanceof JViewport) {
JViewport viewport = (JViewport) p;
Point cp = SwingUtilities.convertPoint(c, e.getPoint(), viewport);
Point vp = viewport.getViewPosition();
vp.translate(origin.x - cp.x, origin.y - cp.y);
((JComponent) c).scrollRectToVisible(new Rectangle(vp, viewport.getSize()));
origin.setLocation(cp);
}
}
#Override
public void mousePressed(MouseEvent e) {
Component c = e.getComponent();
Container p = SwingUtilities.getUnwrappedParent(c);
if (p instanceof JViewport) {
JViewport viewport = (JViewport) p;
Point cp = SwingUtilities.convertPoint(c, e.getPoint(), viewport);
origin.setLocation(cp);
}
}
}

Preventing Dotted Lines When Mouse is Moved Fast

Does anyone know how to draw solid lines when the mouse is rapidly moved?
When I move the mouse slowly the line is drawn solid, but when the mouse is moved quickly the line is drawn like a dotted line, as shown here.
The code to draw the lines is currently this:
private final class MouseL extends MouseAdapter implements MouseMotionListener
{
#Override
public void mouseClicked(MouseEvent e)
{
Point p = e.getPoint();
int half = brushDiameter / 1200;
Graphics2D g = getImage().createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setPaint(getColor());
g.fillOval(p.x - half, p.y - half, brushDiameter, brushDiameter);
g.dispose();
repaint(p.x - half, p.y - half, brushDiameter, brushDiameter);
}
#Override
public void mouseDragged(MouseEvent e)
{
mouseClicked(e);
}
But i would like to change it so that the line appears solid. Any help to achieve this is greatly appreciated thanks.
Simple: If you want to draw curves, don't draw individual points or ovals. Instead connect adjacent points with a line using g.drawLine(...). If you want a thicker curve, change the Graphics2D's Stroke width.
For example:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class DrawCurve extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private static final Color CURRENT_PTS_COLOR = Color.BLUE.brighter().brighter();
public static final Color IMG_COLOR = Color.RED;
public static final Stroke IMG_STROKE = new BasicStroke(4f);
private static final Color FILL_COLOR = Color.WHITE;
private BufferedImage img = null;
private List<Point> currentPts = new ArrayList<>();
public DrawCurve() {
img = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setBackground(FILL_COLOR);
g2.clearRect(0, 0, PREF_W, PREF_H);
g2.dispose();
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, null);
}
Graphics2D g2 = (Graphics2D) g;
g2.setColor(CURRENT_PTS_COLOR);
for (int i = 1; i < currentPts.size(); i++) {
int x1 = currentPts.get(i - 1).x;
int y1 = currentPts.get(i - 1).y;
int x2 = currentPts.get(i).x;
int y2 = currentPts.get(i).y;
g2.drawLine(x1, y1, x2, y2);
}
}
private class MyMouse extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
currentPts = new ArrayList<>();
currentPts.add(e.getPoint());
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
currentPts.add(e.getPoint());
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
currentPts.add(e.getPoint());
Graphics2D g2 = img.createGraphics();
g2.setColor(IMG_COLOR);
g2.setStroke(IMG_STROKE);
for (int i = 1; i < currentPts.size(); i++) {
int x1 = currentPts.get(i - 1).x;
int y1 = currentPts.get(i - 1).y;
int x2 = currentPts.get(i).x;
int y2 = currentPts.get(i).y;
g2.drawLine(x1, y1, x2, y2);
}
g2.dispose();
currentPts.clear();
repaint();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("DrawCurve");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new DrawCurve());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Boolean not keeping value

I have an application where the user draws lines. There is a JButton btnClear which, when the user clicks, must clear the drawings, so that the user can draw anew. I use an ActionListener on btnClear to know when it is clicked. I set a boolean Clear so that the correct IF statement is executed in paintComponent(). However, the boolean Clear keeps a False value in paintComponent() although I set it to True just before repaint(). Why is it so?
Note: I tried setting the frame's background to red just for to test the boolean in paintComponent().
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Line2D;
import javax.swing.*;
public class Clipping extends JPanel implements MouseListener, ActionListener
{
static JFrame frame;
static JComboBox cboDraw;
static JButton btnClear;
static JButton btnClip;
double x1, y1, x2, y2;
boolean FirstPoint;
boolean Clear = false;
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
public void run()
{
CreateFrame();
}
});
}
private static void CreateFrame()
{
frame = new JFrame("Clipping");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Clipping());
frame.setSize(500,500);
frame.setVisible(true);
}
public Clipping()
{
setLayout(new BorderLayout());
JToolBar toolbar = new JToolBar(JToolBar.VERTICAL);
PopulateToolBar(toolbar);
add(toolbar, BorderLayout.WEST);
addMouseListener(this);
cboDraw.addMouseListener(this);
btnClip.addActionListener(this);
btnClear.addActionListener(this);
}
private static void PopulateToolBar(JToolBar toolbar)
{
String[] cboList = {"Line", "Polygon"};
cboDraw = new JComboBox(cboList);
cboDraw.setMaximumSize(new Dimension(70,30));
btnClip = new JButton("Set clip area");
btnClear = new JButton("Clear");
toolbar.add(cboDraw);
toolbar.addSeparator();
toolbar.add(btnClip);
toolbar.addSeparator();
toolbar.add(btnClear);
cboDraw.setAlignmentX(Component.CENTER_ALIGNMENT);
btnClip.setAlignmentX(Component.CENTER_ALIGNMENT);
btnClear.setAlignmentX(Component.CENTER_ALIGNMENT);
toolbar.setMargin(new Insets(10,10,10,10));
toolbar.setFloatable(false);
toolbar.setBackground(Color.black);
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
if (cboDraw.getSelectedIndex() == 0) //draw line
{
g2.draw(new Line2D.Double(x1, y1, x2, y2));
}
else if (Clear == true)
{
frame.setBackground(Color.red); //ONLY FOR TESTING PURPOSE
}
}
public void mousePressed(MouseEvent e)
{
if (e.getSource() != cboDraw) //to prevent line coordinates from being saved when selecting from combobox
{
if (cboDraw.getSelectedIndex() == 0) //user wants to draw line
{
if (FirstPoint == false) //first coordinates
{
x1 = e.getX();
y1 = e.getY();
FirstPoint = true;
}
else //second coordinates
{
x2 = e.getX();
y2 = e.getY();
repaint();
FirstPoint = false;
}
}
}
}
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == btnClear)
{
Clear = true;
repaint();
Clear = false;
}
}
public void mouseClicked(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}
You should just do setBackground(Color.red); to call it on your JPanel instead of the JFrame
I think your actionPerformed and mousePressed are both executed at the same time. In mousePressed your if condition inside mousePressed is satisfied also if btnClear() is the source. So repaint method is called anyway, and you see no changes.
You're not calling the super.paintComponent(g) method within your paintComponent method override. Call this first, else, clear won't work.
Note that in your current code, this will not work for you since you're painting incorrectly in that you're not specifying, iterating through and drawing all the lines that need to be drawn within your paintComponent method. The way to solve this is via one of two ways:
Either create a List<Line2D> such as an ArrayList<Line2D>, fill it in your MouseListener/MouseMotionListener code, and then iterate through this List in your paintComponent method, drawing each line. If you do this, then your clear button's action would be to simply clear the List via clear() and call repaint(). No need for a boolean.
Or you could draw your lines onto a BufferedImage, and then draw the BufferedImage in your paintComponent method via the g.drawImage(...) method. If you do this, always check that the image is not null before drawing. Then in your mouse listening code, you'd draw to this image. In your clear button action, you'd create a new BufferedImage, or clear the current BufferedImage.
Also get rid of setBackground(...) calls from within paintComponent as they really shouldn't be in there.
For example of use of an ArrayList of lines:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class DrawPanelViaArrayList extends JPanel {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private static final Color LINES_COLOR = Color.black;
private static final Color DRAW_LINE_COLOR = Color.pink;
private static final Stroke STROKE = new BasicStroke(3f);
private List<Line2D> lineList = new ArrayList<>();
private int x1 = 0;
private int y1 = 0;
private int x2 = 0;
private int y2 = 0;
public DrawPanelViaArrayList() {
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
add(new JButton(new ClearAction("Clear")));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// for smooth graphics
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// first draw the temporary line to show the user
// where he's drawing
if (x1 != x2 && y1 != y2) {
g2.setColor(DRAW_LINE_COLOR);
g2.drawLine(x1, y1, x2, y2);
}
// then draw all the lines held in the linesList.
Stroke oldStroke = g2.getStroke();
g2.setColor(LINES_COLOR);
g2.setStroke(STROKE); // draw thicker lines
for (Line2D line2d : lineList) {
g2.draw(line2d);
}
g2.setStroke(oldStroke); // reset stroke
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
x1 = e.getPoint().x;
y1 = e.getPoint().y;
}
#Override
public void mouseReleased(MouseEvent e) {
x2 = e.getPoint().x;
y2 = e.getPoint().y;
Line2D line = new Line2D.Double(x1, y1, x2, y2);
// add line to ArrayList
lineList.add(line);
x1 = x2 = y1 = y2 = 0;
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
x2 = e.getPoint().x;
y2 = e.getPoint().y;
// draw temporary line
repaint();
}
}
private class ClearAction extends AbstractAction {
public ClearAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
lineList.clear();
repaint();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new DrawPanelViaArrayList());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
And what the heck, a BufferedImage version
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class DrawPanelViaBufferedImage extends JPanel {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private static final Color LINES_COLOR = Color.black;
private static final Color DRAW_LINE_COLOR = Color.pink;
public static final Color CLEAR_COLOR = new Color(0, 0, 0, 0);
public static final Stroke STROKE = new BasicStroke(3f);
private int x1 = 0;
private int y1 = 0;
private int x2 = 0;
private int y2 = 0;
private BufferedImage img = new BufferedImage(PREF_W, PREF_W, BufferedImage.TYPE_INT_ARGB);
public DrawPanelViaBufferedImage() {
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
add(new JButton(new ClearAction("Clear")));
// if the GUI is to be re-sizeable, then consider adding a
// ComponentListener here, and resizing the BufferedImage in it
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// for smooth graphics
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// first draw the temporary line to show the user
// where he's drawing
if (x1 != x2 && y1 != y2) {
g2.setColor(DRAW_LINE_COLOR);
g2.drawLine(x1, y1, x2, y2);
}
// then draw the BufferedImage if not null
if (img != null) {
g2.drawImage(img, 0, 0, null);
}
}
// size of our GUI
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
x1 = e.getPoint().x;
y1 = e.getPoint().y;
}
#Override
public void mouseReleased(MouseEvent e) {
x2 = e.getPoint().x;
y2 = e.getPoint().y;
Line2D line = new Line2D.Double(x1, y1, x2, y2);
// draw to the BufferedImage
Graphics2D g2 = img.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(STROKE);
g2.setColor(LINES_COLOR);
g2.draw(line);
g2.dispose();
x1 = x2 = y1 = y2 = 0;
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
x2 = e.getPoint().x;
y2 = e.getPoint().y;
repaint();
}
}
private class ClearAction extends AbstractAction {
public ClearAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
Graphics2D g2 = img.createGraphics();
g2.setBackground(CLEAR_COLOR);
g2.clearRect(0, 0, getWidth(), getHeight());
g2.dispose();
repaint();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new DrawPanelViaBufferedImage());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Call JDialog from JDialog

I'm trying to build an application, in which allows calling JDialog from JDialog. I've tried it, but at the time of the call dialog B of A, B dialog appears and then immediately disappears. Is there a solution to these problems?
My code :
I have a class A which extends javax.swing.JDialog. Then there is a label that has the action to call dialog from class PadAndZoom as below:
private void lblSuratRekomendasiMouseClicked(java.awt.event.MouseEvent evt) {
try {
PadAndZoom app = new PadAndZoom();
BufferedImage img = ImageIO.read(PadAndZoom.class.getResource("/tampilan/background5.jpg"));
app.tes(img);
} catch (IOException ex) {
Logger.getLogger(RincianBukuBesar.class.getName()).log(Level.SEVERE, null, ex);
}
}
then I have one more class to be invoked by the method lblSuratRekomendasiMouseClicked (java.awt.event.MouseEvent evt) of class A
package dispertasih;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.*;
public class PadAndZoom implements ChangeListener {
BufferedImage image;
PanPanelX label;
public void stateChanged(ChangeEvent e) {
int value = ((JSlider) e.getSource()).getValue();
double scale = value / 200.0;
BufferedImage scaled = getScaledImage(scale);
label.setImage(scaled);
}
public 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;
}
public PanPanelX getContent() {
// createAnImage();
label = new PanPanelX(image);
//label.setHorizontalAlignment(JLabel.CENTER);
return label;
}
public void createAnImage(BufferedImage imgbuf) {
int w = 500;
int h = 500;
int type = BufferedImage.TYPE_INT_RGB; // many options
image = imgbuf;
}
public JSlider getControl() {
JSlider slider = new JSlider(JSlider.HORIZONTAL, 50, 200, 50);
slider.setMajorTickSpacing(50);
slider.setMinorTickSpacing(10);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.addChangeListener(this);
return slider;
}
public void tes(BufferedImage img) {
PadAndZoom app = new PadAndZoom();
JDialog f = new JDialog();
JButton b = new JButton();
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) { }
app.createAnImage(img);
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.getContentPane().add(new JScrollPane(app.getContent()));
//f.getContentPane().add(new JButton("tessss"));
f.getContentPane().add(app.getControl(), "Last");
f.setSize(400, 400);
f.setLocation(200,200);
f.setVisible(true);
}
}
class PanPanelX extends JPanel {
public int x, y;
public int width = 800, height = 800;
BufferedImage img;
public final static RenderingHints textRenderHints = new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
public final static RenderingHints imageRenderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
public final static RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
static int startX, startY;
public void setImage(BufferedImage img) {
this.img = img;
revalidate();
repaint();
}
public PanPanelX(BufferedImage img) {
x = 20;
y = 20;
this.img = img;
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent me) {
super.mousePressed(me);
startX = me.getX();
startY = me.getY();
}
});
addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent me) {
super.mouseDragged(me);
if (me.getX() < startX) {//moving image to right
x -= 2;
} else if (me.getX() > startX) {//moving image to left
x += 2;
}
if (me.getY() < startY) {//moving image up
y -= 2;
} else if (me.getY() > startY) {//moving image to down
y += 2;
}
repaint();
}
});
}
#Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
Graphics2D g2d = (Graphics2D) grphcs;
//turn on some nice effects
applyRenderHints(g2d);
g2d.drawImage(img, x, y, null);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
public static void applyRenderHints(Graphics2D g2d) {
g2d.setRenderingHints(textRenderHints);
g2d.setRenderingHints(imageRenderHints);
g2d.setRenderingHints(renderHints);
}
}
thanks u ..

Minimal way to make a cleanable drawing area

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();
}
});
}
}

Categories

Resources