【问题标题】:Can't repaint a JPanel while my program is busy我的程序忙时无法重绘 JPanel
【发布时间】:2015-05-03 02:24:33
【问题描述】:

我正在尝试对算法进行可视化。我有一个工作程序,但它真的很脏,我决定在继续之前重新组织它。问题是在算法完成之前它不会再重新绘制。 (我尝试过使用 revalidate 来代替/结合 repaint)

选项菜单:

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

图形用户界面:

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

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

【问题讨论】:

  • 我建议在不使用 SwingWorker 的情况下不要做任何繁重的工作

标签: java swing paintcomponent repaint


【解决方案1】:

也许采取这样的方法。这将在 Event Dispatch Thread 的工作线程中完成所有计算和工作,然后调用 done() ,您可以在 Event Dispatch Thread 上进行 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;
    }
}

【讨论】:

    【解决方案2】:

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

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

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

    一种方法是使用Swing Worker,它在单独的线程上执行,并允许您在算法执行时“发布”结果。

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

    【讨论】:

      猜你喜欢
      • 2016-04-20
      • 1970-01-01
      • 2022-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-23
      • 2012-10-05
      相关资源
      最近更新 更多