简体   繁体   English

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

[英]Can't repaint a JPanel while my program is busy

I'm trying to make a visualization of algorithms. 我正在尝试使算法可视化。 I had a working program, but is was really dirty and I decided to re-orgranize it before I continued. 我有一个工作程序,但是真的很脏,我决定在继续之前重新组织它。 The problem is that it won't repaint anymore before the algorithm finishes. 问题在于它不会在算法完成之前重新绘制。 (and I have tried using revalidate instead/in combination with repaint) (并且我尝试使用revalidate代替/与repaint结合使用)

The option menu: 选项菜单:

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

The main algorithm stuffs: 主要算法资料:

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

The GUI: 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)
}
}

When I put System.out.println("1") before the repaint() call, System.out.println("2") in the paintComponent() function and System.out.println("3") after the repaint() call it will only print: 1 3 1 3 1 3 ... I also tried printing the stack, didn't get anything usefull from that either. 当我在repaint()调用之前放置System.out.println(“ 1”)时,paintComponent()函数中的System.out.println(“ 2”)和重绘之后的System.out.println(“ 3”) ()调用它只会打印:1 3 1 3 1 3 ...我也尝试打印堆栈,也没有得到任何有用的信息。 The program does repaint when the algorithm is done, but that isn't usefull to me. 算法完成后,程序确实会重新绘制,但这对我没有用。

Maybe take an approach like this. 也许采取这样的方法。 This will do all your calculations and stuff in a worker thread off the Event Dispatch Thread, and then call done() where you can do you GUI updates on the 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;
    }
}

The problem is that it won't repaint anymore before the algorithm finishes. 问题在于它不会在算法完成之前重新绘制。

Your algorithm is executing on the Event Dispatch Thread (EDT) which is the Thread the GUI uses to paint itself, therefore the GUI can't repaint itself until the algorithm is finished. 您的算法在Event Dispatch Thread (EDT)分配Event Dispatch Thread (EDT) ,该线程是GUI用来绘制自身的线程,因此,在算法完成之前,GUI不能重新绘制自身。

The solution is to use a separate Thread for the algorithm. 解决方案是对算法使用单独的线程。

One way to do this is to use a Swing Worker which executes on a separate Thread and allows you to "publish" results as the algorithm is executing. 一种方法是使用Swing Worker ,该Swing Worker在单独的线程上执行,并允许您在算法执行时“发布”结果。

Read the section from the Swing tutorial on Concurrency for more details. 阅读Swing 并发教程中的这一节以获取更多详细信息。 The tutorial has a Swing Worker example. 本教程有一个Swing Worker示例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM