contentpane.removeAll不会删除JPanel

时间:2017-01-02 15:26:53

标签: java swing concurrency jframe jpanel

当按下该按钮时,我有一个带开始按钮的JPanel,它通过mainFrame调用控制器中的start()函数

public void actionPerformed(ActionEvent e) {
    // TODO Auto-generated method stub
    if (e.getSource().equals(start)) {
        System.out.println("hi");
        try {
            f.c.start();
        } catch (KludgeException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

    }
}

start()函数调用askQuesions()函数,循环问题为它们创建一个问题面板并存储答案。

public void start() throws KludgeException{
    System.out.println("start");
    askQuestions();
    ConductInference();
}

 public void askQuestions() throws KludgeException {
    QuestionsPanel qp = new QuestionsPanel(main);
    for(data.containers.Question q : kludge.getQuestions()){
        qp.addQuestion(q.getQuestion(), q.getType());
        main.setPanel(qp);
        synchronized(this){
            while(!next){
                try {
                    wait();
                    kludge.setSystemValue(q.getValueName(), v);
                    //System.out.println("waitOver");
                }   catch (InterruptedException e) {}
            }
        }
        next = false;
        //System.out.println("next question");
    }
    System.out.println("questions over;");
}

这是mainFrame中的一个函数,它是一个JFrame,它设置了必要的面板。

public void setPanel(JPanel p){
    main.getContentPane().removeAll();
    main.getContentPane().add(p);
    main.validate();
    System.out.println("all removed, added and validated");
}

我的问题是这个...当按下stat按钮时程序卡在startPanel上它会冻结。如果我跳过整个startPanel并告诉它直接回答问题它可以正常工作。但我仍然不希望它直接回答问题。由于某种原因,它在问题面板之间切换正常,但不在startPanel和questionPanels之间切换..

1 个答案:

答案 0 :(得分:1)

您遇到了并发问题,并且正在Swing事件线程上调用长时间运行的代码,这个问题将阻止此线程执行其重要的工作,例如绘制GUI并与用户交互。解决方案是在后台线程中执行长时间运行的代码,例如SwingWorker提供的代码。那并阅读Swing并发:Lesson: Concurrency in Swing

好的,我现在确定我的原始建议 - 使用后台线程 - 是错误的,相反,您使用while循环,同步块和等待。是的,这些都阻止了事件线程,是的,这会阻碍你的应用程序,使其冻结并变得完全没有响应,但解决方案不是使用后台线程,而是你想要摆脱while (true)循环,同步块和wait()调用,并在其位置使用事件侦听器和回调方法。确切的接线将取决于我们尚未知道的代码,但这是该问题的解决方案。例如,问题面板可以通知控件类已经回答了问题,以更改模型的状态,以便它继续进行下一个问题。然后模型会更改,这可以通知视图它必须自行更新,现在显示下一个问题。

附注:

  • 您最好使用CardLayout交换视图,然后直接交换它们。可以在此处找到该教程:CardLayout tutorial

  • 关于:main.setPanel(qp);
    您似乎在for循环中将QuestionPanel重新添加到main。如果是这样,您只需要添加一次即可。