Ich habe für die Schule ein Programm schreiben müssen, welches Graphen auswertet. Die Algorithmen habe ich bereits geschrieben jetzt würde noch eine graphische Oberfläche fehlen. Bis jetzt habe ich folgendes gemacht:
Als Layout für das Fenster habe BorderLayout verwendet und habe als erstes einen JSlider, für die Größe des Graphen, in NORTH positioniert.
Weiters habe ich einen Button "auswerten" in SOUTH eingefügt, um die Auswertung starten zu können.
Als nächstes hätte ich gern noch, dass ich die Matrix mittels JCheckBox(es) darstelle nur weis ich nicht wie das geht.
ja genau sowas, nur gibt es da die Möglichkeit das die checkboxes näher zueinander stehen??? Bei mir sind da sehr große Abstände, das sieht ungefähr so aus:
n=3
m=3
[] [] []
[] [] []
[] [] []
Was ich gerne hätte:
n=3
m=3
[] [] []
[] [] []
[] [] []
Und noch eine weitere Frage:
Kann man irgendwie die Diagonale sperren ??? Aber nur die von links oben nach rechts unten. Ich meine das nur die Checkboxes außerhalb der Diagonale anklickbar sind.
Ungefähr so:
da wäre noch was:
Ich brauche die CheckBoxMatrix später noch für Berechnungen, dafür muss ich aber auch wissen wo jetzt überall ein Häcken gesetzt wurde um eine Matrix erstellen zu können, mit der ich dann weiterrechne. Geht das mit der Methode von dir ???
Bsp.:
Und noch etwas was mit erst jetzt auffällt:
Wenn ich jetzt angenommen eine 4*4 Matrix habe
1 2 3 4
1 [] [] [] []
2 [] [] [] []
3 [] [] [] []
4 [] [] [] []
und ich jetzt bei [1,3] ein Häcken setze, sollte es auch automatisch bei [3,1] auch ein Häcken setzen.
Wie würde das dann funktionieren ? JCheckBox[][] ? Gibt es so was ???
Um jeweils zu jeder CheckBox das Gegenstück auf der anderen Seite der Diagonale zu selektieren, müssen die CheckBoxen wissen, an welcher Position sie stehen. Am einfachsten realisieren wir das, wenn wir eine neue Klasse (ich habe sie MatrixBox genannt) definieren, die von der JCheckBox erbt. Der Konstruktor dieser Klasse nimmt die Positionen r (Row) und c (Column) entgegen und speichert sie. (Zeilen 53-67)
Dann definieren wir ein Array [c]MatrixBox[][] boxes[/c], in welchem alle diese Boxen gespeichert werden. Ausserdem kriegt jede Box einen ActionListener, der dafür sorft, dass das Gegenstück selektiert wird, wenn eine CheckBox selektiert wird. Oder auch deselektiert. (Zeilen 19-25)
Um die Diagonale zu deaktivieren, überprüft jede Box, ob sie in der Diagonale liegt. Dies ist der Fall, wenn r==c ist. Dann wird setEnabled(false) aufgerufen. (Zeilen60-62)
Um den Minimalabstand zu den Nachbarn zu definieren, kannst du setBorder verwenden und der CheckBox ein EmptyBorder geben. Die Zahlen definieren die Abstände zu den Nachbarkomponenten (Zeile 65).
Es bleibt das Problem, dass sich das Panel auseinanderziehen lässt und dadurch die Boxen auseinander gehen. Um dieses Problem zu lösen, musst du einige Layouts kombinieren. Eine ganz einfache Idee wäre es, ein ZwischenPanel zu erstellen, das ein FlowLayout hat und in dem dann die Matrix hineingelegt wird. (Zeilen 43-45)
Wenn dir ein anderes Verhalten vorschwebt, was passieren soll, wenn sich die Komponente ausdehnt, müsstest du das etwas genauer definieren. Wenn du willst, dass die Matrix immer gleich gross in der Mitte ist, wären zwei Panels mit BoxLayout hilfreich. Ich verwende gerne BoxLayouts, weil sie die bevorzugten Grössen der Komponenten gut berücksichtigen.
Java:
importjava.awt.FlowLayout;importjava.awt.GridLayout;importjava.awt.event.ActionEvent;importjava.awt.event.ActionListener;importjavax.swing.JCheckBox;importjavax.swing.JFrame;importjavax.swing.JPanel;importjavax.swing.SwingUtilities;importjavax.swing.border.EmptyBorder;publicclassCheckBoxMatrixextendsJPanel{privateMatrixBox[][] boxes;// Alle CheckboxenpublicCheckBoxMatrix(int n,int m){super(newGridLayout(n, m));ActionListener al =newActionListener(){publicvoidactionPerformed(ActionEvent e){// Selektiere auch das GegenstückMatrixBox box =(MatrixBox) e.getSource();
boxes[box.c][box.r].setSelected(box.isSelected());}};
boxes =newMatrixBox[n][m];for(int i=0;i<n;i++){for(int j=0;j<m;j++){MatrixBox box =newMatrixBox(i, j);
box.addActionListener(al);add(box);
boxes[i][j]= box;}}}publicstaticvoidmain(String[] args){SwingUtilities.invokeLater(newRunnable(){publicvoidrun(){JFrame frame =newJFrame("CheckBox Matrix");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);JPanel pnl =newJPanel(newFlowLayout());
pnl.add(newCheckBoxMatrix(10,6));
frame.add(pnl);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);}});}privateclassMatrixBoxextendsJCheckBox{privateint r,c;privateMatrixBox(int r,int c){this.r = r;this.c = c;if(r==c){// Diagonale deaktivierensetEnabled(false);}// Minimalabstand zu den Nachbarn definierensetBorder(newEmptyBorder(2,2,2,2));}}}
cool danke, jedoch hat das mit den Abständen leider nicht geklappt. Aber ich habe da was gefunden (setBounds) nur weis ich nicht wo genau ich das jetzt einbauen soll.
setBounds
public void setBounds(int x,
int y,
int width,
int height)
Moves and resizes this component. The new location of the top-left corner is specified by x and y, and the new size is specified by width and height.
Parameters:
x - the new x-coordinate of this component
y - the new y-coordinate of this component
width - the new width of this component
height - the new height of this component
das würde glaub ich dann so funktionieren: boxes[j].setBounds(x, y, width, height)
Und noch was:
Also nachdem man die Checkboxes ausgewählt hat, würde ich gerne in ein genauso großes 2 Dimensionales Array die Werte einlesen. D.h., eine Matrix mit 0 und 1, wobei 0 kein Hackerl und 1 ein gesetztes Hackerl bedeutet.
Kann es sein das ich das mit einer CheckBoxMatrix Instanz mache ?? Ich muss die Matrix durchlaufen und an jeder position mit isSelected() == true prüfen und an der jeweiligen Position dann einen 1er in der Matrix setzen.
setBounds() funktioniert aber nur, wenn du kein Layout verwendest, was du aber besser nicht tun solltest. Ansonsten ruft das Layout selber setBounds auf. Mach mir mal eine Zeichnung, die das ganze aussehen soll, wenn das Fenster vergrössert wird, dann kann ich dir schon sagen, welche(s) Layout(s) du verwenden kannst.
setBorder() funktioniert. Gib mal grosse und kleine Werte ein, dann wirst du sehen, dass sich die Abstände verändern.
Lass den ActionListener das Array verwalten. Entweder ein boolean[][] oder eine int[][], was dir besser passt. Du weisst ja die Koordinaten, der JCheckBox, die den ActionListener aufgeruden hat: box.r und box.c.
Mit denen kannst du auch in deinem Array die richtigen Werte setzen.
im Anhang sind 2 Screenshots(Bild1, Bils2) von einem Freund von mir, so ungefähr hätte ich die Anordnung. Die blauen Felder sollen die Zeilennr. und Spaltennr. darstellen
Es befindet sich noch ein weiterer Screenshot(Bild3) von meiner GUI. Irgendwie verändert sich leider auch mit setBorder() auch nichts. Ich habe die 2 und 10 versucht, aber die Ansicht ändert sich nicht.
Und den Slider bekomme ich auch nicht kleiner. Ich habe es mit FlowLayout(FlowLayout.LEFT) in einem Panel versucht, nur das überlappen sich die Zahlen und es wird nicht erkennbar. Ich habe es auch versucht einfach nur mit add(slider) statt add(slider, BorderLayout.NORTH), aber dann verschwindet der Slider ganz.
Ich weis, dass ich jedesmal mit einem neuen Problem zu dir komme, tut mir echt Leid. Mir wird es langsam aber sicher echt unangenehm
Mein jetztiges Problem werde ich ebenfalls versuchen mit Grafiken zu erläutern:
In Bild1 siehst du eine 15*15 Matrix, mit ein paar Hackerl die gesetzt sind und im nächsten Bild2 eine 9*9 Matrix, jedoch ist es anscheinend so das er sich die 15*15 Matrix merkt und nur das Aussehen auf eine 9*9 Matrix heruntersetzt, denn man kann nach wie vor Checkboxes außerhalb der 9*9 Matrix anklicken.
Das ist der Code für das Hauptfenster und ganz unten ab Zeile 93 habe ich einen ChangeListener für den Slider implementiert der auf Veränderungen horcht, und je nach momentanen Wert die Ansicht aktualisiert.
Du fügst zwar jeweils eine neue CheckBoxMatrix hinzu, aber du löschst sie nie. Das sollte eigentlich bereits helfen.
Schreib einfach [c]remove(boxes)[/c] bevor du eine neue Matrix auf boxes speicherst (Zeile 100).
Nach dem add() Befehel solltest du noch validate() aufrufen, damit die Komponenten neu geortned werden.
Aber bezüglich deiner Aussage habe ich noch eine Frage:
Lass den ActionListener das Array verwalten. Entweder ein boolean[][] oder eine int[][], was dir besser passt. Du weisst ja die Koordinaten, der JCheckBox, die den ActionListener aufgeruden hat: box.r und box.c.
Mit denen kannst du auch in deinem Array die richtigen Werte setzen.
Also das Hauptfenster kennst du ja bereits. Da habe ich rechts unten eine Button "auswerten". Nach Betätigung dieses Button erscheint ein neues Fenster "Verarbeitungsfenster" wo ich die Auswertungen ausgeben möchte. Hier der momentane Code:
Und noch was:
Also nachdem man die Checkboxes ausgewählt hat, würde ich gerne in ein genauso großes 2 Dimensionales Array die Werte einlesen. D.h., eine Matrix mit 0 und 1, wobei 0 kein Hackerl und 1 ein gesetztes Hackerl bedeutet.
Kann es sein das ich das mit einer CheckBoxMatrix Instanz mache ?? Ich muss die Matrix durchlaufen und an jeder position mit isSelected() == true prüfen und an der jeweiligen Position dann einen 1er in der Matrix setzen.
Wie mach ich das jetzt, denn der ActionListener für die CheckBoxMatrix ist im Hauptfenster.
Und noch etwas komisches ist mir aufgefallen, also nach betätigen des "auswerten"-Buttons erscheint das AuswertungsFenster. In diesem Fenster ist rechts unten ein "schließen"-Button, der aber nicht nach erscheinen des Fenster sichtbar ist, erst nach dem man an der Größe des Button spielt wird er sichtbar. Woran mag das liegen ????
Das Array, sagen wir mal, es sei ein boolean[][] müsstest du in der Klasse CheckBoxMatrix haben. Im Konstruktor von CheckBoxMatrix würdest du dann dieses Array dann instanzieren: [c]array = new boolean[n][m][/c].
Der ActionListener in CheckBoxMatrix wird jedesmal aufgerufen, wenn eine Checkbox selektiert oder deselektiert wird. Du musst einfach die richtige Position in Array auf true oder false setzen.
Wenn dann "auswerten" gedrückt wird, übergibst du der Klasse Verarbeitungsfenster dieses array als Parameter. Das Objekt der Klasse Verarbeitungsfenster kann dann damit anstellen, was es will.
setVisible(true) sollte erst aufgerufen werden, wenn das gesamte Fenster mit allen Komponenten erstellt worden ist. Lösche es aus der Methode init() und setze es im Konstruktor als letzten Befehl. Dann klappt das.
Du kannst gerne noch weiter fragen, aber ich kann dir leider erst nächstes Jahr wieder weiterhelfen
Guten Rutsch allen
Hallo schon lange nichts mehr voneinander gehört ;-)
Das Array, sagen wir mal, es sei ein boolean[][] müsstest du in der Klasse CheckBoxMatrix haben. Im Konstruktor von CheckBoxMatrix würdest du dann dieses Array dann instanzieren: array = new boolean[n][m] .
Der ActionListener in CheckBoxMatrix wird jedesmal aufgerufen, wenn eine Checkbox selektiert oder deselektiert wird. Du musst einfach die richtige Position in Array auf true oder false setzen.
Wenn dann "auswerten" gedrückt wird, übergibst du der Klasse Verarbeitungsfenster dieses array als Parameter. Das Objekt der Klasse Verarbeitungsfenster kann dann damit anstellen, was es will.
Ich habe das alles befolgt, nur habe ich statt einem boolean[][] ein int[][] genommen, jedoch gibt es da noch ein Problem irgendwie kann man keine int[][] ausgeben oder ?? Ich habe auch versucht das int[][] in ein JLabel einzufügen, aber das mag er nicht. Also gibt es da eine Möglichkeit Matrizen auszugeben ???
Dadurch erreiche ich aber nur, dass die Werte im int[][] in der Console ausgegeben wird, aber nicht auf der GUI. Oder hätte ich noch etwas zusätzliches machen müssen ???
Willst du die Matrix denn schön als Teil der GUI ausgeben, so dass der Benutzer die Zahlen sieht, oder willst du das nur vorübergehen einprogrammieren, so dass du es siehst?
Wenn du es einfach haben willst, würde ich dir eine JTextArea empfehlen. Diese Komponente verfügt über die Methode append(String). Damit kannst du analog zur oben gezeigten for-Schleife, die Elemente in die Textarea einfügen. Wenn du noch setEditable(false) aufrufst, kann man der Benutzer den Text nicht selbst verändern.
Wenn du es ganz schön haben willst, könntest du eine LabelMatrix analog zur CheckBoxMatrix erstellen und statt JCheckBoxen einfach JLabels als Matrix Elemente verwenden.
Ok eine "kurze" Erläuterung was ich alles gemacht habe:
In der Klasse MatrixBoxMatrix(beim ActionListener) habe ich, wie du gesagt hast, ein 2 Dimensionales Array(int[][]) angelegt und ein Abbild der CheckBoxMatrix abgebildet: (Zeile 43-61)
Wie du sicher bemerken wirst habe ich eine getArray() und eine setArray(int[][] array) Methode gemacht. Mit der setArray(int[][] array) übergebe ich dem Attribut die Werte der Matrix, und mit der getArray() hohle ich mir den Wert der Matrix in der Klasse Hauptfenster:
Beim ChangeListener des JSliders hohle ich mir das Array (Ziele 109) in ein Attribut der Klasse Hauptfenster und übergebe dieses Attribut als Parameter für den Konstruktor der Klasse Verarbeitungsfenster (Zeile 92). Aber irgendwie wird da ein Null übergeben und nicht das int[][] was ursprünglich Werte in sich hatte. Denn in der Klasse CheckBoxMatrix habe ich in der Zeile 60 eine Methode die die Werte vom Array auf der Konsole ausgibt. Und die Werte stimmen auch, aber funktioniert nicht.
Bezüglich der Ausgabe vom int[][] auf der GUI:
Ich habe mich ein bisschen falsch ausgedrückt, denn wie schon gesagt soll dieses int[][], was ein Abbild der CheckBoxMatrix ist, nur als Parameter für den Konstruktor einer anderen Klasse(Verarbeitungsfenster) übergeben werden. Das ist aber noch nicht alles, denn dann möchte ich innerhalb des Verarbeitungsfensters dieses int[][] wieder als Parameter für einen anderen Konstruktor(Klasse Graph) verwenden, welches mit diesem int[][] Berechnungen durchführt und dann aber wieder int[][] als Retourwert liefert und diese möchte ich auf der GUI ausgeben, wobei der Benutzer aber keine Veränderungen durchnehmen darf. Hier noch der Code vom Verarbeitgunsfenster:
Ich kann nicht so ganz nachvollziehen, wieso das array null sein könnte, ausser vielleicht, wenn du sofort auf auswerten klickst, bevor du eine einzige CheckBox aktiviert hast. Die Klasse CheckBoxMatrix erstellt im Konstruktor nämlich nicht sofort ein int[][] array, sondern erst im ActionListener. Das finde ich keine gute Idee. Jedesmal, wenn du eine CheckBox anklickst, wird das array komplett neu erstellt und auch noch ein neues Objekt der Klasse Graph erzeugt.
Du solltest das Array ein einziges Mal erstellen, im Konstruktor, und im actionListener nur jene Einträge ändern, die sich tatsächlich geändert haben. Welche Einträge das sind, weisst du ja (array[box.r][box.c]).
Die Methode setArray solltest du löschen, sonst kann ja jeder irgend ein Array da reinspeichern.
In Zeile 92 könntest du auch schreiben: [c]new VerarbeitungsFenster(boxes.getArray());[/c], dann musst du das Array nicht in Zeile 109 extrahieren.
Was ist bei der Klasse VerarbeitungsFenster das Problem? Wenn das int[][] dann wirklich kommt, sollte das eigentlich klappen.