Anstatt dir ein paar wenig aussagekräftige Codefragmente zu präsentieren, beschreibe ich das Gesamtkonzept, damit dir das komplexe Zusammenspiel der einzelnen Komponenten klarer wird. Dabei werde ich eine Top-Down-Strategie verwenden, d.h. vom einfachen Überblick ausgehend deren einzelne Bestandteile zu analysieren. Dadurch wirst du (hoffentlich

) lernen, wie man eine gegebene Aufgabenstellung so 'seziert', dass die Implementierung nur noch reine Fleißarbeit ist. Bei der Implementierung solltest du dann eine Bottom-Up-Strategie anwenden, d.h. erst die Klassen für die atomaren Bestandteile programmieren (bei dir sind das die Felder), dann die Klassen für deren Container usw.
Ich setze voraus, dass du Swing-Klassen verwendest. Man kann das alles auch mit AWT-Klassen machen, aber ich glaube, dass du auch Swing-spezifische GUI-Elemente verwenden möchtest, beispielsweise eine
JTable für die Auswahl des gewünschten Nonogramms.
Wenn du dir ein Nonogramm anschaust, wirst du sehen, dass es eine Tabelle ist, die aus drei Untertabellen besteht; je eine für die Spalten- und Zeilenköpfe, wo die Längen der Streifen angegeben sind, und eine dritte, die als Bild-Raster fungiert. Ich werde mich bei der Darstellung im wesentlichen auf das Raster beschränken, für die anderen beiden Untertabellen gilt, in leicht abgewandelter Form, die gleiche Vorgehensweise.
Für das Nonogramm definierst du eine Klasse
Zettel, die du von
JPanel ableitest. Dieses Panel hat, je nach Zoomstufe, eine unveränderliche Größe. Beim Einbauen in deine GUI wird es in ein
JScrollPane eingebettet. Du erweiterst diese Klasse um eine
setCellSize-Methode zur Festlegung der Zoomstufe und eine
BuildUp-Methode, welche den ganzen internen Aufbau macht; du kannst auch einen zusätzlichen Konstruktor definieren, der diese
BuildUp-Methode aufruft, aber das ist nicht unbedingt notwendig. Zusätzlich kannst du hier auch eine Statistik verwalten, die überprüft, ob das Raster vom Benutzer den Vorgaben entsprechend ausgefüllt wurde, aber darauf kannst du beim Prototyp deiner Anwendung erstmal verzichten.
BuildUp benötigt drei Parameter: je eine 2D-Tabelle für die Daten der Zeilen- und Spaltenköpfe sowie die Größe der einzelnen Zellen. Die Tabelle für die Spaltenköpfe organisierst du nach dem Muster
ColumnHeader[col][row], diejenige für die Zeilenköpfe nach dem Muster
RowHeader[row][col]. Aus den Dimensionen der beiden Tabellen kannst du über die jeweiligen length-Attribute nicht nur die Anzahl der Reihen und Spalten für dein
Raster-Objekt ermitteln, sondern auch die Anzahl der zusätzlichen Zeilen und Spalten für die Tabellen der Zeilen- und Spaltenköpfe. Jede dieser drei Untertabellen bekommt eine eigene Klasse, die du wiederum von
JPanel ableitest.
Für das Panel
Zettel erzeugst du einen
GridBagLayout-Manager. Die Anzahl der Zeilen und Spalten ist jeweils die Anzahl der Zeilen und Spalten in deinem
Raster-Objekt plus die Anzahl der für die Zeilen- und Spaltenköpfe zusätzlich benötigten Zeilen und Spalten. Die Objekte der einzelnen Tabellen bettest du dann in den jeweiligen Zellenbereich ein. Nun weißt du, wieviele Zeilen und Spalten du insgesamt hast. Die
BuildUp-Methode kann nun die Methode
setCellSize aufrufen, der sie den Parameter für die Zellengröße übergibt.
Die Methode
setCellSize berechnet aus der Zellengröße sowie der Anzahl der Reihen und Spalten den Platzbedarf und passt dementsprechend die Fenstergröße an. Durch den Layout-Manager werden dadurch automatisch auch die Panels für die drei Untertabellen auf die richtige Größe skaliert.
Für die Notizen erstellst du eine Klasse
Raster, welche du von
JPanel ableitest. Sie ist relativ einfach aufgebaut, weil der größte Teil der Funktionalität automatisch abläuft. Für
Raster verwendest du einen normalen
GridLayout-Manager; die Anzahl der Zeilen und Spalten übergibst du als Parameter dem Konstruktor. In jede Zelle platzierst du ein eigenes Objekt deiner Klasse
Feld. Wird die Größe des
Raster-Panels verändert (das geschieht, wenn das
Zettel-Panel beim Zoomen vergrößert oder verkleinert wird), passt der Layout-Manager auch automatisch die Größe der
Feld-Objekte an; das Neuzeichnen wird dadurch auch automatisch veranlasst.
Ein
Feld kann zwei Zustände haben: leer oder gefüllt. Am besten leitest du die Klasse
Feld von der Klasse
JCheckBox ab. Im Konstruktor rufst du dann die geerbten Methoden
setIcon und
setSelectedIcon auf und übergibst ihnen die gewünschten Bildchen; alles andere geschieht automatisch. Wenn du Probleme bei der Anzeige hast, solltest du sie doch von
Canvas ableiten; dann mußt du die Verwaltung der Zustände und das Zeichnen der entsprechenden Grafik 'von Hand' programmieren. Aber das wolltest du ja sowieso schon.
Ich hoffe, dass du dich von so viel Informationen nicht erschlagen fühlst und wünsche dir viel Erfolg beim Programmieren. Ich würde mich freuen, wenn du irgendwann das Resultat deiner Arbeit präsentieren kannst, so dass ich auch mal ein bißchen damit spielen kann.
PS:
Eine große Sammlung von Nonogrammen und anderen Spielen findest du bei
Otto Janko.