小摆动应用程序多次单击按钮后崩溃

问题描述:

此代码是琐事游戏的简单引擎。这个想法是,答案显示在JButton上。为此,我必须设置一个刷新方法,删除所有内容并重新绘制它。似乎每次调用这个方法时,它都会变得越来越慢。点击10次左右后,它会变得很慢,它会停止响应,我将不得不手动关闭程序。小摆动应用程序多次单击按钮后崩溃

感谢

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

为什么不使用[卡布局(http://docs.oracle.com/javase/tutorial/uiswing/layout/card.html)它,这样你就不必去掉 - >添加 - >重新验证自己。试一试 – Frakcool

+0

@krzyk(希望你会看到这个):这可能是正确的答案。至少在这里值得一提的是:每次调用'refreshAll'时,都会将操作侦听器添加到按钮中。点击几下后,按钮就会有数十个动作监听器。这可能会搞砸一点。不管如何,总体方法并不是最好的,你应该考虑像Frakcool建议的那样,一个CardLayout。 – Marco13

+0

听众的数量呈指数增长。我刚刚尝试过。 – mszymborski

好的,如评论所说,你加了太多的ActionListeners,这会导致您所描述的问题。

下面会有一些意见,我想给你。

首先,你不必使用要更改按钮的文本关键字new每次。垃圾收集将摆脱不使用的按钮,但为什么你想要新的按钮,而不是通过setTest(String)更新按钮上的文本,这将不会调用任何垃圾收集。

最后,尽量使用构造比较多,可以居然让你需要的一切(ATLEAST在这种情况下,一般不)来调用构造函数时创建的。作为一个例子,你可以在构造函数中创建所有JButton,并将所有监听器添加到按钮中(我将在下面提供一些代码)。

我改写了你的代码一点点,它不会有你有相同的功能,但它也不会崩溃。

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); 

} 

}

编辑:至于当前的代码去,你的功能refreshAll(WindowComp w, JFrame frame)不再被调用,因为目前还没有必要调用它。在没有调用的情况下测试程序后,我用这个编辑来评论它。

+0

我需要调用repaint()吗?让按钮文字改变? –

+0

我测试了它,不用你不必调用repaint()。 –

+0

谢谢!这很好。 –

你的问题是的ActionListeners总是添加到按钮,但永远不会被删除。一个快速的解决将是写一个方法将其删除:

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

然后调用它在你的“refreshAll()”:

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

...如已指出,这是不这样做的最好方法,但它不会再滞后。