简体   繁体   English

如何在JComponent上永久绘制

[英]How to paint permanently on JComponent

I'm trying to create a paint application in Java. 我正在尝试用Java创建绘画应用程序。

  • I have a "canvas" class which extends JComponent. 我有一个扩展JComponent的“画布”类。
  • I have an ArrayList of type Shape which holds all the shapes of the entire drawing. 我有一个Shape类型的ArrayList,其中包含整个图形的所有形状。

Inside the paintComponent() method: 在paintComponent()方法内部:

  • Each loop everything gets cleared 每个循环都会清除所有内容
  • Every Shape inside the ArrayList gets painted with either g.draw() or g.fill() ArrayList内部的每个Shape都用g.draw()或g.fill()绘制
  • If I want to add a shape or draw a Shape, I add it to the ArrayList. 如果要添加形状或绘制形状,请将其添加到ArrayList中。

The problem is that after a considerably high amount of shapes inside the ArrayList, the execution of the paintComponent() method slows. 问题在于,在ArrayList内出现大量形状之后,paintComponent()方法的执行会变慢。

For example a custom brush. 例如自定义画笔。

  • When dragging the brush over the canvas I have to add a new Shape of type "CustomBrush extends Shape" to the ArrayList 将画笔拖到画布上时,我必须向ArrayList添加类型为“ CustomBrush extended Shape”的新Shape
  • So with just a single stroke I end up with hundreds of shapes in the ArrayList 因此,仅需一次笔划,我在ArrayList中就得到了数百种形状

The question is: 问题是:

  • How do I "pack" say 100 Shape objects into one, so that a single brush stroke becomes one single object in my ArrayList ? 如何将100个Shape对象打包为一个,以便单个画笔笔触成为ArrayList中的单个对象?
  • The ultimate goal is however to speed up the paintComponent() method so that it paints all the drawn Shapes faster. 但是,最终目标是加快paintComponent()方法,以便更快地绘制所有绘制的Shapes。

Thank You! 谢谢!

Here's a sample code: 这是一个示例代码:

public class GraphicPanel extends JComponent{
  private ArrayList<Shape> shapeBuffer;

  public void paintComponent( Graphics gPlain ){
       Graphics2D g = (Graphics2D)gPlain;
       for( Shape s : shapeBuffer ){
        if( filled.next() ){
            g.fill( s );
        }
        else{
            g.draw( s );
        }
  }
}

Paint the background to a BufferedImage, and then draw the BufferedImage to your GrahpicPanel within the paintComponent(...) method using g.drawImage(...) . 将背景绘制为BufferedImage,然后使用g.drawImage(...)将BufferedImage绘制到paintComponent(...)方法内的GrahpicPanel上。 You get the BufferedImage's Graphics context by calling getGraphics() or createGraphics() (for a Graphics2D object). 您可以通过调用getGraphics()createGraphics() (对于Graphics2D对象)来获得BufferedImage的Graphics上下文。 Don't forget to dispose of the Graphics object obtained in this way (but never dispose of a Graphics object given to you by the JVM). 不要忘记处理以这种方式获得的Graphics对象(但不要处理JVM给您的Graphics对象)。

Also, don't forget to call the super.paintComponent(g) in your override! 另外,不要忘记在覆盖中调用super.paintComponent(g)

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.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.Random;

import javax.swing.*;

public class MyPaint extends JComponent {
   private static final int PREF_W = 600;
   private static final int PREF_H = PREF_W;
   private static final Stroke STROKE = new BasicStroke(4f);
   private static final Color[] COLORS = { Color.RED, Color.GREEN,
         Color.yellow, Color.orange, Color.blue, Color.cyan };
   private BufferedImage img = new BufferedImage(PREF_W, PREF_H,
         BufferedImage.TYPE_INT_ARGB);
   private Rectangle rect = null;

   public MyPaint() {
      MyMouse myMouse = new MyMouse();
      addMouseListener(myMouse);
      addMouseMotionListener(myMouse);
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (img != null) {
         g.drawImage(img, 0, 0, null);
      }
      if (rect != null) {
         g.setColor(Color.LIGHT_GRAY);
         ((Graphics2D) g).draw(rect);
      }
   }

   @Override
   public Dimension getPreferredSize() {
      if (isPreferredSizeSet()) {
         return super.getPreferredSize();
      }
      return new Dimension(PREF_W, PREF_H);
   }

   private class MyMouse extends MouseAdapter {
      private Random random = new Random();
      private Point p;

      @Override
      public void mousePressed(MouseEvent e) {
         if (e.getButton() != MouseEvent.BUTTON1) {
            return;
         }
         p = e.getPoint();
      }

      @Override
      public void mouseReleased(MouseEvent e) {
         if (p != null) {
            Rectangle rect2 = createRect(e.getPoint());
            Graphics2D g2 = img.createGraphics();
            g2.setStroke(STROKE);
            Color c = COLORS[random.nextInt(COLORS.length)];
            g2.setColor(c);
            g2.fill(rect2);
            g2.setColor(c.darker());
            g2.draw(rect2);
            g2.dispose();
         }

         p = null;
         rect = null;
         repaint();
      }

      @Override
      public void mouseDragged(MouseEvent e) {
         rect = createRect(e.getPoint());
         repaint();
      }

      private Rectangle createRect(Point p2) {
         int x = Math.min(p.x, p2.x);
         int y = Math.min(p.y, p2.y);
         int width = Math.abs(p.x - p2.x);
         int height = Math.abs(p.y - p2.y);
         Rectangle rect2 = new Rectangle(x, y, width, height);
         return rect2;
      }

   }

   private static void createAndShowGui() {
      MyPaint mainPanel = new MyPaint();

      JFrame frame = new JFrame("MyPaint");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.setResizable(false);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

Brushstroke and color are attributes of a shape. 笔触和颜色是形状的属性。 You could define your own shape class like this. 您可以像这样定义自己的形状类。 That way, you're maintaining shapes in your List. 这样,您就可以在列表中维护形状。

package com.ggl.testing;

import java.awt.Color;
import java.awt.Shape;

public class MyShape {

    private int brushSize;

    private Color interiorColor;

    private Shape shape;

    public MyShape() {
        this.brushSize = 1;
        this.interiorColor = Color.blue;
    }

    public MyShape(int brushSize, Color interiorColor, Shape shape) {
        this.brushSize = brushSize;
        this.interiorColor = interiorColor;
        this.shape = shape;
    }

    public int getBrushSize() {
        return brushSize;
    }

    public void setBrushSize(int brushSize) {
        this.brushSize = brushSize;
    }

    public Color getInteriorColor() {
        return interiorColor;
    }

    public void setInteriorColor(Color interiorColor) {
        this.interiorColor = interiorColor;
    }

    public Shape getShape() {
        return shape;
    }

    public void setShape(Shape shape) {
        this.shape = shape;
    }

}

If I missed any attributes, feel free to add them to your shape class. 如果我错过了任何属性,请随时将它们添加到形状类中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM