# rechtecke zeichnen anhand von matrix



## Lirave (22. Jan 2010)

Hallo,
kann mir jemand sagen wie ich am besten von:

Ein Array das folgendermaßen gefüllt ist.

3 3 3 1 1 5 5
3 3 3 1 1 5 5
3 3 3 1 1 5 5
4 4 4 2 2 2 2
4 4 4 2 2 2 2
4 4 4 2 2 2 2

   nach

hier komme ?







Habe echt keinen Plan, wie man da ran gehen könnte, und welche Befehle man benötigt.

Also gleiche zahlen bilden zusammen ein rechteck, in dessen Mitte zentriert diese Zahl stehen soll.
Außerdem sollen die Flächen immer anders gefärbt sein.
Also bei wie hier 5 Flächen 5 unterschiedliche Farben, bei 10 Flächen 10 unterschiedliche Farben.

Hoffe ihr könnt mir helfen.
Gruß 
Robert


----------



## LeaveX (22. Jan 2010)

Hallo,

Warum ein Array? nimm einfach mehrere Canvas objekte.

MFG


----------



## Marco13 (22. Jan 2010)

Hm ???:L 

Wie auch immer: Wenn es nur um Rechtecke geht, wäre das wohl nicht so aufwändig. Nur schnell als halb-Pseudocode hingeschrieben

```
List<Rectangle> computeRectangles(int array[][])
{
    List<Rectangle> result = new ArrayList<Rectangle>();
    for (int i=0; i<array.length; i++)
    {
        for (int j=0; j<array[i].length; j++)
        {
            if (array[i][j] != 0) 
            {
                 Rectangle rectangle = computeRectangle(array, i, j);
                 result.add(rectangle);
            }
        }
    }
    return result;
}

Rectangle computeRectangle(int array[][], int i, int j)
{
    // Breite berechnen
    int x = i;
    while (x<array.length && array[x][j]==array[i][j]) x++;
    int w = x-i;

    // Höhe berechnen (analog dazu)
    ...

    // Berechneten Bereich im Array mit 0en füllen
    // (damit man in der Methode oben sieht, dass
    // der Bereich schon abgegrast ist)
    ...

    return new Rectangle(i,j,w,h);
}
```

Damit kreigt man schonmal die Rechtecke in einer Liste.


Die jetzt mit verschiedenen Farben gefüllt zu malen... ja, wie over-engineered soll es sein? Es reichen ja VIER Farben, da kann man jetzt einen GraphColoring-Algorithmus drüberlaufen lassen  Aber ganz hübsch, sinnvoll und recht einfach wäre wahrscheinlich, bei n Rechtecken n Punkte über den Hue des HSB-Farbraumes laufen zu lassen, um die Farben zu bestimmen... Wenn man die als Liste will:

```
List<Color> computeColors(int n)
{
    List<Color> result = new ArrayList<Color>();
    for (int i=0; i<n; i++)
    {
        float hue = (float)i/n;
        Color color = new Color(Color.HSBtoRGB(hue, 1, 1));
        result.add(color);
    }
    return result;
}
```
Das kann man aber auch "on the fly" beim Zeichnen ausrechnen.

Das Zeichnen an sich... ist dann einfach: Man malt einfach mit
g.fill(rectangles.get(i))
alle Rectangles. Wenn sie die Component ausfüllen sollen, muss man sie halt noch skalieren....


----------



## Lirave (26. Jan 2010)

danke die passenden rechtecke habe ich jetzt,

das mit den g.fill bekomme ich nicht hin, welche Klassen muss man da importieren ?

Oder kann jemand ein Beispiel machen, wo er ein Rechteck zeichnet.


----------



## ARadauer (26. Jan 2010)

> welche Klassen muss man da importieren ?


ich würde eine Entwicklungsumgebung wie eclipse benutzen.. das hilft dir imens dabei...


----------



## Lirave (26. Jan 2010)

benutze ich, wenn ich g.fill(rectangle) ausführen will sagt er mir g wird nicht gefunden, und werden auch keine Sachen angeboten die ich importieren muss


