2013-03-09 6 views
5

Ich habe etwas Code, um Rechtecke zu zeichnen. Es wird verwendet, um Rechtecke auf JPanel zu zeichnen, um Grenzen von Widgets zu markieren. Hier der Code zuerst, danach erkläre ich mein Problem cq. Frage.Java Swing - Gültiger Ansatz zum Ziehen von Rechtecken auf ein JPanel?

Zunächst einmal habe ich eine Klasse (WidgetDrawingPanel), die JPanel erweitert.

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 
} 

Nachfolgend finden Sie mich ch viel Referenz sehen. Dies ist ein CoordinateHolder, der Start und aktuelle Koordinaten meiner Mausbewegung enthält.

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

und schließlich die paintComponent(Grapics) Methode. Es gibt eine Schleife durch Widgets, die eigentlich nur bereits gezeichnet sind Rects (x, y, w, h Attribute), aber die ein wenig mehr Informationen, die nicht in der Zeichnung Teil der Anwendung nützlich ist. Jedes Mal, wenn Sie die Maus loslassen, wird die CoordinateHolder in ein Widget konvertiert und zu widgets hinzugefügt.

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

Dieser Code funktioniert, aber ich vermute, dass dieses höchst ineffizient und inperformant ist, als ständig über Code die JPanel auf der Maus per Drag erfrischt, die einmal, sagen wir, alle 10 ms? Ich nehme an, dass es sehr bald langsam wird, besonders wenn der Benutzer eine Menge Rechtecke erstellt (die ebenfalls kontinuierlich neu gezeichnet werden, wie in painComponent(Graphics) zu sehen ist).

Frage cq. Problem

Gibt es eine bessere, weniger Ressourcen verbrauchende Methode, wo der Benutzer Rechtecke reibungslos ziehen kann?

Ich lese eine Antwort auf diese Drag rectangle on JFrame in Java, aber der Autor dieser Antwort scheint es genauso zu tun wie ich. Aber auch das ist unperformant, oder? Oder sollten Computer in der Lage sein, die Komponente kontinuierlich neu zu zeichnen, und ist dies tatsächlich ein gültiger Ansatz?

Antwort

4

Um viele unveränderliche Hintergrundformen anzuzeigen, zeichnen Sie sie zu einem BufferedImage und zeigen Sie dann BufferedImage in der paintComponent(...)-Methode an. Während also eine Form gezeichnet wird, zeichne sie in paintComponent(...), aber sobald die Form gezeichnet ist, vielleicht auf mouseRelease, dann zeichne sie im Hintergrund BufferedImage.

Beachten Sie, dass das, was Ihren aktuellen Zeichnungscode am meisten verlangsamt, Ihre Debug-SOP-Anweisungen sein können, aber ich nehme an, dass diese aus dem fertigen Code entfernt werden.

Zum Beispiel:

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

Danke, werde ich die BufferedImage bald überprüfen, aber es kann eine Weile dauern, weil ich sehr beschäftigt bin. Und deine Annahme ist richtig. – stealthjong

+0

@ChristiaandeJong: siehe Edit für ein [sscce] (http://sscce.org) Beispiel –

+0

Schönes Beispiel. Auch über RDP läuft das reibungslos. Ich denke, ich kann das für meinen Zweck verwenden. – stealthjong

Verwandte Themen