2009-08-06 5 views
9

Ich muss eine Linie mit java.awt.Graphics zeichnen, aber nur der Teil der Linie, die außerhalb eines Rechtecks ​​liegt, sollte gerendert werden.Innenausschnitt mit Java Graphics

Ist es möglich, die Grafik-Clipping-Unterstützung zu verwenden, oder muss ich die Schnittmenge berechnen und die Linie selbst schneiden?

Antwort

10

Sie müssen die Klasse Area verwenden. In diesem Beispiel wird gezeigt, wie Sie vorgehen müssen:

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.geom.Area; 
import java.awt.geom.Rectangle2D; 

import javax.swing.JFrame; 
import javax.swing.JPanel; 


public class Test extends JPanel { 

    public static void main(String[] args) { 
     JFrame f = new JFrame(); 
     Test t = new Test(); 
     f.getContentPane().setLayout(new BorderLayout()); 
     f.getContentPane().add(t,BorderLayout.CENTER); 
     f.pack(); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.setVisible(true); 
    } 

    public Test() { 
     setPreferredSize(new Dimension(300, 300)); 
    } 

    public void paintComponent(Graphics g) { 
     Graphics2D g2 = (Graphics2D)g.create(); 
     Rectangle2D rectangleNotToDrawIn = new Rectangle2D.Double(100, 100, 20, 30); 
     Area outside = calculateRectOutside(rectangleNotToDrawIn); 
     g2.setPaint(Color.white); 
     g2.fillRect(0, 0, getWidth(), getHeight()); 
     g2.setPaint(Color.black); 
     g2.setClip(outside); 
     g2.drawLine(0, 0, getWidth(), getHeight()); 

    } 


    private Area calculateRectOutside(Rectangle2D r) { 
     Area outside = new Area(new Rectangle2D.Double(0, 0, getWidth(), getHeight())); 
     outside.subtract(new Area(r)); 
     return outside; 
    } 

} 
+0

Danke, perfekt! – tuler

+1

+1 - viel besser als meins :) – banjollity

+0

Die Area-Methode ist besser in Bezug auf Lesbarkeit und Erweiterbarkeit (Sie können eine beliebige Form und Clip nach außen), aber ich denke, es könnte einige Leistungsprobleme (die Area-Klasse ist ein bisschen über die Spitze vielleicht). Sie sollten es benchmarken, wenn Sie mehrmals auf den Clip zeichnen müssen, um zu sehen, ob die andere Methode schneller ist. –

3

Sie können dies mit einem AWT-Clip tun. Sie müssen die Grenzen des auszuschließenden Rechtecks ​​und die äußeren Grenzen des Zeichenbereichs kennen.

Der folgende Democode öffnet einen Frame und zeigt ein einzelnes Panel an. Die Malmethode des Bedienfelds erstellt einen Beispielclip, der wie ein Rechteck mit einem rechteckigen Loch in der Mitte aussieht. In Wirklichkeit ist es ein Polygon, das den Bereich um den Bereich beschreibt, den wir ausschließen möchten. Das Clip-Rechteck sollte aus den Grenzen des ausgeschlossenen Rechtecks ​​und dem äußeren Rand des Zeichenbereichs bestehen, aber ich habe hartcodierte Werte eingegeben, um es einfach zu halten und die Funktionsweise besser zu veranschaulichen (hoffe ich!)

 
+-------------------+ 
| clip drawing area | 
+---+-----------+ | 
| | excluded | | 
| | area | | 
| +-----------+ | 
|     | 
+-------------------+ 

Diese Methode hat den Vorteil, dass die Linienkreuzung manuell berechnet wird, indem verhindert wird, dass alle AWT-Zeichnungen in den ausgeschlossenen Bereich gelangen. Ich weiß nicht, ob das für dich nützlich ist oder nicht.

Meine Demo malt dann ein schwarzes Rechteck über die gesamte Fläche, und eine einzelne weiße diagonale Linie durchläuft es, um den Clip zu veranschaulichen.

public class StackOverflow extends JFrame { 
    public static void main(String[] args) { 
     new StackOverflow(); 
    } 

    private StackOverflow() { 
     setTitle("Clip with a hole"); 
     setSize(320,300); 
     getContentPane().add(new ClipPanel()); 
     setVisible(true); 
    } 
} 

class ClipPanel extends JPanel { 
    @Override 
    public void paintComponent(Graphics g) { 
     super.paintComponent(g); 

     Polygon clip = new Polygon(
       new int[]{ 0, 100, 100, 0, 0, 20, 20, 80, 80, 0 }, 
       new int[]{ 0, 0, 60, 60, 20, 20, 40, 40, 20, 20 }, 
       10 
      ); 
     g.setClip(clip); 
     g.setColor(Color.BLACK); 
     g.fillRect(0,0,100,60); 
     g.setColor(Color.WHITE); 
     g.drawLine(0,0,100,60); 
    } 
} 
+0

Auch korrekt. Aber die andere ist einfacher, weil die Verwendung subtrahiert. Vielen Dank. – tuler

+0

Ja, Savvas Dalkitsis 'Antwort ist viel besser. – banjollity

+0

+1. Diese Antwort funktioniert fast und verwendet APIs, die von J2ME PP unterstützt werden. Ich fand, dass ich die Form bei 0,20 anfangen musste, um ein geschlossenes Polygon zu schaffen. Der komplette Arbeitscode steht in meiner Frage: http://stackoverflow.com/questions/1273688/is-there-any-way-to-have-an-inverted-clip-region-for-painting-in-java –