----------



## ARadauer (26. Jan 2010)

Lirave hat gesagt.:


> benutze ich, wenn ich g.fill(rectangle) ausführen will sagt er mir g wird nicht gefunden, und werden auch keine Sachen angeboten die ich importieren muss



naja er müsste schon Graphics meckern ... zeig mal deine ganze code


----------



## Lirave (26. Jan 2010)

daran wirds liegen, habe kein grafics

habe noch nie was gezeichnet mit Java, weiß nicht was man dazu braucht, habe derzeit


```
public static List<Rectangle> computeRectangles(int array[][])
	 {
		    List<Rectangle> result = new ArrayList<Rectangle>();
		    for (int i=0; i<array.length; i++)
		    {
		        for (int j=0; j<array[i].length; j++)
		        {
		            if (array[i][j] != 0) 
		            {
		                 Rectangle rectangle = computeRectangle(array, i, j);
		                 result.add(rectangle);
		                 disp(array);
		            }
		        }
		    }
	    
		    return result;
	}
	 
	 public static Rectangle computeRectangle(int array[][], int i, int j)
	 {
		 int Wert = array[i][j];
	     int x = i;
	     while (x<array.length && Wert==array[i][j]) x++;
	     int w = x-i;
	     
	     int y = j;
	     while (y<array[i].length && Wert == array[i][j]) y++;
	     int h = y-j;
	  
	     for (int a=0;a<array.length;a++){
	    	 for (int b=0; b<array[a].length;b++){
	    		 if (Wert == array[a][b]){
	    			 array[a][b] = 0;
	    		 }
	    	 }
	     }
	     return new Rectangle(i,j,w,h);
	 }
```

da wird aus dem oben genannten 2d array eine Liste von rectangle erzeugt.

Ich hatte jetzt einfach probiert g.fill aufzurufen, aber g wird anscheinend ein zu übergebender Parameter sein


----------



## ARadauer (26. Jan 2010)

schau dir das mal an
Java ist auch eine Insel – 14.4 Grundlegendes zum Zeichnen

Ich weiß, es ist irgenwie lästig.. man hat ein kleines Problem und bekommt dann 10-15 Zeiten Anleitung zum durchlesen. Es loht sich aber wirklicih sich diese sachen durchzulesen, da man dann einfach das nötige Hintergrundwissen hat... dann macht die ganze Sache auch viel mehr Spaß..



> int Wert = array_[j];
> _


_ wert! Variablen schreibt man klein..._


----------



## Lirave (26. Jan 2010)

danke dir 
schau ich mir mal durch


----------



## Lirave (26. Jan 2010)

habe jetzt jedenfalls ein Fenster geöffnet, aber wie ich jetzt da drin mehrere Rechtecke zeichnen kann ist mir nicht klar, komme denke ich ohne weitere Hilfe hier nicht weiter.


```
import java.awt.*;
import javax.swing.JFrame;
import java.awt.Graphics;
import javax.swing.*;

public class Frame
{

	
  public static void main( String[] args )
  {
    JFrame   f = new   JFrame  ( "Guillotineschnitt" );
    f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
    f.setSize( 600, 400 );
    Dimension d = Toolkit.getDefaultToolkit().  getScreenSize()  ;
    f.setLocation( (d.width - f.getSize().width ) / 2 , (d.height - f.getSize().height) / 2 );
    f.setVisible( true );
    
  }
}
```


----------



## Michael... (26. Jan 2010)

Lirave hat gesagt.:


> aber wie ich jetzt da drin mehrere Rechtecke zeichnen kann ist mir nicht klar


Würde eher sagen: Wie man zeichnet ist Dir nicht klar ;-)
siehe: http://www.java-forum.org/awt-swing-swt/43939-zeichnen-swing-tutorial.html

Und noch ein kleiner Tipp:
Anstelle von

