M
M
Mimocodil2021-04-09 15:03:58
Java
Mimocodil, 2021-04-09 15:03:58

Is the swing library suitable to reproduce MS Paint (win7)?

Hello! At the moment, only a round brush is implemented and the ability to adjust its size, color and transparency, as well as the canvas cleaning function. Tools in one JFrame, canvas in another.
I want everything to be like in paint - in one window and look the same. So far the only way I can do this is to draw the entire screen pixel by pixel. But not sure if this is a good approach.
I also have another problem: the faster I move the mouse over the canvas, the more the resulting line breaks. Can this be solved somehow?
PS. I'm not specifically tied to swing, I just haven't even touched other ui frameworks yet. But if there is a better option, I will use it.

Illustration
6070417aaf354039071523.png


Paint.java
package paint;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;

import javax.swing.*;
import javax.swing.event.*;

public class Paint {

  private JFrame frame1, frame2;
  private JPanel panel1;
  private JSlider sl_red, sl_green, sl_blue, sl_size, sl_transparency;
  private JButton btn_clear;
  private Color color;

  private PaintData paintdata;

  private PaintPanel panel2;
  private PaintActionListener actionListener;
  private PaintChangeListener listener;
  private PaintMouseListener mouseListener;
  private PaintMouseMotionListener mouseMotionListener;

  public Paint() {
    initBrushesPanel();
    setBrushesAttributes();

    initDrawingPanel();
    setDrawingAttributes();
  }

  public void initBrushesPanel() {
    frame1 = new JFrame();
    panel1 = new JPanel();

    listener = new PaintChangeListener();
    actionListener = new PaintActionListener();

    sl_red = new JSlider(0, 255);
    sl_green = new JSlider(0, 255);
    sl_blue = new JSlider(0, 255);
    sl_size = new JSlider(0, 100);
    sl_transparency = new JSlider(0, 100);

    btn_clear = new JButton("Clear");
  }

  private void initSlider(JSlider js, ChangeListener cl, String title, int ticksSparcing, int val) {
    js.addChangeListener(cl);
    js.setBorder(BorderFactory.createTitledBorder(title));
    js.setMajorTickSpacing(ticksSparcing);
    js.setValue(val);
    js.setPaintTicks(true);
    js.setPaintLabels(true);
    panel1.add(js);
  }

  public void setBrushesAttributes() {
    initSlider(sl_red, listener, "Red", 50, 0);
    initSlider(sl_green, listener, "Green", 50, 0);
    initSlider(sl_blue, listener, "Blue", 50, 0);

    initSlider(sl_size, listener, "Size", 25, 5);
    initSlider(sl_transparency, listener, "Transparency", 25, 100);

    btn_clear.addActionListener(actionListener);
    panel1.add(btn_clear);

    frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame1.setSize(220, 600);
    frame1.setResizable(false);
    frame1.add(panel1);
    frame1.setVisible(true);
  }

  public void initDrawingPanel() {
    mouseListener = new PaintMouseListener();
    mouseMotionListener = new PaintMouseMotionListener();

    paintdata = new PaintData();

    frame2 = new JFrame();
    panel2 = new PaintPanel();
  }

  public void setDrawingAttributes() {
    panel2.addMouseListener(mouseListener);
    panel2.addMouseMotionListener(mouseMotionListener);

    frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame2.setLocation(285, 0);
    frame2.setSize(800, 600);
    frame2.setResizable(false);
    frame2.add(panel2);
    frame2.setVisible(true);
  }

  private class PaintActionListener implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
      if (e.getSource() == btn_clear) {
        paintdata.reset();
        panel2.repaint();
      }
    }
  }

  private class PaintMouseListener implements MouseListener {
    @Override
    public void mouseClicked(MouseEvent e) {
      if (e.getSource() == panel2) {
        int drawX = e.getX() - sl_size.getValue() / 2;
        int drawY = e.getY() - sl_size.getValue() / 2;

        Shape shape = new Ellipse2D.Double(drawX, drawY, sl_size.getValue(), sl_size.getValue());
        paintdata.add(shape, color, sl_transparency.getValue() / 100f);
        panel2.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) {
    }
  }

  private class PaintMouseMotionListener implements MouseMotionListener {
    @Override
    public void mouseDragged(MouseEvent e) {
      if (e.getSource() == panel2) {
        int drawX = e.getX() - sl_size.getValue() / 2;
        int drawY = e.getY() - sl_size.getValue() / 2;

        Shape shape = new Ellipse2D.Double(drawX, drawY, sl_size.getValue(), sl_size.getValue());
        paintdata.add(shape, color, sl_transparency.getValue() / 100f);
        panel2.repaint();
      }
    }

    @Override
    public void mouseMoved(MouseEvent e) {
    }

  }

  private class PaintChangeListener implements ChangeListener {
    @Override
    public void stateChanged(ChangeEvent e) {
      if (e.getSource() == sl_red || e.getSource() == sl_green || e.getSource() == sl_blue) {
        color = new Color(sl_red.getValue(), sl_green.getValue(), sl_blue.getValue());
        panel1.setBackground(color);
      }
    }
  }

  private class PaintPanel extends JPanel {
    public void paintComponent(Graphics gr) {
      Graphics2D g = (Graphics2D) gr;

      g.setColor(Color.WHITE);
      g.fillRect(0, 0, 800, 600);

      for (int i = 0; i < paintdata.size(); i++) {
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, paintdata.getTransparency(i)));
        g.setColor(paintdata.getColor(i));
        g.fill(paintdata.getShape(i));
      }
    }
  }
  
  public static void main(String[] args) {
    new Paint();
  }
}


PaintData.java
package paint;

import java.awt.*;
import java.util.ArrayList;

public class PaintData {

  private ArrayList<Shape> shapes;
  private ArrayList<Color> colors;
  private ArrayList<Float> transp;

  public PaintData() {
    shapes = new ArrayList<Shape>();
    colors = new ArrayList<Color>();
    transp = new ArrayList<Float>();
  }

  public void add(Shape shape, Color color, Float transparency) {
    shapes.add(shape);
    colors.add(color);
    transp.add(transparency);
  }

  public Shape getShape(int index) {
    return shapes.get(index);
  }

  public Color getColor(int index) {
    return colors.get(index);
  }

  public Float getTransparency(int index) {
    return transp.get(index);
  }

  public void reset() {
    shapes.clear();
    colors.clear();
    transp.clear();
  }
  
  public int size() {
    return shapes.size();
  }
}

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question