绘制一个在下一个油漆中不会消失的矩形

我试图创建一个绘制矩形的JPanel。 小组需要绘制很多矩形,但它们不会移动。 我的问题的一个解决方案是创建一个包含我已经创建的所有矩形的列表,并在每次调用“Paint”时绘制它们。 但是有很多矩形,它会减慢计算机的速度。
我也尝试使用重绘(x,y,高度,宽度)来掠夺新矩形的空间,但它不起作用。 (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); } 

}

  1. 不要覆盖paint没有非常,很好的理由……使用paintComponent代替
  2. 总是调用super.paintXxx ,这些方法在后台做了很多,没有调用super只会回来困扰你。
  3. 如果您使用多个窗格作为矩形,请使MyPanel透明。

油漆是无国籍的。 最后一个油漆和下一个油漆之间没有任何联系。 在每个绘制请求中,您都需要更新整个状态。

安德鲁建议的双缓冲(或后缓冲)是非常好的,我强烈建议你看一下它的实现。

与此同时,我把这个小例子放在一起……

在此处输入图像描述

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

我没有任何问题得到了1000个rects,能够调整窗口大小没有发出或明显减慢…

 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); } } } 

有一个去,很有趣;)

ps-在我注意到减速之前,我达到了超过5000个矩形(我将代码修改为10毫秒延迟并且每个滴答添加10个新矩形)

从这种方法开始 – 基于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 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); } } 

这个来源非常不完整。

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