```
Dimension d = Toolkit.getDefaultToolkit().  getScreenSize()  ;
f.setLocation( (d.width - f.getSize().width ) / 2 , (d.height - f.getSize().height) / 2 );
```
kann man auch die Methode verwenden:

```
f.setLocationRelativeTo(null);
```


----------



## Lirave (26. Jan 2010)

> habe noch nie was gezeichnet mit Java, weiß nicht was man dazu braucht,..



jup null Plan davon, muss aber bis morgen Funktionieren^^

schaue mir mal jetzt das swing tutorial durch


----------



## Michael... (26. Jan 2010)

Allzu schwer ist das nicht.
Am besten man schreibt eine eigene Klasse (siehe Zeile 22), die von JPanel oder JComponent erbt und überschreibt darin die 
	
	
	
	





```
public void paintComponent(Graphics g)
```
Bsp.:

```
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JComponent;
import javax.swing.JFrame;

public class SimplePaint extends JFrame {
	public SimplePaint() {
		this.getContentPane().add(new PaintComponent(), BorderLayout.CENTER);
	}

	public static void main(String[] args) {
		JFrame frame = new SimplePaint();
		frame.setBounds(0, 0, 500, 300);
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}

class PaintComponent extends JComponent {
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		g.setColor(Color.RED);
		g.fillRect(10, 10, 50, 50);
	}
}
```


----------



## Lirave (26. Jan 2010)

danke schaue ich mir gleich an, habe in der Zwischenzeit ff zusammengebaut:


```
import java.awt.*;

import javax.swing.JComponent;
import javax.swing.JFrame;
import java.awt.Graphics;
import java.awt.geom.Rectangle2D;


public class Frame
{
  public Frame(){
	  
	    JFrame   f = new   JFrame  ( "Guillotineschnitt" );
	    f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
	    f.setSize( 600, 400 );
	    f.setLayout(new BorderLayout());
	    //paintingComponent.setPreferredSize(new Dimension(20,20));
	    paintingComponent.setShape(new Rectangle(30, 30 , 50, 50));
	    paintingComponent.setColor(Color.RED);
	    f.add(paintingComponent,BorderLayout.CENTER);
	    
	    
	    
	    f.setLocationRelativeTo(null);
	    f.setVisible( true );
  }
  
 
  
  
  
  public static void main( String[] args )
  {	  
	new Frame();    
  }
private NaivePaintingComponent paintingComponent = new NaivePaintingComponent();
}
class NaivePaintingComponent extends JComponent{
    
	private Color c;
	private Shape shape;
	
	
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D)g;
        g2d.setColor(c);
        g2d.draw(shape);

    }
    
    public void setColor(Color c) {
        this.c = c;
    }
 
    public void setShape(Shape shape) {
        this.shape = shape;
    }

}
```

Wofür benötige ich da eigentlich "paintingComponent.setPreferredSize(new Dimension(20,20));"
Habe es auskommentiert, vergrößert verkleinert , gab alles keinen unterschied.

Gruß Robert


----------



## Michael... (26. Jan 2010)

Lirave hat gesagt.:


> Wofür benötige ich da eigentlich "paintingComponent.setPreferredSize(new Dimension(20,20));"
> Habe es auskommentiert, vergrößert verkleinert , gab alles keinen unterschied.



In dem Fall braucht man es nicht, da es als Komponente im Center Bereich eines BorderLayouts den maximal verfügbaren Platz einnimmt.

Noch ein Hinweis: JFrame besitzt standardmäßig BorderLayout als LayoutManager ein setLayout(new BorderLayout()) ist also nicht notwendig.


----------



## Lirave (26. Jan 2010)

Wollte jetzt dazu ein weiteres Rechteck zeichnen.


