2016-07-24 28 views
0

Dieser Code ist ein einfacher Motor für ein Quiz-Spiel. Die Idee ist, dass die Antworten auf den JButtons angezeigt werden. Um dies zu tun, musste ich eine Aktualisierungsmethode einrichten, die alles löscht und neu zeichnet. Es scheint, dass jedes Mal, wenn diese Methode aufgerufen wird, es langsam wird. Es wird so langsam nach ungefähr 10 Knopfklicks, dass es nicht mehr reagiert und ich muss das Programm manuell beenden.Kleine Swing-Anwendung stürzt nach dem Klicken auf Schaltflächen mehrmals

Dank

package mainPackage; 

import java.awt.FlowLayout; 
import java.awt.Graphics; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.JButton; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 

public class MainGame{ 
    static JFrame frame; 
    static WindowComp w; 

    public static void main(String[] args) { 
     frame = new JFrame("Game"); 
     w = new WindowComp(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setSize(300, 300); 
     frame.setVisible(true); 
     frame.setResizable(true); 

     WindowComp.setAnswers("start", "start", "start", "start"); 
     WindowComp.refreshAll(w, frame); 

     WindowComp.setAnswers("final", "final", "final", "final"); 
     WindowComp.refreshAll(w, frame); 
    } 
} 

public class WindowComp extends JComponent implements ActionListener { 
    static JButton [] buttons = new JButton[4]; 
    static JLabel question = new JLabel("default"); 

    public WindowComp(){ 
     setAnswers("default", "default", "default", "default"); 
    } 

    public void paintComponent(Graphics g){ 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     if(e.getSource() == buttons[0]){ 
      setQuestion("button 1"); 
     } 
     if(e.getSource() == buttons[1]){ 
      setQuestion("button 2"); 
     } 
     if(e.getSource() == buttons[2]){ 
      setQuestion("button 3"); 
     } 
     if(e.getSource() == buttons[3]){ 
      setQuestion("button 4"); 
     } 
     refreshAll(MainGame.w, MainGame.frame); 
    } 

    public void addAll(){ 
     setLayout(new FlowLayout()); 
     buttons[0].addActionListener(this); 
     buttons[1].addActionListener(this); 
     buttons[2].addActionListener(this); 
     buttons[3].addActionListener(this); 
     add(buttons[0]); 
     add(buttons[1]); 
     add(buttons[2]); 
     add(buttons[3]); 
     add(question); 
    } 

    public static void setAnswers(String ans1, String ans2, String ans3,String ans4){ 
     buttons[0] = new JButton("Answer 1 : " + ans1); 
     buttons[1] = new JButton("Answer 2 : " + ans2); 
     buttons[2] = new JButton("Answer 3 : " + ans3); 
     buttons[3] = new JButton("Answer 4 : " + ans4); 
    } 

    public static void setQuestion(String q){ 
     question = new JLabel("Question: " + q); 
    } 

