I have 3 classes. One class is my mainframe, another class is my JInternalFrame and also my Observer and the third class does a simulation with a field ob buttons and that one is also my observable class.
Basically I made a button in my observer that copies itself. That includes the add to the desktoppane and the addObserver function of my observable class.
The clone of my observer should also observer the very same observable. So if I interact with the one JInternalFrame, it also changes stuff for the other InternalFrame. It should act like a mirror. (Actually the copy should have like diffrent color buttons and a diffrent orientation but I think that should not be a problem to implement, as soon as I successfully could mirror my Observer)
So since I am using the Observable pattern, I also have to implement the "update" function in my Observer class. I did that and I works like a charm. But when I copy my JInternalFrame, the new InternalFrame observes the Observable(Simulation), but my original JInternalFrame loses the observable connection. It does not show buttons anymore etc.
What I tried: I created a second Observer/JInternalFrame class that extends my first Observer class. That did not work as well. I don't know if thats even a possibility to achieve what I want to.
Sorry for my non perfect english. Sorry for some german words that you might find in the code and sorry that I post so much code. But I am really uncertain right now where my mistake is since I tried to find the error for ours so far.
So here are 2 pictures for you: First picture shows how my JInternalFrame looks like when I create it. Here everything works perfectly.
Second picture shows what it looks like when I click on the New View button. As already described. The original JInternalFrame does not show the simulation anymore. Although they are both observing the same Observable.
And here are my 3 imporant classes:
MainFrame:
public class LangtonsAmeise extends JFrame implements ActionListener {
JDesktopPane desk;
JPanel panelButtons;
JMenuBar jmb;
JMenu file, modus;
JMenuItem load, save, exit, mSetzen, mMalen, mLaufen;
JSlider slider;
static int xInt, yInt, xKindFrame = 450, yKindFrame = 450, xLocation,
yLocation, xMainFrame = 1000, yMainFrame = 900;
static boolean bSetzen = false, bMalen = false, running = true;
static JFileChooser fc;
Random randomGenerator = new Random();
JLabel xLabel, yLabel, speed, statusText, status;
JButton start, stop, addAnt;
JTextField xField, yField;
public LangtonsAmeise() {
// Desktop
desk = new JDesktopPane();
getContentPane().add(desk, BorderLayout.CENTER);
// File Chooser
fc = new JFileChooser(System.getProperty("user.dir"));
speed = new JLabel("Geschwindigkeit");
xLabel = new JLabel("x:");
yLabel = new JLabel("y:");
xLabel.setHorizontalAlignment(JLabel.RIGHT);
yLabel.setHorizontalAlignment(JLabel.RIGHT);
xLabel.setOpaque(true);
yLabel.setOpaque(true);
xField = new JTextField();
yField = new JTextField();
start = new JButton("Fenster erstellen");
stop = new JButton("Pause/Fortsetzen");
start.setMargin(new Insets(0, 0, 0, 0));
stop.setMargin(new Insets(0, 0, 0, 0));
// Buttons
panelButtons = new JPanel();
panelButtons.setLayout(new GridLayout());
panelButtons.add(start);
panelButtons.add(xLabel);
panelButtons.add(xField);
panelButtons.add(yLabel);
panelButtons.add(yField);
panelButtons.add(speed);
panelButtons.add(new Panel());
panelButtons.add(stop);
start.addActionListener(this);
stop.addActionListener(this);
add(panelButtons, BorderLayout.NORTH);
statusText = new JLabel("Status:");
status = new JLabel("Stopp");
// JMenuBar
jmb = new JMenuBar();
setJMenuBar(jmb);
file = new JMenu("File");
modus = new JMenu("Mode");
mLaufen = new JMenuItem("Laufen");
mMalen = new JMenuItem("Malen");
mSetzen = new JMenuItem("Setzen");
load = new JMenuItem("Simulation laden");
//save = new JMenuItem("Simulation speichern");
mSetzen.addActionListener(this);
mMalen.addActionListener(this);
mLaufen.addActionListener(this);
exit = new JMenuItem("Exit");
file.add(load);
file.addSeparator();
file.add(exit);
load.addActionListener(this);
modus.add(mLaufen);
modus.add(mSetzen);
modus.add(mMalen);
jmb.add(file);
jmb.add(modus);
for (int i = 0; i < 20; i++) {
jmb.add(new JLabel(" "));
}
jmb.add(statusText);
jmb.add(status);
setSize(new Dimension(xMainFrame, yMainFrame));
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
this.setLocation(dim.width / 2 - this.getSize().width / 2, dim.height
/ 2 - this.getSize().height / 2);
xField.setText("5");
yField.setText("5");
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Fenster erstellen")) {
if (xField.getText().equals("") || yField.getText().equals("")) {
} else {
xInt = Integer.parseInt(xField.getText());
yInt = Integer.parseInt(yField.getText());
state s = new state();
kindFenster k = new kindFenster(s, this);
s.addObserver(k);
addChild(k);
s.startSimulation();
}
}
if (e.getActionCommand().equals("Pause/Fortsetzen")) {
running = !running;
System.out.println(running);
status.setText("Stopp");
}
if (e.getActionCommand().equals("Setzen")) {
status.setText("Setzen");
running = false;
bSetzen = true;
bMalen = false;
}
if (e.getActionCommand().equals("Laufen")) {
status.setText("Laufen");
running = true;
bSetzen = false;
bMalen = false;
}
if (e.getActionCommand().equals("Malen")) {
status.setText("Malen");
running = false;
bSetzen = false;
bMalen = true;
}
if (e.getActionCommand().equals("Simulation laden")) {
LangtonsAmeise.running = false;
InputStream fis = null;
try {
fc.showOpenDialog(null);
fis = new FileInputStream(fc.getSelectedFile().getPath());
ObjectInputStream ois = new ObjectInputStream(fis);
state s = (state) ois.readObject();
kindFenster k = new kindFenster(s, this);
s.addObserver(k);
addChild(k);
s.startSimulation();
} catch (IOException | ClassNotFoundException
| NullPointerException e1) {
LangtonsAmeise.running = true;
} finally {
try {
fis.close();
} catch (NullPointerException | IOException e1) {
LangtonsAmeise.running = true;
}
}
LangtonsAmeise.running = true;
}
}
public void addChild(JInternalFrame kind) {
xLocation = randomGenerator.nextInt(xMainFrame - xKindFrame);
yLocation = randomGenerator.nextInt(yMainFrame - yKindFrame - 100);
kind.setSize(370, 370);
kind.setLocation(xLocation, yLocation);
desk.add(kind);
kind.setVisible(true);
}
public static void main(String[] args) {
LangtonsAmeise hauptFenster = new LangtonsAmeise();
}
}
JInternalFrame:
public class kindFenster extends JInternalFrame implements ActionListener,
Serializable,Observer,Cloneable {
/**
*
*/
private static final long serialVersionUID = 8939449766068226519L;
static int nr = 0;
static int x,y,xScale,yScale,xFrame,yFrame;
state s;
ArrayList<ImageIcon> ameisen = new ArrayList<ImageIcon>();
JFileChooser fc;
LangtonsAmeise la;
Color alteFarbe, neueFarbe;
JButton save, addAnt, newView;
JPanel panelButtonsKind;
JSlider sliderKind;
public JPanel panelSpielfeld,panelSpielfeldKopie;
JButton[] jbArrayy;
static SetzenActionListener sal = new SetzenActionListener();
static MouseMotionActionListener mmal = new MouseMotionActionListener();
public kindFenster(state s,LangtonsAmeise la) {
super("Kind " + (++nr), true, true, true, true);
setLayout(new BorderLayout());
this.s=s;
jbArrayy=new JButton[s.jbArrayy.length];
for (int b = 1; b<s.jbArrayy.length;b++) {
this.jbArrayy[b] = s.jbArrayy[b];
}
this.la=la;
setSize(new Dimension(xFrame, yFrame));
this.addInternalFrameListener(listener);
this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
panelSpielfeld = new JPanel();
panelSpielfeld.setLayout(new GridLayout(s.y, s.x));
panelButtonsKind = new JPanel();
panelButtonsKind.setLayout(new GridLayout(1, 3));
save = new JButton("<html>Save<br>simulation</html>");
addAnt = new JButton("<html>Add<br>ant</html>");
newView = new JButton("<html>New<br>View</html>");
save.setActionCommand("save");
addAnt.setActionCommand("addAnt");
newView.setActionCommand("newView");
save.setMargin(new Insets(0, 0, 0, 0));
addAnt.setMargin(new Insets(0, 0, 0, 0));
addAnt.addActionListener(this);
save.addActionListener(this);
newView.addActionListener(this);
sliderKind = new JSlider(JSlider.HORIZONTAL, 1, 9, 5);
sliderKind.setSnapToTicks(true);
sliderKind.setPaintTicks(true);
sliderKind.setPaintTrack(true);
sliderKind.setMajorTickSpacing(1);
sliderKind.setPaintLabels(true);
sliderKind.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider) e.getSource();
if (!source.getValueIsAdjusting()) {
int speed = source.getValue();
state.sleeptime = 1000 / speed;
}
}
});
panelButtonsKind.add(save);
panelButtonsKind.add(newView);
panelButtonsKind.add(sliderKind);
panelButtonsKind.add(addAnt);
add(panelButtonsKind, BorderLayout.NORTH);
add(panelSpielfeld, BorderLayout.CENTER);
this.addComponentListener(new MyComponentAdapter());
for (int i = 1 ; i<jbArrayy.length;i++) {
panelSpielfeld.add(jbArrayy[i]);
}
}
// I have been trying around to change the orientation of the buttons in the copy of the frame
public void secondViewFrameSettings() {
int temp;
for (int i = 1; i<=x;i++) {
for (int k = 0; k<y;k++) {
temp = i+(k*x);
panelSpielfeldKopie.add(s.jbArrayy[temp]);
}
}
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("addAnt")) {
s.addAnt();
}
if (e.getActionCommand().equals("newView")){
kindFenster kk = new kindFenster(s,la);
s.addObserver(kk);
la.addChild(kk);
}
if (e.getActionCommand().equals("save")) {
OutputStream fos = null;
try {
LangtonsAmeise.running=false;
try {
fc = new JFileChooser(System.getProperty("user.dir"));
fc.showSaveDialog(null);
LangtonsAmeise.fc.setCurrentDirectory(fc.getSelectedFile());
fos = new FileOutputStream(fc.getSelectedFile());
ObjectOutputStream o = new ObjectOutputStream(fos);
o.writeObject(s);
} catch (NullPointerException e2) {
System.out.println("Fehler beim Auswählen der Datei. Wenden Sie sich an den Entwickler.");
}
} catch (IOException e1) {
LangtonsAmeise.running=true;
System.err.println(e1);
} finally {
try {
fos.close();
} catch (NullPointerException | IOException e1) {
LangtonsAmeise.running=true;
}
LangtonsAmeise.running=true;
}
LangtonsAmeise.running=true;
}
}
InternalFrameListener listener = new InternalFrameAdapter() {
public void internalFrameClosing(InternalFrameEvent e) {
e.getInternalFrame().dispose();
s.simulation.suspend();
}
};
class MyComponentAdapter extends ComponentAdapter {
public void componentResized(ComponentEvent e) {
//Ameisenbilder an die Buttongrößen anpassen
xScale=s.jbArrayy[1].getSize().width;
yScale=s.jbArrayy[1].getSize().height;
s.ameisen.clear();
s.ameisen.add(new ImageIcon(new ImageIcon("ameise.gif")
.getImage().getScaledInstance(xScale, yScale,
Image.SCALE_SMOOTH)));
s.ameisen.add(new ImageIcon(new ImageIcon("ameise90.gif")
.getImage().getScaledInstance(xScale, yScale,
Image.SCALE_SMOOTH)));
s.ameisen.add(new ImageIcon(new ImageIcon("ameise180.gif")
.getImage().getScaledInstance(xScale, yScale,
Image.SCALE_SMOOTH)));
s.ameisen.add(new ImageIcon(new ImageIcon("ameise270.gif")
.getImage().getScaledInstance(xScale, yScale,
Image.SCALE_SMOOTH)));
}
}
public void update(Observable o, Object arg) {
if (o == s) {
for (int i = 1;i<s.jbArrayy.length;i++) {
jbArrayy[i].setBackground(s.jbArrayy[i].getBackground());
}
}
}
}
class SetzenActionListener implements ActionListener,Serializable {
JButton source;
@Override
public void actionPerformed(ActionEvent e) {
source = (JButton) e.getSource();
if (LangtonsAmeise.bSetzen == true) {
if (source.getBackground().equals(Color.GREEN)) {
source.setBackground(Color.WHITE);
} else {
source.setBackground(Color.GREEN);
}
}
}
}
class MouseMotionActionListener extends MouseInputAdapter implements Serializable {
boolean dragged = false;
JButton tempJButton = new JButton();
public void mouseEntered(MouseEvent e) {
if (LangtonsAmeise.bMalen == true && dragged == true) {
((JButton) e.getSource()).setBackground(Color.GREEN);
}
}
public void mouseDragged(MouseEvent e) {
dragged = true;
}
public void mouseReleased(MouseEvent e) {
dragged = false;
}
}
Observable class:
public class state extends Observable implements Serializable {
/**
*
*/
private static final long serialVersionUID = 450773214079105589L;
int[] obRand, reRand, unRand, liRand;
int x, y, temp;
static int sleeptime = 200;
Color background;
int posAmeise, aktuellesIcon = 1, altePosAmeise, xScale, yScale;
Color alteFarbe, neueFarbe, color1, color2;
ArrayList<JButton> jbSer = new ArrayList<JButton>();
private List<Ant> ants = new ArrayList<Ant>();
ArrayList<ImageIcon> ameisen = new ArrayList<>();
JButton[] jbArrayy;
transient Thread simulation;
public state() {
this.x = LangtonsAmeise.xInt;
this.y = LangtonsAmeise.yInt;
color1 = Color.WHITE;
color2 = Color.GREEN;
jbArrayy = new JButton[x * y + 1];
initializeBorders();
initializeAntsImages();
initializeSimulationButtons();
xScale = jbArrayy[1].getSize().width;
yScale = jbArrayy[1].getSize().height;
// Startpunkt für die Ameise festlegen
posAmeise = (((x / 2) * y) - y / 2);
background = jbArrayy[posAmeise].getBackground();
ants.add(new Ant(this));
}
public void initializeAntsImages() {
ameisen.add(new ImageIcon(new ImageIcon("ameise.gif").getImage()
.getScaledInstance(LangtonsAmeise.xKindFrame / x,
LangtonsAmeise.yKindFrame / y, Image.SCALE_SMOOTH)));
ameisen.add(new ImageIcon(new ImageIcon("ameise90.gif").getImage()
.getScaledInstance(LangtonsAmeise.xKindFrame / x,
LangtonsAmeise.yKindFrame / y, Image.SCALE_SMOOTH)));
ameisen.add(new ImageIcon(new ImageIcon("ameise180.gif").getImage()
.getScaledInstance(LangtonsAmeise.xKindFrame / x,
LangtonsAmeise.yKindFrame / y, Image.SCALE_SMOOTH)));
ameisen.add(new ImageIcon(new ImageIcon("ameise270.gif").getImage()
.getScaledInstance(LangtonsAmeise.xKindFrame / x,
LangtonsAmeise.yKindFrame / y, Image.SCALE_SMOOTH)));
}
// Alle Buttons für das Simulationsfeld werden erstellt
public void initializeSimulationButtons() {
jbArrayy[0] = new JButton();
for (int i = 1; i < jbArrayy.length; i++) {
jbArrayy[i] = new JButton();
jbArrayy[i].setBackground(color1);
jbArrayy[i].addActionListener(kindFenster.sal);
jbArrayy[i].addMouseListener(kindFenster.mmal);
jbArrayy[i].addMouseMotionListener(kindFenster.mmal);
}
}
// Ränderindex in Array schreiben
public void initializeBorders() {
reRand = new int[y];
liRand = new int[y];
obRand = new int[x];
unRand = new int[x];
for (int i = 0; i < x; i++) {
obRand[i] = i + 1;
unRand[i] = (x * y - x) + i + 1;
}
for (int i = 1; i <= y; i++) {
reRand[i - 1] = i * x;
liRand[i - 1] = i * x - (x - 1);
}
}
public void initializeSimulation() {
if (simulation != null && simulation.isAlive()) {
simulation.stop();
}
simulation = new Thread() {
@Override
public void run() {
super.run();
while (true) {
try {
sleep(300);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
while (LangtonsAmeise.running && countObservers() > 0) {
try {
Thread.sleep(sleeptime);
for (Ant a : ants) {
move(a);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
};
}
public void startSimulation() {
initializeSimulation();
simulation.start();
}
public void changeColor(int altePos, Color c) {
jbArrayy[altePos].setBackground(c);
}
public void addAnt() {
ants.add(new Ant(this));
}
public void changeIcon(boolean k, Ant a) {
int g = (k == true) ? 1 : -1;
if (a.aktuellesIcon + g < 0) {
a.aktuellesIcon = 3;
} else if (a.aktuellesIcon + g > 3) {
a.aktuellesIcon = 0;
} else {
a.aktuellesIcon += g;
}
jbArrayy[a.posAmeise].setIcon(ameisen.get(a.aktuellesIcon));
setChanged();
notifyObservers();
}
public void rightCheck(Ant a) {
if (checkInArray(a.posAmeise, reRand)) {
a.posAmeise -= x - 1;
} else {
a.posAmeise += 1;
}
}
public void leftCheck(Ant a) {
if (checkInArray(a.posAmeise, liRand)) {
a.posAmeise += x - 1;
} else {
a.posAmeise -= 1;
}
}
public void upCheck(Ant a) {
if (checkInArray(a.posAmeise, obRand)) {
a.posAmeise += (y - 1) * x;
} else {
a.posAmeise -= x;
}
}
public void downCheck(Ant a) {
if (checkInArray(a.posAmeise, unRand)) {
a.posAmeise -= (y - 1) * x;
} else {
a.posAmeise += x;
}
}
public void checkAmeisenSize(Ant a) {
while (!(ameisen.size() == 4)) {
}
;
}
public static boolean checkInArray(int currentState, int[] myArray) {
int i = 0;
for (; i < myArray.length; i++) {
if (myArray[i] == currentState)
break;
}
return i != myArray.length;
}
public ImageIcon getAntImage() {
return ameisen.get(aktuellesIcon);
}
public void move(Ant a) throws InterruptedException {
try {
a.altePosAmeise = a.posAmeise;
a.alteFarbe = jbArrayy[a.posAmeise].getBackground();
if (a.alteFarbe.equals(Color.GREEN) && ameisen.size() == 4) {
if (a.aktuellesIcon == 0) {
checkAmeisenSize(a);
rightCheck(a);
} else if (a.aktuellesIcon == 1) {
checkAmeisenSize(a);
downCheck(a);
} else if (a.aktuellesIcon == 2) {
checkAmeisenSize(a);
leftCheck(a);
} else if (a.aktuellesIcon == 3) {
checkAmeisenSize(a);
upCheck(a);
}
changeIcon(true, a);
changeColor(a.altePosAmeise, Color.WHITE);
} else if (a.alteFarbe.equals(Color.WHITE) && ameisen.size() == 4) {
if (a.aktuellesIcon == 0) {
checkAmeisenSize(a);
leftCheck(a);
} else if (a.aktuellesIcon == 1) {
checkAmeisenSize(a);
upCheck(a);
} else if (a.aktuellesIcon == 2) {
checkAmeisenSize(a);
rightCheck(a);
} else if (a.aktuellesIcon == 3) {
checkAmeisenSize(a);
downCheck(a);
}
changeIcon(false, a);
changeColor(a.altePosAmeise, Color.GREEN);
setChanged();
notifyObservers();
}
jbArrayy[a.altePosAmeise].setIcon(new ImageIcon());
} catch (IndexOutOfBoundsException e) {
move(a);
}
}
}
Edit: Ant Class
import java.awt.Color;
import java.awt.Image;
import java.io.Serializable;
import java.util.ArrayList;
import javax.swing.ImageIcon;
public class Ant implements Serializable {
int posAmeise, aktuellesIcon = 1, altePosAmeise;
Color alteFarbe, neueFarbe;
ArrayList<ImageIcon> ameisen = new ArrayList<>();
public Ant(state s) {
this.posAmeise = s.posAmeise;
s.jbArrayy[posAmeise].setIcon(s.ameisen.get(aktuellesIcon));
}
}