```
public class Frame
{
  public Frame(){
	  
	    JFrame   f = new   JFrame  ( "Guillotineschnitt" );
	    f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        f.setBounds(0, 0, 500, 300);
        NaivePaintingComponent paintingComponent = new NaivePaintingComponent();
	    paintingComponent.setShape(new Rectangle(30, 30 , 50, 50));
	    paintingComponent.setColor(Color.RED);
	    f.add(paintingComponent,BorderLayout.CENTER);

	    paintingComponent = new NaivePaintingComponent();
	    paintingComponent.setShape(new Rectangle(80, 80 , 50, 50));
	    paintingComponent.setColor(Color.BLUE);
	    f.add(paintingComponent,BorderLayout.CENTER);

	    f.setLocationRelativeTo(null);
	    f.setVisible( true );
  } 
 
  
  
  
  public static void main( String[] args )
  {	  
	new Frame();    
  }

}
```

Doch wird nur das zweite angezeigt und verändert, ein 2. Rechteck wird anscheinend nicht erstellt.


----------



## Michael... (26. Jan 2010)

NaivePaintingComponent kann mit der Implementierung nur eine Shape zeichnen. Man könnte in der Klasse eine Liste verwenden mit der man die einzelnen Shapes verwalten und zeichnen kann.


----------



## Lirave (26. Jan 2010)

kannst du mir bitte zeigen wie man die Klasse umbauen muss, damit mehrere Rechtecke gezeichnet werden können, die dann gleichzeitig ausgegeben werden


```
class NaivePaintingComponent extends JComponent{
	private Color c;
	private Shape shape;
	LinkedList test = new LinkedList();
	int count = 0;
	
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D)g;
        g2d.setColor(c);
        g2d.draw(shape);
    }
    
    public void setColor(Color c) {
        this.c = c;
    }
 
    public void setShape(Shape shape) {
        this.shape = shape;
    }

}
```

sobald ich versuche dort irgendwas zu ändern meckert eclipse rum


----------



## Lirave (27. Jan 2010)

HI kann mir jemand sagen wie ich "test" aus der main classe dem JFrame übergeben kann in diesem Beispiel ?
So dass alle Elemente aus der Liste gezeichnet werden.


```
import java.io.*;
import java.util.*;
import java.util.LinkedList;
import java.awt.*;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JFrame;
import java.awt.Graphics;


public class Guillotine {
	
	 public Guillotine(){
		  
		    JFrame   f = new   JFrame  ( "Guillotineschnitt" );
		    f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
	        f.setBounds(0, 0, 500, 300);

		    f.add(paintingComponent,BorderLayout.CENTER);


		    f.setLocationRelativeTo(null);
		    f.setVisible( true );
	  } 
	  
	 private NaivePaintingComponent paintingComponent = new NaivePaintingComponent();

	  public static void main(String[] args) {
		  
                ...
	        
	        char[] array = code.toCharArray();
	        System.out.println("\n\n");
	        Grafik.disp(Grafik.zeichnen(array, Steine));
	        
	        List<Rectangle> test = Grafik.computeRectangles(Grafik.zeichnen(array, Steine));      //geht um diese Variable hier


	        new Guillotine();

		System.out.println(" \n -ENDE-");

	  	}
}


class NaivePaintingComponent extends JComponent{
	private Color c;
	private Shape shape;
	LinkedList<Rectangle> rechtecke;
	
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (int i=0;i<rechtecke.size();i++){
        	Graphics2D g2d = (Graphics2D)g;
            g2d.setColor(c);
            g2d.draw(rechtecke.get(i));
        }
        
    }
    
    public void setColor(Color c) {
        this.c = c;
    }
 
    public void setShape(Shape shape) {
        this.shape = shape;
    }

}
```



EDIT:

Habe es jetzt meiner Meinung nach übergeben, aber bekomme f. Fehler


> Exception in thread "main" java.lang.Error: Unresolved compilation problem:
> The constructor Guillotine(List<Rectangle>) is undefined
> 
> at Guillotine.main(Guillotine.java:345)



Wie kann ich das abändern ?

derzeitiger Code:


```
import java.io.*;
import java.util.*;
import java.util.LinkedList;
import java.awt.*;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JFrame;
import java.awt.Graphics;


public class Guillotine {
	
	 public Guillotine(LinkedList<Rectangle> Liste){
		  
		    JFrame   f = new   JFrame  ( "Guillotineschnitt" );
		    f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
	        f.setBounds(0, 0, 500, 300);
                    paintingComponent.setRechtecke(Liste);
		    f.add(paintingComponent,BorderLayout.CENTER);


		    f.setLocationRelativeTo(null);
		    f.setVisible( true );
	  } 
	  
	 private NaivePaintingComponent paintingComponent = new NaivePaintingComponent();

	  public static void main(String[] args) {
		  
                ...
	        
	        char[] array = code.toCharArray();
	        System.out.println("\n\n");
	        Grafik.disp(Grafik.zeichnen(array, Steine));
	        
	        List<Rectangle> test = Grafik.computeRectangles(Grafik.zeichnen(array, Steine));      //geht um diese Variable hier


	        new Guillotine();

		System.out.println(" \n -ENDE-");

	  	}
}


class NaivePaintingComponent extends JComponent{
	private Color c;
	private Shape shape;
	LinkedList<Rectangle> rechtecke;
	
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (int i=0;i<rechtecke.size();i++){
        	Graphics2D g2d = (Graphics2D)g;
            g2d.setColor(c);
            g2d.draw(rechtecke.get(i));
        }
        
    }
    
    public void setColor(Color c) {
        this.c = c;
    }
 
    public void setShape(Shape shape) {
        this.shape = shape;
    }

    public void setRechtecke(LinkedList<Rectangle> Liste){
    	this.rechtecke = Liste;
    }

}
```
Gruß Robert


----------



## Lirave (27. Jan 2010)

habe es gefunden, einfach LinkedList und List verwechselt -.-

als Ergebnis bekomme ich nun folgendes:







was muss ich mache wenn ich das ganze grafic object passend skaliert haben will, so das es die Fläche ausfüllt, wie hier zu sehen ?


----------



## Marco13 (27. Jan 2010)

Du musst die Gesamthöhe und Breite der Rechtecke ausrechnen/wissen. Dann kann man in der paintComponent sowas machen wie

```
float rw = ...Gesamtbreite der Rechtecke
float rh = ...Gesamthöhe der Rechtecke
float cw = getWidth();
float ch = getHeight();
float ratioX = rw / cw;
float ratioY = rh / ch;
float scale = Math.min(ratioX, ratioY);
```
(so ungefähr... bin noch nicht ganz wach...)


----------



## Lirave (27. Jan 2010)

Danke ist nun skaliert.

Ein Problem gelöst tauchen 3 neue auf =), hoffe ihr könnt mir weiterhelfen.

Derzeitiger Stand:






```
public Guillotine (List<Rectangle> Liste, int[][] Bild){
		  
		    JFrame   f = new   JFrame  ( "Guillotineschnitt" );
		    f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
	        f.setBounds(0, 0, 500, 300);
	        paintingComponent.setRechtecke(Liste);
	        paintingComponent.setHoehe(Bild.length);
	        paintingComponent.setBreite(Bild[0].length);
		    f.add(paintingComponent,BorderLayout.CENTER);


		    f.setLocationRelativeTo(null);
		    f.setVisible( true );
	  } 
	  
	 private NaivePaintingComponent paintingComponent = new NaivePaintingComponent();
```


```
class NaivePaintingComponent extends JComponent{
	private Color c;
	private Shape shape;
	List<Rectangle> rechtecke;
	private float gh;
	private float gb;

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        int n = rechtecke.size();
        List<Color> color = new ArrayList<Color>(n);
            for (int i=0; i<n; i++)
            {
                float hue = (float)i/n;
                Color farbe = new Color(Color.HSBtoRGB(hue, 1, 1));
                color.add(farbe);
            }
        
        float cw = getWidth();
        float ch = getHeight();
        float ratioX = cw/ gb;
        float ratioY = ch / gh;
        float scale = Math.min(ratioX, ratioY);        
        
        Graphics2D g2d = (Graphics2D)g;
        g2d.scale(scale, scale);
        for (int i=0;i<rechtecke.size();i++){
        	
            g2d.setColor(color.get(i));
            g2d.fill(rechtecke.get(i));
            g2d.setColor(Color.BLACK);
           // g2d.draw(rechtecke.get(i));
            g2d.drawString(String.valueOf(i) , (int)rechtecke.get(i).getCenterX() , (int)rechtecke.get(i).getCenterY());
        }
    }
```