    public static void refreshAll(WindowComp w, JFrame frame){ 
     w.removeAll(); 
     w.addAll(); 
     w.revalidate(); 
     frame.add(w); 
    } 
} 
+1

Warum verwenden Sie nicht [Kartenlayout] (http://docs.oracle.com/javase/tutorial/uiswing/layout/card.html) es wurde gemacht, so dass Sie nicht entfernen müssen -> hinzufügen -> revalidate sich selbst. Probieren Sie es aus – Frakcool

+0

@krzyk (in der Hoffnung, dass Sie das sehen werden): Dies könnte die richtige Antwort gewesen sein. Erwähnenswert ist hier zumindest: Bei jedem Aufruf von 'refreshAll' fügen Sie den Schaltflächen Aktions-Listener hinzu. Nach ein paar Klicks haben die Schaltflächen Dutzende von Aktionshörern. Das könnte die Sache etwas durcheinander bringen. Ungeachtet dessen ist der Gesamtansatz nicht der beste, und Sie sollten z.B. ein 'CardLayout', wie Frakcool vorgeschlagen hat. – Marco13

+0

Die Anzahl der Listener wächst exponentiell. Ich habe es gerade ausprobiert. – mszymborski

Antwort

1

In Ordnung, wie in den Kommentaren erwähnt, fügen Sie zu viele ActionListeners hinzu, was zu dem von Ihnen beschriebenen Problem führt.

Im Folgenden werden einige Ratschläge, die ich Ihnen geben möchte.

Zunächst müssen Sie das Schlüsselwort new nicht jedes Mal verwenden, wenn Sie den Text der Schaltflächen ändern möchten. Garbage Collection wird nicht verwendete Schaltflächen los, aber warum möchten Sie neue Schaltflächen, statt nur den Text auf den Schaltflächen über setTest(String) aktualisieren, die keine Garbage Collection aufrufen würde.

Schließlich, versuchen Sie, den Konstruktor mehr zu verwenden, können Sie tatsächlich alles, was Sie brauchen (zumindest in diesem Fall nicht allgemein) lassen, wenn Sie den Konstruktor aufrufen. Als ein Beispiel können Sie alle JButtons im Konstruktor erstellen und alle Listener zu den Schaltflächen hinzufügen (ich werde etwas Code unten zur Verfügung stellen).

Ich habe deinen Code ein wenig umgeschrieben, er hat nicht die gleiche Funktionalität wie du, aber er stürzt auch nicht ab.

package de; 

import javax.swing.JFrame; 

public class MainGame{ 
static JFrame frame; 
static WindowComp w; 
public static void main(String[] args) { 
    frame = new JFrame("Game"); 
    w = new WindowComp(); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.setSize(300, 300); 
    frame.add(w); 
    frame.setVisible(true); 
    frame.setResizable(true); 
    /*WindowComp.setAnswers("start", "start", "start", "start"); 
    WindowComp.refreshAll(w, frame); 

    WindowComp.setAnswers("final", "final", "final", "final"); 
    WindowComp.refreshAll(w, frame);*/ 
} 

} 




package de; 

import java.awt.FlowLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.JButton; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 

@SuppressWarnings("serial") 
public class WindowComp extends JComponent implements ActionListener { 

static JButton [] buttons; 
static JLabel question; 

public WindowComp(){ 
    question = new JLabel("default"); 
    buttons = new JButton[4]; 
    setLayout(new FlowLayout()); 
    buttons[0] = new JButton("Answer 1 : " + "default"); 
    buttons[1] = new JButton("Answer 2 : " + "default"); 
    buttons[2] = new JButton("Answer 3 : " + "default"); 
    buttons[3] = new JButton("Answer 4 : " + "default"); 

    buttons[0].addActionListener(this); 
    buttons[1].addActionListener(this); 
    buttons[2].addActionListener(this); 
    buttons[3].addActionListener(this); 
    addAll(); 

} 


@Override 
public void actionPerformed(ActionEvent e) { 
    if(e.getSource() == buttons[0]){ 
     setQuestion("button 1"); 
     setAnswers("start", "start", "start", "start"); 
    } 
    if(e.getSource() == buttons[1]){ 
     setQuestion("button 2"); 
     setAnswers("final", "final", "final", "final"); 
    } 
    if(e.getSource() == buttons[2]){ 
     setQuestion("button 3"); 
    } 
    if(e.getSource() == buttons[3]){ 
     setQuestion("button 4"); 
    } 
    //refreshAll(MainGame.w, MainGame.frame); 

} 
public void addAll(){ 

    add(buttons[0]); 
    add(buttons[1]); 
    add(buttons[2]); 
    add(buttons[3]); 
    add(question); 

} 



public static void setAnswers(String ans1, String ans2, String ans3,String ans4){ 
    buttons[0].setText("Answer 1 : " + ans1); 
    buttons[1].setText("Answer 2 : " + ans2); 
    buttons[2].setText("Answer 3 : " + ans3); 
    buttons[3].setText("Answer 4 : " + ans4); 

} 

public static void setQuestion(String q){ 
    question.setText("Question: " + q); 
} 

public static void refreshAll(WindowComp w, JFrame frame){ 
    w.removeAll(); 
    w.addAll(); 
    w.revalidate(); 
    frame.add(w); 

} 

}

Edit: Was aktuelle Code geht, Ihre Funktion refreshAll(WindowComp w, JFrame frame) wird nicht mehr aufgerufen, weil es derzeit keine Notwendigkeit, es für den Aufruf. Ich habe es mit dieser Änderung auskommentiert, nachdem ich das Programm ohne den Anruf getestet habe.

+0

Müsste ich repaint() aufrufen? um den Schaltflächentext zu ändern? –

+0

Ich habe es getestet und nein, Sie müssen Repaint() nicht aufrufen. –

+0

danke! das funktioniert super. –

0

Ihr Problem ist, dass die ActionListeners immer auf die Tasten hinzugefügt werden, aber nie entfernt. Eine schnelle Lösung wäre es, ein Verfahren zu schreiben, sie zu entfernen:

public void removeActionListeners(){ 
     buttons[0].removeActionListener(this); 
     buttons[1].removeActionListener(this); 
     buttons[2].removeActionListener(this); 
     buttons[3].removeActionListener(this); 
} 

Und es dann in Ihrem Anruf „Refreshall()“:

public static void refreshAll(WindowComp w, JFrame frame){ 
     w.removeActionListeners(); 
     w.removeAll(); 
     w.addAll(); 
     w.revalidate(); 
     frame.add(w); 
} 

... wie bereits erwähnt ist dies nicht der beste Weg, dies zu tun, aber es nicht mehr aushält.