Dibujando un rectángulo que no desaparecerá en la próxima pintura

Estoy tratando de crear un JPanel que dibuje rectangularjs. El Panel necesita dibujar muchos rectangularjs, pero no se mueven. Una solución a mi problema fue crear una lista con todos los rectangularjs que ya he creado y dibujarlos todos en cada llamada de “Paint”. Pero hay muchos rectangularjs y ralentiza la computadora.
También traté de usar repintado (x, y, alto, ancho) para crear exactamente el espacio del nuevo rectángulo, pero no funcionó. (JPanel sigue borrando rectangularjs previos). En orden, necesito dibujar rectangularjs que no desaparezcan en cada pintura. O un método de pintura que no borrará los sorteos anteriores, o no pintará el fondo. Eso es parte de mi clase 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); } 

}

  1. No anule la paint SIN MUY, muy buena razón … use paintComponent en paintComponent lugar
  2. Siempre llame a super.paintXxx , estos métodos hacen mucho en segundo plano, no llamar a super solo va a volver y perseguirlo.
  3. Si está utilizando varios paneles como rectangularjs, haga que MyPanel transparente.

Las pinturas son sin estado. No hay conexión entre la última pintura y la siguiente. En cada solicitud de pintura, se espera que actualice todo el estado.

La sugerencia de Andrew de doble buffering (o buffering posterior) es excelente, y le recomiendo que eche un vistazo y lo implemente.

Mientras tanto, puse este pequeño ejemplo juntos …

enter image description here

Básicamente, mantienes presionado el botón del mouse y agregará aleatoriamente otro rectángulo al panel cada 40 milisegundos (aproximadamente 25 fotogtwigs por segundo).

Conseguí esto hasta 1000 rects sin ningún problema, pude cambiar el tamaño de la ventana sin y emitir o obviamente ralentizar …

 public class MyPanel extends JPanel { private List lstShapes; private Timer populate; public MyPanel() { lstShapes = new ArrayList(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); } } } 

ir, es divertido;)

ps- Llegué a más de 5000 rectangularjs antes de notar una desaceleración (modifiqué el código a una demora de 10 milisegundos y estaba agregando 10 rectangularjs nuevos por tic)

Comience con este enfoque, basado en una BufferedImage como superficie de pintura.

Aplicación básica de pintura.

 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 hintsMap = new HashMap(); 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); } } 

Esta fuente es muy desigual.

  • Tiene muchas partes con // TODO
  • Se declara dirty atributo dirty pero nunca se usa de manera significativa. ..