Nun zu den Problemen:
-erstens die Zahlen (0,1,2) , passen nicht in das Feld hätte sie gerne so groß, das sie in einem Feld sind und auch mit skalieren (habe sie eigentlich ins Zentrum gesetzt, klappt aber anscheinend nicht)
-dann wollte ich fragen, ob es eine Möglichkeit gibt, das Fenster nach dem skalieren noch anzupassen, so das in diesem Fall der graue Rand unten weg fällt (speziell nur bis zur blauen Fläche abschneiden, der graue Rand unter rot und grün soll erhalten bleiben)
-dann hatte ich erst noch Rahmen um die einzelnen Rechtecke gezogen, da sie aber erst sehr klein gezeichnet werden, skaliert der Rahmen dann auch in der breite mit, und das sieht dann nicht mehr so schön aus, gibt es aber eine Möglichkeit um jedes Rechteck einen Rahmen zu setzen, der seine Größe ändert, aber immer 1 px breit ist ?

Bin für jeden Ratschlag dankbar.

Gruß Robert


----------



## Marco13 (27. Jan 2010)

Ja, das wird dann halt irgendwann alles aufwändiger. Natürlich KANN man mit FontMetrics.getStringBounds oder einem GlyphVector die Größe der Zahlen bestimmen, und die dann wirder ähnlich anpassen wie schon das gesamtrechteck in das Fenster. Natürlich kann man den grauen Rand entfernen, aber wenn man das Fenster verändert, muss da entweder ein Rand sein, oder das eigentliche Bild ist verzerrt. Und natürlich kann man die Rechtecke umranden. Dafür (und nicht nur dafür, sondern auch für den Text) wäre es eigentlich gut, eine Möglichkeit zu schaffen, die "Original"-Rechtecke in der gewünschten Größe zu Zeichnen, OHNE Graphics2D.scale zu verwenden (das ist nämlich eigentlich nur für .... sehr spezielle Anwendungen wirklich gut geeignet). 

Sinngemäß könnte es dafür dann eine Methode geben wie zum Beispiel ungefähr (!)

```
private static void paint(Graphics g, Rectangle r, String numberString, float scaleX, float scaleY)
{
    Rectangle rs = das rectangle r, entsprechend skaliert
    g.fillRect(rs);
    g.setColor(Color.BLACK);
    g.drawRect(rs);

    g.setFont(fontMitPassenderGröße);
    g.drawString(numberString, xPassendBerechnet, yPassendBerechnet);
}
```

Speziell die letzten beiden Zeilen wären in Wirklichkeit halt u.U. mit dem Aufruf mehrerer Hilfsmethoden verbunden, die diese "passenden" Sachen ausrechnen...


----------



## Lirave (27. Jan 2010)

habe ich fast befürchtet, also muss ich alles nochmal von vorne Anfangen


----------



## Marco13 (27. Jan 2010)

Warum? ???:L


----------



## Lirave (27. Jan 2010)

war doch nicht so schlimm, wie ich dachte

passt zwar nicht genau, aber ist hinreichend:






so eine trim() Funktion gibt es nicht, oder um den Rand unten und rechts einfach abzuschneiden ?


----------



## Marco13 (28. Jan 2010)

Nicht direkt ... wenn du das ganze in irgendeine JComponent zeichnest, kannst du
theComponent.setPreferredSize(new Dimension(w,h));
schreiben (wobei w,h eben die "saklierte" Größe des Rechtecks ist, also die gewünschte Größe für den dargestellten bereich) und danach noch ein
derFrameWoDasGanzeDrinIst.pack();


----------

