I'm trying to create an interface where the user can change the color of a line to mark what is background or what is foreground of an image. So far I have coded this:
private class ImageLine extends JComponent
{
java.awt.Point p1,p2;
BufferedImage show;
ArrayList <Shape> shapes = new ArrayList<Shape>();
int flag = 0;
Color color = Color.ORANGE;
public ImageLine(BufferedImage img)
{
show = img;
setPreferredSize(new Dimension(img.getWidth(), img.getHeight()));
this.addMouseListener
(
new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent e)
{
p1 = e.getPoint();
}
@Override
public void mouseReleased(MouseEvent e)
{
p2 = e.getPoint();
Shape r = createLine(p1.x,p1.y,e.getX(),e.getY());
shapes.add(r);
repaint();
}
@Override
public void mouseDragged(MouseEvent e)
{
mouseReleased(e);
repaint();
}
}
);
this.addKeyListener(
new KeyAdapter()
{
@Override
public void keyPressed(KeyEvent e)
{
if(e.getKeyChar() == 'b')
{
color = Color.GREEN;
System.out.println("bck");
}
if(e.getKeyChar() == 'f')
{
color = Color.RED;
System.out.println("fgr");
}
}
}
);
this.setFocusable(true);
}
private Line2D.Float createLine(int x1, int y1, int x2, int y2)
{
return new Line2D.Float(x1,y1 ,x2, y2);
}
Until this part everything works fine , my real problem comes when I try to override the paintComponent() method, here actually I dont know exactly how to set the color as the keylistener indicates, in this case if the user press the "b" key the color of the line has to change to green, in the other hand if the user press the "f" key the color of the line has to change to red, also if the user draws differents lines , these lines have to remain shown. I have tried with this code without sucess:
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(10));
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.50f));
for (Shape s : shapes) {
//g2.setPaint(Color.BLACK);
g2.draw(s);
g2.setPaint(color);
//g2.fill(s);
}
if (p1 != null && p2 != null) {
g2.setPaint(Color.CYAN);
Shape r = createLine(p1.x, p1.y, p2.x, p2.y);
g2.draw(r);
}
}
But the result is not what I want, I paint the lines and change the color, but when this happen , the lines I drew before change it´s color automatically to the color selected, and they dont keep it's "original color". Any sugestions? Thanks in advance.
There are a few ways you might be able to achieve this, I kind of like the idea of marrying the Shape
and Color
together into a single object, but this might present more work as you add more shapes.
Another solution might be to use a Map
to simply map the line to a color, for example
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.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DrawLines {
public static void main(String[] args) {
new DrawLines();
}
public DrawLines() {
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 Line2D currentLine;
private Map<Shape, Color> mapColors;
private Color currentColor;
private List<Shape> shapes;
public TestPane() {
mapColors = new HashMap<>(25);
shapes = new ArrayList<>(25);
InputMap inputMap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getActionMap();
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_F, 0), "foreground");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_B, 0), "background");
actionMap.put("foreground", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
currentColor = Color.GREEN;
if (currentLine != null) {
mapColors.put(currentLine, currentColor);
repaint();
}
}
});
actionMap.put("background", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
currentColor = Color.RED;
if (currentLine != null) {
mapColors.put(currentLine, currentColor);
repaint();
}
}
});
MouseAdapter ma = new MouseAdapter() {
private Point p1, p2;
@Override
public void mousePressed(MouseEvent e) {
p1 = e.getPoint();
currentLine = null;
}
@Override
public void mouseReleased(MouseEvent e) {
p2 = e.getPoint();
if (currentLine == null) {
currentLine = createLine(p1.x, p1.y, e.getX(), e.getY());
} else {
currentLine.setLine(p1, p2);
}
mapColors.put(currentLine, currentColor);
shapes.add(currentLine);
repaint();
}
@Override
public void mouseDragged(MouseEvent e) {
p2 = e.getPoint();
if (currentLine == null) {
currentLine = createLine(p1.x, p1.y, e.getX(), e.getY());
} else {
currentLine.setLine(p1, p2);
}
repaint();
}
private Line2D.Float createLine(int x1, int y1, int x2, int y2) {
return new Line2D.Float(x1, y1, x2, y2);
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (Shape shape : shapes) {
Color color = mapColors.get(shape);
if (color == null) {
color = Color.BLACK;
}
g2d.setColor(color);
g2d.draw(shape);
}
if (currentLine != null) {
Color color = mapColors.get(currentLine);
if (color == null) {
color = currentColor;
}
g2d.setColor(color);
g2d.draw(currentLine);
}
g2d.dispose();
}
}
}
Also, I avoid using KeyListener
and use the key bindings API instead, it's less troublesome
See How to Use Key Bindings for more details