2013-03-09 15 views
5

Ho un po 'di codice per disegnare rettangoli. È usato per disegnare rettangoli su un JPanel, per marcare i confini dei widget. Ecco il codice prima, dopo spiegherò il mio problema cq. domanda.Java Swing: approccio valido per il trascinamento di rettangoli su un JPanel?

Prima di tutto, ho una classe (WidgetDrawingPanel) che si estende 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 
} 

Di seguito vedrete mi riferisco ch molto. Questo è un CoordinateHolder, che contiene le coordinate iniziali e attuali del mio movimento del mouse.

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

e, infine, il metodo paintComponent(Grapics). C'è un loop attraverso Widgets, che in realtà sono già appena disegnati Rects (attributi x, y, w, h), ma che un po 'più di informazioni, che non è utile nella parte del disegno dell'applicazione. Ogni volta che si rilascia il mouse, lo CoordinateHolder viene convertito in un widget e aggiunto a 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); 
} 

Questo codice funziona, ma ho il sospetto questo è altamente inefficiente e inperformant, come sopra il codice aggiorna continuamente l'JPanel il trascinamento del mouse, che è, per esempio, una volta ogni 10 ms? Suppongo che sarà presto molto lento, specialmente quando l'utente crea un diavolo di rettangoli molto (che sono anche ridisegnati continuamente, come visto in painComponent(Graphics)).

Domanda cq. Problema

Esiste un metodo migliore, meno dispendioso in termini di risorse, in cui l'utente può trascinare i rettangoli senza problemi?

Ho letto una risposta a questo Drag rectangle on JFrame in Java, ma l'autore di quella risposta sembra farlo come me. Ma di nuovo, è molto efficace, giusto? O i computer dovrebbero essere facilmente in grado di ridisegnare continuamente il componente, e questo è davvero un approccio valido?

risposta

4

Per mostrare molte forme di sfondo non modificabili, disegnarle su un'immagine con buffer e quindi mostrare BufferedImage nel metodo paintComponent(...). Quindi, mentre viene disegnata una forma, disegnala in paintComponent(...) ma una volta che la forma è stata disegnata, forse su mouseRelease, quindi disegnalo in background BufferedImage.

Nota che ciò che rallenterà maggiormente il tuo codice di disegno corrente potrebbero essere le tue istruzioni SOP di debug, ma presumo che queste verranno rimosse dal codice finito.

Ad esempio:

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

Grazie, vado a controllare il BufferedImage presto, ma si può prendere un po ', perché sono molto occupato. E la tua ipotesi è corretta. – stealthjong

+0

@ChristiaandeJong: vedere la modifica per un esempio [sscce] (http://sscce.org) –

+0

Bel esempio. Anche attraverso RDP questo va liscio. Penso di poter usare questo per il mio scopo. – stealthjong

Problemi correlati