addActionListener zeigt keine Wirkung

Der_Falke_

Mitglied
Hallo liebe Community,

ich habe vor kurzem mit dem programmieren von richtigen Programmen von Java angefangen, habe jedoch schon einige Erfahrung mit Java aus vorherigen Programmierungen wie z.B. Plugins gesammelt.
Da ich beim programmieren von Anwendungen jedoch noch recht frisch bin habe ich eine Frage. Ich habe ein JFrame mit Buttons erstellt und allem Texturen gegeben. Jetzt möchte ich fortfahren. Dazu soll der Anwender auf einen der Buttons klicken. Jedoch funktioniert das adden der Buttons zu dem ActionListener nicht. Ich habe mir bereits einige Sachen im Netz angeschaut, doch ich habe meinen Fehler nicht gefunden. Das ActionEvent an sich wird ausgeführt, doch wenn ich auf einen der Buttons klicke wird der jeweilige Code für den Button nicht ausgeführt. Ich denke mal das die Buttons nicht dem ActionListener hinzugefügt worden sind, doch wo liegt mein Fehler?

Ich würde mich über Antworten sehr freuen!

Hier mein Code:
[Java]public class Frame extends JFrame implements ActionListener {

private JButton startButton;
private JButton optionenButton;
private JButton schliessenButton;


public static void main(String[] args) throws IOException {
Frame fenster = new Frame("MineJump");
fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
fenster.setSize(1400,800);
fenster.setResizable(false);

Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
fenster.setBounds((screenSize.width-1400)/2, (screenSize.height-800)/2, 1400, 800);

Image icon = new ImageIcon(Frame.class.getResource("/Images/icon.png")).getImage();
fenster.setIconImage(icon);
fenster.setVisible(true);
}



public Frame(String titel) {
super(titel);

JPanel panel = new JPanel();

JLabel background = new JLabel(new ImageIcon(Frame.class.getResource("/Images/menu.png")));
background.setBounds(0,0,1400,800);
panel.add(background);

panel.setLayout(null);


JButton startButton = new JButton("Start");
JButton optionenButton = new JButton("Optionen");
JButton schliessenButton = new JButton("Schliessen");

startButton.setBounds(300, 180, 798, 80);
startButton.setIcon(new ImageIcon(Frame.class.getResource("/Images/startButton.png")));
startButton.setRolloverIcon(new ImageIcon(Frame.class.getResource("/Images/startButtonMouseOver.png")));
startButton.setBorderPainted(false);
startButton.addActionListener(this);

optionenButton.setBounds(300, 320, 798, 80);
optionenButton.setIcon(new ImageIcon(Frame.class.getResource("/Images/optionenButton.png")));
optionenButton.setRolloverIcon(new ImageIcon(Frame.class.getResource("/Images/optionenButtonMouseOver.png")));
optionenButton.setBorderPainted(false);
optionenButton.addActionListener(this);

schliessenButton.setBounds(300, 460, 798, 80);
schliessenButton.setIcon(new ImageIcon(Frame.class.getResource("/Images/schliessenButton.png")));
schliessenButton.setRolloverIcon(new ImageIcon(Frame.class.getResource("/Images/schliessenButtonMouseOver.png")));
schliessenButton.setBorderPainted(false);
schliessenButton.addActionListener(this);

add(startButton);
add(optionenButton);
add(schliessenButton);

add(panel);
}



public void actionPerformed(ActionEvent e) {
if(e.getSource() == startButton) {
System.out.println("klappt");
startButton.setBounds(0,0,0,0);
optionenButton.setBounds(0,0,0,0);
schliessenButton.setBounds(0,0,0,0);
} else if(e.getSource() == optionenButton) {
System.out.println("3");
} else if(e.getSource() == schliessenButton) {
System.exit(0);
}
}[/Java]
 
Als erstes würde ich die Buttons mal dem JPanel und nicht dem JFrame hinzufügen (Z.58-60). Und zweitens: Du musst zum Beispiel in Zeile 29 nicht Frame.class schreiben, da du keine statische Methode/Konstruktor hast. Deshalb kannst du auch einfach getClass() schreiben!
 
Ein Klassiker.
Du legst im Konstruktor von Frame drei neue JButton Instanzen als lokale Variablen an und fügst denen den ActionListener hinzu. Dies sind aber andere Objekte als die 3 JButton Instanzvariablen! Deshalb schlägt der Vergleich in der actionPerformed fehl.
Ausserdem solltest du eine eigene Klasse nie wie eine java-Standardklasse benennen.
 
Also dein Code selbst hat viel Verbesserungspotential.

- Leite nicht von JFrame ab, wenn du nicht dessen Verhalten änderst (tust du nicht)
- Ich würde deine Klasse nicht von ActionListener ableiten lassen (das geht auch mit einer inneren Klasse)
- LayoutManager verwenden (kein null-Layout)
- JFrame zentriert man einfach mit: frame.setLocationRelativeTo(null);
- Vom Stil her: englische Bezeichner verwenden.
- Buttons brauchen keinen gemeinsamen ActionListener, das geht auch wenn du sie auf mehr verteilst, somit sparst du dir die Frage welcher Button gedrückt wurde.
- Lass dein frame erst ganz zum Schluß anzeigen, wenn du alle Komponenten hinzugefügt hast (setVisible(true))
- Starte deine Gui in der main-Methode mit:
Java:
SwingUtilities.invokeLater(new Runnable() {
  @Override
  public void run() {
    // new Frame("Titel");
  }
});
 
Eine Frage zu deinen Punkten: Es ist doch nicht falsch, wenn man wie dort die Klasse von JFrame ableitet. Oder was meinst du mit Veränderungen?
 
Es ist nicht falsch, eher ein Bad Smell hätt ich gesagt. Du veränderst das Verhalten nicht von JFrame.

Analoges Beispiel:

Java:
class Car {
  private String brand;
  public Car(String brand) {
    this.brand = brand;
  }
  public String getBrand() {
    return brand;
  }
  public void setBrand(String brand) {
    this.brand = brand;
  }
}

Normalerweise würde man diese Klasse so verwenden:

Java:
Car vw = new Car("VW");
Car merceds = new Car("Mercdes");

Hingegen du würdest es so verwenden:

Java:
class MyCar extends Car {
  public MyCar(String brand) {
    super(brand);
  }
}

Mit:

Java:
MyCar vw = new MyCar ("VW");
MyCar merceds = new MyCar ("Mercdes");

Du hast genau das Selbe erzeugt mit deiner Frame Klasse.

Hingegen wenn du jetzt sowas machen würdest, dann würdest du das Verhalten der Klasse ändern:

Java:
class VWCar extends Car {
  public VWCar(String brand) {
    // Ignore input
    super("VW");
  }
  @Override
  public void setBrand(String brand) {
    // Do nothing
  }
}

Ich hoffe das war jetzt verständlich.
 
Zuletzt bearbeitet:
@Java20134 Ich habe die Buttons bewusst dem Frame hinzugefügt da ich sonst das Problem habe das sie von dem Hintergrund überschrieben werden. (Bzw. Der Start Button wird zwar angezeigt doch Optionen und Schliessen erst wenn man drüber fährt)
Und: Aber es ist doch trotzdem möglich Frame.class zu schreiben, oder gibt es einen bestimmten Grund warum man eher getClass() nehmen sollte?

@HarryKane Okay

@Flown
- Verbesserungspotenzial:
Auf alle Fälle. Ich versuche immer die besten Wege zu finden, doch oft mache ich es so, dass ich es erst einmal mit funktionierenden Methoden mache und später verbessere oder in anderen Projekten besser umsetze.
- LayoutManager:
Ich habe bis vor kurzem ein Layout verwendet, doch das wie schon gesagt die Buttons überschrieben worden sind habe ich es dann so gemacht das ich das Layout null gemacht habe und die Buttons dann direkt dem Frame hinzufüge, da ich so finde ich mehr Möglichkeiten habe und nicht an ein festes Layout gebunden bin.
-Zentrieren des Frames:
Danke, ich habe die neue Methode eingebaut, die ist wesentlich einfacher, ich hatte jedoch nur diese gefunden, bzw. dann nicht weiter gesucht ^^"
- Starten der main Methode:
Was bedeutet der Code?
Wie muss ich ihn verstehen?
Was bewirkt er?

Lösung:
Danke an alle die geantwortet haben!
Ich habe jetzt diese Methode verbaut:
[Java]startButton.setBounds(300, 180, 798, 80);
startButton.setIcon(new ImageIcon(Frame.class.getResource("/Images/startButton.png")));
startButton.setRolloverIcon(new ImageIcon(Frame.class.getResource("/Images/startButtonMouseOver.png")));
startButton.setBorderPainted(false);
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("klawdawd");
}
});[/Java]
Flown hatte gesagt das jeder Button auch einen eigenen ActionListener haben kann. Das hat mir wieder so ein wenig auf die Sprünge geholfen. Ich habe diese Methode schon mal im Internet gesehen, doch fand das ich insgesamt dann zu viel Code haben könnte, da ich für jeden Button dann erst das schreiben muss. Diese Methode funktioniert perfekt!
Danke für eure Hilfe!
 
Wenn man es gleich richtig programmiert ist das nur die Hälfte der Arbeit, dass kann ich dir versichern.

Das mit dem Starten meinte ich so. So läuft deine eigene Anwendung nicht direkt auf dem AWT Thread sondern in einem eigenen. Der Vorteil ist, dass man einfacher die GUI updaten kann (braucht man eher für Concurrency in Swing). Doch ist es nicht schlecht es gleich zu machen.

Java:
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class Test {
  
  public Test() {
    JFrame frame = new JFrame("Test");
    frame.setLocationByPlatform(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(new JLabel("Test"));
    frame.pack();
    frame.setVisible(true);
  }
  
  public static void main(String... args) {
    SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        new Test();
      }
    });
  }
}
 

Zurück
Oben