【问题标题】:Drawing a rectangle that won't disappear in next paint绘制一个不会在下一次绘画中消失的矩形
【发布时间】:2012-09-22 21:47:06
【问题描述】:

我试图创建一个绘制矩形的 JPanel。面板需要绘制很多矩形,但它们不会移动。 我的问题的一个解决方案是创建一个包含我已经创建的所有矩形的列表,并在每次调用“Paint”时将它们全部绘制出来。但是有很多矩形,它会降低计算机的速度。
我还尝试使用 repaint(x, y, height, width) 来绘制新矩形的空间,但它不起作用。 (JPanel 不断擦除以前的矩形。) 总的来说,我需要绘制不会消失的矩形。或者一种不会擦除以前绘制的绘制方法,或者不会绘制背景。 这是我的 JPanel 课程的一部分:

class MyPanel extends JPanel{
  private int x, y, size;
  private Color c;
  public void DrawRect(int x, int y, int size, Color c){
      this.x = x;
      this.y = y;
      this.size = size;
      this.c = c;
      repaint();
  }
  @Override
    public void
    paint(Graphics g) {

        g.setColor(c);
      g.fillRect(x, y, size, size);
    }

}

【问题讨论】:

    标签: java swing graphics jpanel paint


    【解决方案1】:

    从这种方法开始 - 基于 BufferedImage 作为绘画表面..

    import java.awt.*;
    import java.awt.RenderingHints.Key;
    import java.awt.event.*;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    
    import javax.imageio.ImageIO;
    import javax.swing.*;
    import javax.swing.border.*;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.ChangeListener;
    import javax.swing.filechooser.FileFilter;
    import javax.swing.filechooser.FileNameExtensionFilter;
    
    public class BasicPaint {
    
        /** Reference to the original image. */
        private BufferedImage originalImage;
        /** Image used to make changes. */
        private BufferedImage canvasImage;
        /** The main GUI that might be added to a frame or applet. */
        private JPanel gui;
        /** The color to use when calling clear, text or other 
         * drawing functionality. */
        private Color color = Color.WHITE;
        /** General user messages. */
        private JLabel output = new JLabel("You DooDoodle!");
    
        private BufferedImage colorSample = new BufferedImage(
                16,16,BufferedImage.TYPE_INT_RGB);
        private JLabel imageLabel;
        private int activeTool;
        public static final int SELECTION_TOOL = 0;
        public static final int DRAW_TOOL = 1;
        public static final int TEXT_TOOL = 2;
    
        private Point selectionStart; 
        private Rectangle selection;
        private boolean dirty = false;
        private Stroke stroke = new BasicStroke(
                3,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND,1.7f);
        private RenderingHints renderingHints;
    
        public JComponent getGui() {
            if (gui==null) {
                Map<Key, Object> hintsMap = new HashMap<RenderingHints.Key,Object>();
                hintsMap.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                hintsMap.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
                hintsMap.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
                renderingHints = new RenderingHints(hintsMap); 
    
                setImage(new BufferedImage(320,240,BufferedImage.TYPE_INT_RGB));
                gui = new JPanel(new BorderLayout(4,4));
                gui.setBorder(new EmptyBorder(5,3,5,3));
    
                JPanel imageView = new JPanel(new GridBagLayout());
                imageView.setPreferredSize(new Dimension(480,320));
                imageLabel = new JLabel(new ImageIcon(canvasImage));
                JScrollPane imageScroll = new JScrollPane(imageView);
                imageView.add(imageLabel);
                imageLabel.addMouseMotionListener(new ImageMouseMotionListener());
                imageLabel.addMouseListener(new ImageMouseListener());
                gui.add(imageScroll,BorderLayout.CENTER);
    
                JToolBar tb = new JToolBar();
                tb.setFloatable(false);
                JButton colorButton = new JButton("Color");
                colorButton.setMnemonic('o');
                colorButton.setToolTipText("Choose a Color");
                ActionListener colorListener = new ActionListener() {
                    public void actionPerformed(ActionEvent arg0) {
                        Color c = JColorChooser.showDialog(
                                gui, "Choose a color", color);
                        if (c!=null) {
                            setColor(c);
                        }
                    }
                };
                colorButton.addActionListener(colorListener);
                colorButton.setIcon(new ImageIcon(colorSample));
                tb.add(colorButton);
    
                setColor(color);
    
                final SpinnerNumberModel strokeModel = 
                        new SpinnerNumberModel(3,1,16,1);
                JSpinner strokeSize = new JSpinner(strokeModel);
                ChangeListener strokeListener = new ChangeListener() {
                    @Override
                    public void stateChanged(ChangeEvent arg0) {
                        Object o = strokeModel.getValue();
                        Integer i = (Integer)o; 
                        stroke = new BasicStroke(
                                i.intValue(),
                                BasicStroke.CAP_ROUND,
                                BasicStroke.JOIN_ROUND,
                                1.7f);
                    }
                };
                strokeSize.addChangeListener(strokeListener);
                strokeSize.setMaximumSize(strokeSize.getPreferredSize());
                JLabel strokeLabel = new JLabel("Stroke");
                strokeLabel.setLabelFor(strokeSize);
                strokeLabel.setDisplayedMnemonic('t');
                tb.add(strokeLabel);
                tb.add(strokeSize);
    
                tb.addSeparator();
    
                ActionListener clearListener = new ActionListener() {
                    public void actionPerformed(ActionEvent arg0) {
                        int result = JOptionPane.OK_OPTION;
                        if (dirty) {
                            result = JOptionPane.showConfirmDialog(
                                    gui, "Erase the current painting?");
                        }
                        if (result==JOptionPane.OK_OPTION) {
                            clear(canvasImage);
                        }
                    }
                };
                JButton clearButton = new JButton("Clear");
                tb.add(clearButton);
                clearButton.addActionListener(clearListener);
    
                gui.add(tb, BorderLayout.PAGE_START);
    
                JToolBar tools = new JToolBar(JToolBar.VERTICAL);
                tools.setFloatable(false);
                JButton crop = new JButton("Crop");
                final JRadioButton select = new JRadioButton("Select", true);
                final JRadioButton draw = new JRadioButton("Draw");
                final JRadioButton text = new JRadioButton("Text");
    
                tools.add(crop);            
                tools.add(select);          
                tools.add(draw);            
                tools.add(text);
    
                ButtonGroup bg = new ButtonGroup();
                bg.add(select);
                bg.add(text);
                bg.add(draw);
                ActionListener toolGroupListener = new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent ae) {
                        if (ae.getSource()==select) {
                            activeTool = SELECTION_TOOL;
                        } else if (ae.getSource()==draw) {
                            activeTool = DRAW_TOOL;
                        } else if (ae.getSource()==text) {
                            activeTool = TEXT_TOOL;
                        }
                    }
                };
                select.addActionListener(toolGroupListener);
                draw.addActionListener(toolGroupListener);
                text.addActionListener(toolGroupListener);
    
                gui.add(tools, BorderLayout.LINE_END);
    
                gui.add(output,BorderLayout.PAGE_END);
                clear(colorSample);
                clear(canvasImage);
            }
    
            return gui;
        }
    
        /** Clears the entire image area by painting it with the current color. */
        public void clear(BufferedImage bi) {
            Graphics2D g = bi.createGraphics();
            g.setRenderingHints(renderingHints);
            g.setColor(color);
            g.fillRect(0, 0, bi.getWidth(), bi.getHeight());
    
            g.dispose();
            imageLabel.repaint();
        }
    
        public void setImage(BufferedImage image) {
            this.originalImage = image;
            int w = image.getWidth();
            int h = image.getHeight();
            canvasImage = new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
    
            Graphics2D g = this.canvasImage.createGraphics();
            g.setRenderingHints(renderingHints);
            g.drawImage(image, 0, 0, gui);
            g.dispose();
    
            selection = new Rectangle(0,0,w,h); 
            if (this.imageLabel!=null) {
                imageLabel.setIcon(new ImageIcon(canvasImage));
                this.imageLabel.repaint();
            }
            if (gui!=null) {
                gui.invalidate();
            }
        }
    
        /** Set the current painting color and refresh any elements needed. */
        public void setColor(Color color) {
            this.color = color;
            clear(colorSample);
        }
    
        private JMenu getFileMenu(boolean webstart){
            JMenu file = new JMenu("File");
            file.setMnemonic('f');
    
            JMenuItem newImageItem = new JMenuItem("New");
            newImageItem.setMnemonic('n');
            ActionListener newImage = new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    BufferedImage bi = new BufferedImage(
                            360, 300, BufferedImage.TYPE_INT_ARGB);
                    clear(bi);
                    setImage(bi);
                }
            };
            newImageItem.addActionListener(newImage);
            file.add(newImageItem);
    
            if (webstart) {
                //TODO Add open/save functionality using JNLP API
            } else {
                //TODO Add save functionality using J2SE API
                file.addSeparator();
                ActionListener openListener = new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent arg0) {
                        if (!dirty) {
                            JFileChooser ch = getFileChooser();
                            int result = ch.showOpenDialog(gui);
                            if (result==JFileChooser.APPROVE_OPTION ) {
                                try {
                                    BufferedImage bi = ImageIO.read(
                                            ch.getSelectedFile());
                                    setImage(bi);
                                } catch (IOException e) {
                                    showError(e);
                                    e.printStackTrace();
                                }
                            }
                        } else {
                            // TODO
                            JOptionPane.showMessageDialog(
                                    gui, "TODO - prompt save image..");
                        }
                    }
                };
                JMenuItem openItem = new JMenuItem("Open");
                openItem.setMnemonic('o');
                openItem.addActionListener(openListener);
                file.add(openItem);
    
                ActionListener saveListener = new ActionListener() {
    
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        JFileChooser ch = getFileChooser();
                        int result = ch.showSaveDialog(gui);
                        if (result==JFileChooser.APPROVE_OPTION ) {
                            try {
                                File f = ch.getSelectedFile();
                                ImageIO.write(BasicPaint.this.canvasImage, "png", f);
                                BasicPaint.this.originalImage = BasicPaint.this.canvasImage;
                                dirty = false;
                            } catch (IOException ioe) {
                                showError(ioe);
                                ioe.printStackTrace();
                            }
                        }
                    }
                };
                JMenuItem saveItem = new JMenuItem("Save");
                saveItem.addActionListener(saveListener);
                saveItem.setMnemonic('s');
                file.add(saveItem);
            }
    
            if (canExit()) {
                ActionListener exit = new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent arg0) {
                        // TODO Auto-generated method stub
                        System.exit(0);
                    }
                };
                JMenuItem exitItem = new JMenuItem("Exit");
                exitItem.setMnemonic('x');
                file.addSeparator();
                exitItem.addActionListener(exit);
                file.add(exitItem);
            }
    
            return file;
        }
    
        private void showError(Throwable t) {
            JOptionPane.showMessageDialog(
                    gui, 
                    t.getMessage(), 
                    t.toString(), 
                    JOptionPane.ERROR_MESSAGE);
        }
    
        JFileChooser chooser = null;
    
        public JFileChooser getFileChooser() {
            if (chooser==null) {
                chooser = new JFileChooser();
                FileFilter ff = new FileNameExtensionFilter("Image files", ImageIO.getReaderFileSuffixes());
                chooser.setFileFilter(ff);
            }
            return chooser;
    
        }
    
        public boolean canExit() {
            boolean canExit = false;
            SecurityManager sm = System.getSecurityManager();
            if (sm==null) {
                canExit = true;
            } else {
                try {
                    sm.checkExit(0);
                    canExit = true; 
                } catch(Exception stayFalse) {
                }
            }
    
            return canExit;
        }
    
        public JMenuBar getMenuBar(boolean webstart){
            JMenuBar mb = new JMenuBar();
            mb.add(this.getFileMenu(webstart));
            return mb;
        }
    
        public static void main(String[] args) {
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(
                                UIManager.getSystemLookAndFeelClassName());
                    } catch (Exception e) {
                        // use default
                    }
                    BasicPaint bp = new BasicPaint();
    
                    JFrame f = new JFrame("DooDoodle!");
                    f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                    f.setLocationByPlatform(true);
    
                    f.setContentPane(bp.getGui());
                    f.setJMenuBar(bp.getMenuBar(false));
    
                    f.pack();
                    f.setMinimumSize(f.getSize());
                    f.setVisible(true);
                }
            };
            SwingUtilities.invokeLater(r);
        }
    
        public void text(Point point) {
            String text = JOptionPane.showInputDialog(gui, "Text to add", "Text");
            if (text!=null) {
                Graphics2D g = this.canvasImage.createGraphics();
                g.setRenderingHints(renderingHints);
                g.setColor(this.color);
                g.setStroke(stroke);
                int n = 0;
                g.drawString(text,point.x,point.y);
                g.dispose();
                this.imageLabel.repaint();
            }
        }
    
        public void draw(Point point) {
            Graphics2D g = this.canvasImage.createGraphics();
            g.setRenderingHints(renderingHints);
            g.setColor(this.color);
            g.setStroke(stroke);
            int n = 0;
            g.drawLine(point.x, point.y, point.x+n, point.y+n);
            g.dispose();
            this.imageLabel.repaint();
        }
    
        class ImageMouseListener extends MouseAdapter {
    
            @Override
            public void mousePressed(MouseEvent arg0) {
                // TODO Auto-generated method stub
                if (activeTool==BasicPaint.SELECTION_TOOL) {
                    selectionStart = arg0.getPoint();
                } else if (activeTool==BasicPaint.DRAW_TOOL) {
                    // TODO
                    draw(arg0.getPoint());
                } else if (activeTool==BasicPaint.TEXT_TOOL) {
                    // TODO
                    text(arg0.getPoint());
                } else {
                    JOptionPane.showMessageDialog(
                            gui, 
                            "Application error.  :(", 
                            "Error!", 
                            JOptionPane.ERROR_MESSAGE);
                }
            }
    
            @Override
            public void mouseReleased(MouseEvent arg0) {
                if (activeTool==BasicPaint.SELECTION_TOOL) {
                    selection = new Rectangle(
                            selectionStart.x,
                            selectionStart.y,
                            arg0.getPoint().x,
                            arg0.getPoint().y);
                }
            }
        }
    
        class ImageMouseMotionListener implements MouseMotionListener {
    
            @Override
            public void mouseDragged(MouseEvent arg0) {
                reportPositionAndColor(arg0);
                if (activeTool==BasicPaint.SELECTION_TOOL) {
                    selection = new Rectangle(
                            selectionStart.x,
                            selectionStart.y,
                            arg0.getPoint().x-selectionStart.x,
                            arg0.getPoint().y-selectionStart.y);
                } else if (activeTool==BasicPaint.DRAW_TOOL) {
                    draw(arg0.getPoint());
                }
            }
    
            @Override
            public void mouseMoved(MouseEvent arg0) {
                reportPositionAndColor(arg0);
            }
    
        }
    
        private void reportPositionAndColor(MouseEvent me) {
            String text = "";
            if (activeTool==BasicPaint.SELECTION_TOOL) {
                text += "Selection (X,Y:WxH): " + 
                        (int)selection.getX() +
                        "," +
                        (int)selection.getY() +
                        ":" +
                        (int)selection.getWidth() +
                        "x" +
                        (int)selection.getHeight();
            } else {
                text += "X,Y: " + (me.getPoint().x+1) + "," + (me.getPoint().y+1);
            }
            output.setText(text);
        }
    }
    

    这个来源非常不完整。

    • 它有很多部分带有// TODO
    • dirty 属性已声明,但从未以任何有意义的方式使用。 ..

    【讨论】:

      【解决方案2】:
      1. 不要在没有非常非常好的理由的情况下覆盖paint...改用paintComponent
      2. 总是调用super.paintXxx,这些方法在后台做了很多,不调用super只会回来困扰你。
      3. 如果您将多个窗格用作矩形,请将 MyPanel 设为透明。

      Paint 是无状态的。最后一幅画和下一幅画之间没有联系。在每次绘制请求时,您都应该更新整个状态。

      Andrew 关于双缓冲(或后缓冲)的建议非常好,我强烈建议您看看并实施它。

      同时,我把这个小例子放在一起......

      基本上,您按住鼠标按钮,它会每 40 毫秒(大约每秒 25 帧)随机向面板添加另一个矩形。

      我得到了 1000 个矩形,没有任何问题,能够调整窗口大小而没有问题或明显减慢...

      public class MyPanel extends JPanel {
      
          private List<MyRectangle> lstShapes;
          private Timer populate;
      
          public MyPanel() {
      
              lstShapes = new ArrayList<MyRectangle>(25);
      
              populate = new Timer(40, new ActionListener() {
                  @Override
                  public void actionPerformed(ActionEvent e) {
      
                      int x = (int) (Math.random() * getWidth());
                      int y = (int) (Math.random() * getHeight());
                      int width = (int) (Math.random() * (getWidth() / 4));
                      int height = (int) (Math.random() * (getHeight() / 4));
      
                      if (x + width > getWidth()) {
                          x = getWidth() - width;
                      }
                      if (y + height > getHeight()) {
                          y = getHeight() - height;
                      }
      
                      Color color = new Color(
                              (int) (Math.random() * 255),
                              (int) (Math.random() * 255),
                              (int) (Math.random() * 255));
      
                      lstShapes.add(new MyRectangle(x, y, width, height, color));
                      repaint();
                  }
              });
              populate.setInitialDelay(0);
              populate.setRepeats(true);
              populate.setCoalesce(true);
      
              addMouseListener(new MouseAdapter() {
                  @Override
                  public void mousePressed(MouseEvent e) {
                      populate.restart();
                  }
      
                  @Override
                  public void mouseReleased(MouseEvent e) {
                      populate.stop();
                  }
              });
      
          }
      
          @Override
          protected void paintComponent(Graphics g) {
      
              super.paintComponent(g);
      
              Graphics2D g2d = (Graphics2D) g;
              for (MyRectangle rect : lstShapes) {
                  rect.paint(g2d);
              }
      
              FontMetrics fm = g2d.getFontMetrics();
              String text = Integer.toString(lstShapes.size());
      
              g2d.setColor(getForeground());
              g2d.drawString(text, getWidth() - fm.stringWidth(text), getHeight() - fm.getHeight() + fm.getAscent());
      
          }
      
          public class MyRectangle extends Rectangle {
      
              private Color color;
      
              public MyRectangle(int x, int y, int width, int height, Color color) {
                  super(x, y, width, height);
                  this.color = color;
              }
      
              public Color getColor() {
                  return color;
              }
      
              public void paint(Graphics2D g2d) {
      
                  g2d.setColor(getColor());
                  g2d.fill(this);
      
              }
          }
      }
      

      试一试,很有趣;)

      ps- 在我注意到速度变慢之前,我已经达到了 5000 多个矩形(我将代码修改为 10 毫秒的延迟,并且每个刻度添加了 10 个新矩形)

      【讨论】:

      • @ViniciusTafuriCarvalho 不客气,玩得很开心
      猜你喜欢
      • 1970-01-01
      • 2018-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多