Stopping the window from displaying to complete drawing?

I am working on a Java program that accepts a large number of files (3000 max) with a corresponding array of 1/0. I currently have an array render where there is a grid where each cell is filled with black for 1 or white for 0. When drawing, it works well, but takes about a minute to load completely (and possibly locks the computer at that same time.) Is there a way I can: 1, not display the window until it finishes.

(i.e. JFrame create,

// draw window

frame.setVisible (true))

and 2, track the progress so I can use the progress bar with it?

edit: Can I start a thread to draw it and then just make a while loop to only display it after the thread finishes?

+1


source to share


2 answers


The example below SwingWorker

sets the pixels to BufferedImage

based on data read from a random file. Note what is Thread.sleep()

used to simulate latency; otherwise, it is not required. You can add JProgressBar

as shown here .

Is there a better way to get simple colored rectangles?

Yes. In the example below, each pixel represents one cell. For large margins, return multiple values ​​for the image size, eg.



@Override
public Dimension getPreferredSize() {
    return new Dimension(2 * N, 2 * N);
}

      

image

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;

/**
 * @see https://stackoverflow.com/a/25043676/230513
 */
public class WorkerTest {

    private static final int N = 256;
    private final BooleanPanel panel = new BooleanPanel();

    private class BooleanPanel extends JPanel {

        private BufferedImage image;

        public void setImage(BufferedImage bi) {
            this.image = bi;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.drawImage(image, 0, 0, getWidth(), getHeight(), null);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(N, N);
        }
    }

    private class BufferedImageWorker extends SwingWorker<BufferedImage, BufferedImage> {

        @Override
        protected BufferedImage doInBackground() throws Exception {
            BufferedImage image = new BufferedImage(N, N, BufferedImage.TYPE_INT_ARGB);
            try (DataInputStream dis = new DataInputStream(
                    new BufferedInputStream(new FileInputStream("/dev/random")))) {
                for (int row = 0; row < N; row++) {
                    for (int col = 0; col < N; col++) {
                        image.setRGB(col, row, dis.readByte() < 0 ? 0xffffffff : 0xff000000);
                    }
                    Thread.sleep(40); // ~25 Hz
                    publish(image);
                }
                return image;
            }
        }

        @Override
        protected void process(List<BufferedImage> list) {
            for (BufferedImage bi : list) {
                panel.setImage(bi);
                panel.repaint();
            }
        }
    }

    private void display() {
        JFrame f = new JFrame("WorkerTest");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(panel);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
        new BufferedImageWorker().execute();
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            new WorkerTest().display();
        });
    }
}

      

+3


source


In this case, I definitely used SwingWorker. Basically, maybe something along these lines (I'm not sure what type of object your "render" represents, so for simplicity I'll just say it as an image). You can add this at the bottom of your class. You will obviously have to edit it to make it work for you.

protected class DrawGridTask extends SwingWorker<Image, Object> {
    ObjectToPutImageOn imageObject;

    public DrawGridTask(ObjectToPutImageOn obj) {
        this.imageObject = obj;
    }
    protected Image doInBackground() {
        // generate your Image or graphic or whatever here
        return Image;
    }
    protected void done() {
        imageObject.drawThisCompletedImage(get());
    }
}

      

To call this method, you must run (new DrawGridTask (objectToPutImageOn)). execute ();



All the code in doInBackground () will run its own worker thread on it. Done () runs on the event dispatch thread and receives a doInBackground () reference returned when call () is called.

There is more information here, including how to do progress updates: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html

Since I mentioned Images, if you are working with them you can also take a look at the MediaTracker class, this can be very useful for blocking until the image is ready.

+1


source







All Articles