2013-03-09 36 views
5

我有一些代码来绘制矩形。它用于在JPanel上绘制矩形,以标记小部件的边界。这里的代码第一,之后,我会解释我的问题QQ。题。Java Swing - 将矩形拖到JPanel上的有效方法?

首先,我有一个类(WidgetDrawingPanel),它延伸JPanel

public WidgetDrawingPanel(int width, int height) { 
    /*To make things visible at least*/ 
    widgets.add(new Widget(10,10,100,100, WidgetType.TextField)); 
    widgets.add(new Widget(50,50,100,200, WidgetType.TextField)); 
    this.width = width; 
    this.height = height; 
    this.setBackground(Color.BLUE); 
    addListener(); //adds both MouseMotionListener and MouseListener 
} 

下面你会看到我参考ch很多。这是一个CoordinateHolder,它包含我的鼠标移动的开始和当前坐标。

private void addListener() { 
    this.addMouseMotionListener(new MouseMotionListener() { 
     @Override 
     public void mouseDragged(MouseEvent arg0) { 
      ch.currentX = arg0.getX(); 
      ch.currentY = arg0.getY(); 
      System.out.println("dragging " + ch.currentX + ","+ch.currentY); 
      WidgetDrawingPanel.this.repaint(); 
     } 
    }); 
    this.addMouseListener(new MouseListener() { 
     @Override 
     public void mouseReleased(MouseEvent event) { 
      ch.endX = event.getX(); 
      ch.endY = event.getY(); 
      try { 
       checkCoords(); 
      } catch (OutsidePanelException e) { 
       e.printStackTrace(); 
       JOptionPane.showMessageDialog(null, "drawn Outside Panel"); 
      } 
     } 

     @Override 
     public void mousePressed(MouseEvent event) { 
      ch = new CoordinateHolder(event.getX(), event.getY()); 
     } 
    }); 
} 

最后是paintComponent(Grapics)方法。通过Widgets循环,实际上它已经被绘制为Rects(x,y,w,h属性),但是它有更多的信息,这在应用程序的绘图部分中是无用的。每次释放鼠标时,CoordinateHolder都会转换为Widget,并添加到widgets

@Override 
public void paintComponent(Graphics g) { 
    super.paintComponent(g); 
    System.out.println("Paint"); 
    g.setColor(Color.BLUE); 
    g.fillRect(0, 0, width, height); //making the whole panel blue 
    g.setColor(Color.RED); 
    Graphics2D g2 = (Graphics2D)g; 
    g2.setStroke(new BasicStroke(3)); 
    for (Widget w : widgets) { 
     g.drawRect(w.getX(), w.getY(), w.getW(), w.getH()); 
    } 
    if (ch != null) 
     g.drawRect(ch.startX, ch.startY, ch.currentX - ch.startX, ch.currentY - ch.startY); 
} 

此代码工作,但我怀疑这是非常低效和inperformant,如上面的代码将不断刷新上拖动鼠标,这就是讲,每10ms一次JPanel?我猜想它会很快变慢,特别是当用户创建了很多矩形(这也是不断重绘的,如painComponent(Graphics)所示)。

问题cq。问题

是否有更好的,资源消耗较少的方法,用户可以平滑地拖动矩形?

我看到了这个Drag rectangle on JFrame in Java的答案,但这个答案的作者似乎和我一样。但是,再次,这是不正确的,对吗?或者,计算机是否应该能够轻松地重新绘制组件,这实际上是一种有效的方法吗?

回答

4

要显示大量不变的背景形状,请将它们绘制到BufferedImage,然后在paintComponent(...)方法中显示BufferedImage。因此,在绘制形状的同时,将其绘制在paintComponent(...)中,但一旦形状完成绘制后,可能在mouseRelease上,然后在后台绘制BufferedImage。

请注意,什么会减慢您当前的绘图代码最可能是您的调试SOP语句,但我认为这些将从完成的代码中删除。

例如:

import java.awt.*; 
import java.awt.event.*; 
import java.awt.image.BufferedImage; 

import javax.swing.*; 

@SuppressWarnings("serial") 
public class DrawingPanel extends JPanel { 
    private static final int PREF_W = 600; 
    private static final int PREF_H = 400; 
    private static final Color DRAWING_COLOR = new Color(255, 100, 200); 
    private static final Color FINAL_DRAWING_COLOR = Color.red; 

    private BufferedImage backgroundImg; 
    private Point startPt = null; 
    private Point endPt = null; 
    private Point currentPt = null; 

    public DrawingPanel() { 
     backgroundImg = new BufferedImage(PREF_W, PREF_H, 
      BufferedImage.TYPE_INT_ARGB); 
     Graphics g = backgroundImg.getGraphics(); 
     g.setColor(Color.blue); 
     g.fillRect(0, 0, PREF_W, PREF_H); 
     g.dispose(); 

     MyMouseAdapter myMouseAdapter = new MyMouseAdapter(); 
     addMouseMotionListener(myMouseAdapter); 
     addMouseListener(myMouseAdapter); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     if (backgroundImg != null) { 
     g.drawImage(backgroundImg, 0, 0, this); 
     } 

     if (startPt != null && currentPt != null) { 
     g.setColor(DRAWING_COLOR); 
     int x = Math.min(startPt.x, currentPt.x); 
     int y = Math.min(startPt.y, currentPt.y); 
     int width = Math.abs(startPt.x - currentPt.x); 
     int height = Math.abs(startPt.y - currentPt.y); 
     g.drawRect(x, y, width, height); 
     } 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(PREF_W, PREF_H); 
    } 

    public void drawToBackground() { 
     Graphics g = backgroundImg.getGraphics(); 
     g.setColor(FINAL_DRAWING_COLOR); 
     int x = Math.min(startPt.x, endPt.x); 
     int y = Math.min(startPt.y, endPt.y); 
     int width = Math.abs(startPt.x - endPt.x); 
     int height = Math.abs(startPt.y - endPt.y); 
     g.drawRect(x, y, width, height); 
     g.dispose(); 

     startPt = null; 
     repaint(); 
    } 

    private class MyMouseAdapter extends MouseAdapter { 
     @Override 
     public void mouseDragged(MouseEvent mEvt) { 
     currentPt = mEvt.getPoint(); 
     DrawingPanel.this.repaint(); 
     } 

     @Override 
     public void mouseReleased(MouseEvent mEvt) { 
     endPt = mEvt.getPoint(); 
     currentPt = null; 
     drawToBackground(); 
     } 

     @Override 
     public void mousePressed(MouseEvent mEvt) { 
     startPt = mEvt.getPoint(); 
     } 
    } 

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

     JFrame frame = new JFrame("Drawing Panel"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(mainPanel); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 

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

谢谢,我会尽快检查BufferedImage的,但它可能需要一段时间,因为我很忙。你的假设是正确的。 – stealthjong 2013-03-09 15:14:54

+0

@ChristiaandeJong:请参阅编辑[sscce](http://sscce.org)示例 – 2013-03-09 15:33:39

+0

很好的例子。即使通过RDP,这也可以顺利进行。我想我可以用它来达到我的目的。 – stealthjong 2013-03-09 15:53:18