# Slide-Puzzle als Applet implementieren



## Peopels (5. Jul 2004)

Hoy Leute,
erstmals ein großes Hallo an alle, hab zwar schon oft hier in den Threads herumgestöbert und allerhand Interessantes und Nützliches gefunden, aber mich noch nicht hier angemeldet, da ich eigentlich noch eine Stufe unter "Anfänger" war. Naja, nun habe ich ein Semester lang Java genossen und kann mich nun zu den "Anfängern mitzählen  :wink: 
Da ich ja an einer Uni bin, muss ich nun auch in dem Fach an einer Seminararbeit mitwirken und an dieser sitze ich nun scon seit geraumer Zeit und irgendwie erscheint mir meine Aufgabenstellung wie "Böhmische Dörfer" und deshalb wende ich mich nun an Euch, mit der großen Bitte mir ein bißchen unter die Arme zu greifen, da ich echt nimmer weiter weiß!
So, falls sich nun jemand entschließen sollte, mir zu helfen, hier die Aufgabe und weiter unten dann meine Aufgabenstellung:

*Aufgabe*
Erstellung eines Slide-Puzzles, bei dem man selber die Anzahl der Reihen und Spalten einstellen kann mit der das Bild geteilt wird, desweiteren sollen die Teile per Mausklick austauschbar sein, d.h., wenn man ein Teil anklickt und dann das nächste, dann soll die Position der Teile miteinander getauscht werden. Dies alles soll als Applet dann auf eine HTML Seite dargestellt werden.

*Meine Aufgabe*
Ich soll den Benutzerdialog erstellen, d.h. die Auswahl der Bildausschnitte und zusätzlich sollen dann die Bildauschnitte, die per Mausklick ausgewählt werden, mit einem Rahmen umlegt werden, damit man sieht, welche Bildausschnitte man ausgewählt hat.  Das Austauschen der beiden Bildteile übernimmt dann eine Kollege.


*AblauF*
Erster Mausklick
Rahmen um ausgewählten Bildausschnitt machen
Container-Position des Bildausschnitts herausfinden und in eine Variable schreiben, damit diese Variable dann an die Tauschfunktion weitergegeben werden kann

Zweiter Mausklick
wieder Rahmen um ausgewählten Bildauschnitt
wieder Container-Position des Bildausschnitts herausfinden und in eine Variable schreiben, damit diese Variable dann an die Tauschfunktion weitergegeben werden kann

So und hier ist der Code, der bisher von uns entwickelt wurde:


```
/**
 * Bildausschnitt-Anzeige
 * 
 */


import java.awt.*;
import java.awt.image.*;

public class ImageDisplayedDetail extends ImageViewer 
{
	private Dimension Size;
	int breite, hoehe;
	
		

	ImageDisplayedDetail(ImageProducer source, int x, int y, int width, int height)
	{
		// construct base class
		super(new FilteredImageSource(source, new CropImageFilter(x,y,width,height) ));
		// store size of detail
		Size = new Dimension(width, height);
		breite = width;				// für die Breite des Highlights
		hoehe = height;				// für die Höhe des Highlights
	}
	
	public Dimension getPreferredSize()
	{
		return new Dimension(Size);
	}
	/**
 * Das habe ich gemacht um einen Rahmen für den Bildausschnitt zu erhalten
 * 
 */
	
	
	public boolean highlight (boolean status)   // für Rahmen bei Auswahl
	{	

		Graphics g = getGraphics(); // hier wird Graphics g implementiert
		if (status = true)			// wenn Status auf True ...
			g.drawRect(0, 0, breite-1, hoehe-1); // Rahmenblablab
			return true;
	}
}
```


```
/**
 * hier werden dann die Puzzleteile zusammengesetzt
 * 
 */
import java.awt.*;
import java.awt.image.*;
import java.awt.event.MouseAdapter;		//für Mouseadapter
import java.awt.event.MouseEvent;		// für Mouseevent

public class ImageMatrix extends Panel 
{
	private int Rows, Cols;  // rows and columnes of matrix 
	private ImageDisplayedDetail[][] ImgDetail; // array of details
	private Dimension Size; // size of orign
	
	
	ImageMatrix(ImageProducer img, int rows, int cols)
	{
		Rows = rows;
		Cols = cols;
		ImgDetail = new ImageDisplayedDetail[Rows][Cols];

		// Ermittle orig. Größe
		ImageViewer orig = new ImageViewer(img);
		Size = orig.getPreferredSize();
		// System.out.println(Size);
		
		// Grid Layout
		setLayout(new GridLayout(Rows,Cols));
		
		// Größe des Teilbildes
		int dx = Size.width / Cols, dy = Size.height / Rows;
			
		// Anlegen der Matrix
		for (int i=0; i<Rows; i++)
		{
			for (int j=0; j<Cols; j++)		 
			{ 
				ImgDetail[i][j] = new ImageDisplayedDetail(img, j*dx, i*dy, dx, dy );
			}
		}

		for (int j=0; j<Cols; j++)		 
		for (int i=0; i<Rows; i++)
				add(ImgDetail[i][j]);
	
		

		// Kontrolle
		System.out.println("Orig:   " + Size);
		System.out.println("Matrix: " + getPreferredSize());
		System.out.println("Detail: " + ImgDetail[0][0].getPreferredSize());

		
	}
/**
 * Mein Teil
 * Das habe ich bis jetzt gemacht um den Mausklick auszuwerten
 * und wo ich absolut nimmer weiterweiß, was ich machen soll
 * hier sollte die Aktion stehen mit dem Mouseklick
 */
	class MeinMausklick extends MouseAdapter
	{		
		int x, y;
		MeinMausklick (int z, int u)
		{
			x = z;
			y = u;
			
		}
		public void mouseClicked (MouseEvent e)
		{
			if (e.getClickCount() <= 1) //für 1. Klick
			{
									// für 1. Containerwert
				Component component = getComponent(x);
				System.out.println("X ist:   " +x);
				highlight.status = true;
			}
			else if (e.getClickCount() > 1) // für 2. Klick
			{
				int y;					// für 2. Containerwert	
				
			}
			
		}
	}
	
	// public Dimension getPreferredSize()
	// {
	//	return new Dimension(450,450);
	// }

}
```


```
/**ImageViewer
 * 
 * 
 * 
 */


import java.awt.*;
import java.awt.image.*;

public class ImageViewer extends Canvas
{
	private Image bild;
	int breite, hoehe;
	
	ImageViewer(ImageProducer img)
	{
		breite = -1;
		hoehe = -1;
		bild = createImage(img);
		
		// warteAufBildgroesse();
	}
	
	
	public void paint(Graphics g)
	{
		g.drawImage(bild, 0, 0, this);
		g.drawRect(0, 0, breite-1, hoehe-1);
	}
	
	public Dimension getPreferredSize()
	{
		if(breite == -1 || hoehe == -1)
			warteAufBildgroesse();
		
		return new Dimension(breite, hoehe);
	}
	
	private void warteAufBildgroesse()
	{
		prepareImage(bild, this);
		
		while(true)
		{
			int status = checkImage(bild, this);
			if ((status & ImageObserver.WIDTH) != 0 && (status & ImageObserver.HEIGHT) != 0)
				break;
			try
			{
				Thread.sleep(10);
			} catch (InterruptedException ign)
			{
			}
		}
		
		breite = bild.getWidth(this);
		hoehe  = bild.getHeight(this);
	}
}
```


```
/**
 * Applet zur Anzeige eines ImageViewer
 * 
 * 
 * 
 * 
*/

import java.awt.*;
import java.awt.image.*;
import java.applet.Applet;

public class Puzzle extends Applet
{
	public final int Zeilen = 4, Spalten = 4;
	
	public void init()
	{
		// 1. Öffnen eines ImageProducers
		Image orig = getImage(getCodeBase(), "images/test.gif");
		
		// 2. hole aus dem Image den zugehörigen Producer
		ImageProducer origProd = orig.getSource();
	
		// 3. geneiere Bild-Matrix
		ImageMatrix mat = new ImageMatrix(origProd, Zeilen, Spalten); 
		
		add(mat);
		
	}
	
	
}
```

Es wäre wirklich supercool, wenn mir da jemand weiterhelfen könnte, wie ich das zu Ende bekomme, da ich absolut nimmer weiter weiß!
Derjenige, der das hinbekommt, bekommt von mir mein Carepaket, das mir meine Oma geschickt hat, das sind 4 Packungen Haribo Goldbären und ne Riesentafel Milka, zugeschickt

Nüüü denn, schonmal 1000 Dank im voraus für eure Hilfe


----------



## Peopels (5. Jul 2004)

Ähmm, ganz vergessen, die Containerpostion des Bildausschnitts, bekommt man irgendwie mit 
Container.getComponent(), aber das ist auch schon alles, was ich weiß


----------



## KSG9|sebastian (6. Jul 2004)

1) Vergleichen tut man mit '==', zuweisen mit '='


```
//Klasse ImageDisplayedDetail

 if (status = true)
```

Das tut so nicht.

2) Was erwartest du denn ? Fertigen Code wirds sicher nicht geben, aber mal n denkanstoß:


Es wird abgefragt, wieviele Zeilen und Spalen gemacht werden sollen. Dann würde ich für jedes "Bildteil" ein eigenes Objekt erzeugen mit xPos, yPos, width, height

Bei nem Mausklick bekommst du mit e.getPoint() die Maus-Koordinaten. 
Dann guckst du, welcher Bildteil angeklickt wurde, geht ja ganz einfach mit den Korrdinaten.

(int)e.getPoint().x / width
(int)e.getPoint().y / height

Damit kriegst du die Reihe bzw. Spalte wenn ich richtig geraten hab 

Dann schreibst du dir ne Methode die dir die Referenz auf das zuerst geklickte bild speichert, dass gleiche mit dem 2. Mausklick. Wenn der 2. Mausklick gemacht wurde rufst du ne Funktion aus, von mir aus tauschen..

tauschen(bild1, bild2)

In dieser Methode hast du ja die Referenz auf die beiden angeklickten bilder, da tauschst du einfach die x und y koordinaten aus und rufst repaint() auf um alles neu zu zeichnen.


----------



## KSG9|sebastian (6. Jul 2004)

ach ja, du könntest dir mal nen normalen programmierstil angewöhnen, vor allem einen einheitlichen.

manche variablen schreibst du private, manche public, bei manchen machst du gar nichts
variablen werden IMMER klein geschrieben, instanzvariablen werden IMMER private geklariert

noch so was komisches:

du machst ne Instanzvariable Size vom typ Dimension und in der gleichen klasse deklarierst du noch die variablen int width, int height. gibts irgend nen unterschied zwischen den beiden oder ist das nur aus spass an der freude?



Ach ja, die Componente an ner bestimmten maus position bekommst du so, und die abfrage mit getClickCount() wird wohl nicht so gehen wie du sie machst, denn wenn man zum 3. mal klickt dann muss er wieder das erste bild markieren und nicht schon tauschen, ich hab mal hier ne modifizierte version, aber die ist net getestet, compilerfehler wirst du schon bemerken


```
public void mouseClicked(MouseEvent e){
    
    int count = e.getClickCount();
    if((count % 2) != 0){   //Restwertdivision, falls != 0 (1,3,5...) ist es immer der erste klick
        Component c = getComponentAt(e.getPoint());
        //hier muss halt noch der 2. Klick bearbeitet werden, is aber wohl kein prob mehr hoff ich mal        

    }
    else{
        Component c = getComponentAt(e.getPoint());
        //hier muss halt noch der 2. Klick bearbeitet werden, is aber wohl kein prob mehr hoff ich mal

    }

}
```


----------



## Guest (9. Jul 2004)

Hey, besten Dank, du bist ein Schatz.

Hab deine Tipps befolgt und folgendes geschrieben in der ImageMatrix:


```
class MeinMausklick extends MouseAdapter
		{		
			int dxx = Size.width / Cols, dyy = Size.height / Rows;
			
			
			public boolean status = false; 
		
			public void mouseClicked (MouseEvent e)
			{
				
				status = false;
				int count =e.getClickCount();
				if ((count % 2) != 0)		//Restwertdivision, falls != 0 (1,3,5...) ist es immer der erste klick 

				{
					Component c = getComponentAt(e.getPoint()); 
					int x =e.getPoint().x / dxx;
					int y =e.getPoint().y / dyy; 
					status  =! true;
					
				}
				else  // für 2. Klick
				{
					Component c = getComponentAt(e.getPoint()); 					// für 2. Containerwert	
					int x =e.getPoint().x / dxx;
					int y =e.getPoint().y / dyy;
					status =! false;
				}
				
			}
```

so und jetzt wollte ich den Mousadapter bei jeden einzelnen Objekt in der ImagedisplayedDetail anmelden,
dass müsste doch folgendermaßen gehen

```
addMouseListener
```
aber da muckt sich gar nix und auch das mit dem Highlite funktioniert nicht   
Kannst du mir bitte, bitte nochmal helfen[/code]


----------



## P3AC3MAK3R (9. Jul 2004)

@Aufgaben-und-Gesuche-Mods:
Bitte Titel anpassen. Der Titel "Bitte an die Großmeister hier" sagt absolut NICHTS aus.


----------



## L-ectron-X (9. Jul 2004)

_Titel editiert._
@Peacemaker: Besser? :wink:


----------



## Guest (10. Jul 2004)

ähm, eine Frage, wie kann ich jetzt dann den MouseAdapter, der ja eine InnerClass in der ImageMatrix bildet, jetzt dann bei den einzelnen Objekten in der ImageDisplayed Klasse anmelden.

Ich tipp mir schon die Finger wund, aber er macht nix oder bringt nur wüsste Fehlermeldungen, wenn ich es versuche


----------



## Isaac (10. Jul 2004)

Da gibt es verschiedene Konzepte. 

Der einfachste ist sicher der, die Instanzen zu übergeben


Test extends JFrame sei deine Klasse in der deine main(String args[]) Methode ist

Test hat ja einen konstruktor und vieleicht eine init Methode. In der init Methode werden die Komponenten erzeugt. Panel, Menus etc. Man übergibt einfach allen Komponenten "this" und stellt entsprechende Methoden zur Verfügung um an die anderen Komponten zu kommen.


Bin ich nun in Komponente EineTolleAnzeige dann rufst du einfach immer weiter nach oben bis zu der Komponente die du haben willst um deinen Listener zu registrieren.

z.b.

a.getPanelC().getPanel()H.getMainFrame().getMenu().addIrgendNenChangeListener()

Das empfiehlt sich aber eigentlich nur für kleine Projekte. Bei grösseren sollte man Anzeige und Eventhandling in getrennten Klassen mache. Die Vorgehensweise bleibt aber eigentlich die selbe.


----------

