我的程序繁忙时无法重新绘制JPanel

时间:2015-03-02 16:32:03

标签: java swing paintcomponent repaint

我正在尝试对算法进行可视化。我有一个工作计划,但是真的很脏,我决定在继续之前重新粉碎它。问题是它在算法完成之前不再重新绘制。 (我尝试使用revalidate代替/与重绘相结合)

选项菜单:

public class BootScreen extends JPanel implements ActionListener {

GridBagConstraints c = new GridBagConstraints();

JFrame frame = new JFrame();

SpinnerNumberModel arraySizeModel = new SpinnerNumberModel(50, 0, 100000, 1);
SpinnerNumberModel speedModel = new SpinnerNumberModel(20, 0, 10000, 1);
SpinnerNumberModel algSelectModel = new SpinnerNumberModel(1, 1, 5, 1);

JSpinner arraySizeSpinner = new JSpinner(arraySizeModel);
JSpinner speedSpinner = new JSpinner(speedModel);
JSpinner algSelectSpinner = new JSpinner(algSelectModel);

JButton start = new JButton("Start");

BootScreen() {
    frame.setTitle("Settings");
    frame.setSize(500, 250);
    frame.setVisible(true);
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.add(this);

    //just creating the options menu, nothing special here (deleted for simplicity)
    //...
}

@Override
public void actionPerformed( ActionEvent e ) {
    Algorithm alg = new Algorithm(Integer.parseInt(arraySizeModel.getValue().toString()), Integer.parseInt
            (speedModel.getValue().toString()));

    switch(Integer.parseInt(algSelectModel.getValue().toString())) {
        case 1:
            alg.alg1();
            break;

        case 2:
            alg.alg2();
            break;

        case 3:
            alg.alg3();
            break;

        case 4:
            alg.alg4();
            break;

        case 5:
            alg.alg5();
            break;
    }
}

public static void main(String[] Args) {new BootScreen();}
}

主要算法的东西:

public class Algorithm {
int[] A;
GUI gui;
int type;
int[] pointers;
int delay;
int max;

Random r = new Random();

Algorithm( int arraySize, int delaySet) {
    A = new int[arraySize];
    delay = delaySet;
    gui = new GUI(this);
}

void generate(int maxIntSize, int pointersAmount, int typeSet) {
    max = maxIntSize;
    for( int i = 0; i < A.length; i++ ) {
        A[i] = r.nextInt(max);
    }

    pointers = new int[pointersAmount];
    for( int i = 0; i < pointers.length; i++ ) {
        pointers[i] = -1;
    }
    type = typeSet;
}

void step(boolean sleep, int updatePointer, int updatePointerVal) {
    pointers[updatePointer] = updatePointerVal;
    gui.revalidate();
    gui.repaint();
    if( sleep ) {
        try {
            Thread.sleep(delay);
        }catch( InterruptedException e ) {
        }
    }
}

//alg1(), alg2(), .... would be here. They first call generate() and call step() a couple of times. (deleted for simplicity)
}

GUI:

public class GUI extends JPanel {
JFrame frame = new JFrame();
Algorithm alg;

GUI( Algorithm algIn ) {
    alg = algIn;

    frame.setTitle("Algorithmizer");
    frame.setSize(1080, 720);
    frame.setExtendedState(Frame.MAXIMIZED_BOTH);
    frame.setVisible(true);
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.add(this);
}

@Override
protected void paintComponent( Graphics g ) {
    super.paintComponent(g);
    //drawing alg.A as a bar-graph by looping through it (deleted for simplicity)
}
}

当我在repaint()调用之前放入System.out.println(“1”)时,paintComponent()函数和System.out.println(“3”)中的System.out.println(“2”)在repaint()调用之后它只会打印: 1 3 1 3 1 3 ... 我也试过打印堆栈,也没有得到任何有用的东西。 算法完成后程序会重新绘制,但这对我没用。

2 个答案:

答案 0 :(得分:0)

也许采取这样的方法。这将在Event Dispatch Thread的一个工作线程中进行所有计算和填充,然后调用done(),您可以在事件调度线程上进行GUI更新。

@Override
public void actionPerformed( ActionEvent e ) {
    new SwingWorker<Object, Object>() {
            @Override
            protected Object doInBackground() throws Exception {
                runAlg();
                return null
            }

            @Override
            protected void done() {
                //any of you gui stuff here
            }
        }.execute();
    }
}

public void runAlg(){
     Algorithm alg = new Algorithm(Integer.parseInt(arraySizeModel.getValue().toString()), Integer.parseInt
            (speedModel.getValue().toString()));

    switch(Integer.parseInt(algSelectModel.getValue().toString())) {
        case 1:
            alg.alg1();
            break;

        case 2:
            alg.alg2();
            break;

        case 3:
            alg.alg3();
            break;

        case 4:
            alg.alg4();
            break;

        case 5:
            alg.alg5();
            break;
    }
}

答案 1 :(得分:0)

  

问题是它在算法完成之前不再重新绘制。

您的算法正在Event Dispatch Thread (EDT)执行,这是GUI用于绘制自身的线程,因此GUI无法重新绘制,直到算法完成。

解决方案是为算法使用单独的线程。

执行此操作的一种方法是使用在单独的线程上执行的Swing Worker,并允许您发布&#34;算法正在执行的结果。

阅读Concurrency上Swing教程中的部分以获取更多详细信息。本教程有一个Swing Worker示例。