【问题标题】:Stopping a window from displaying till it is fully drawn?停止显示窗口直到完全绘制?
【发布时间】:2014-07-30 14:37:36
【问题描述】:

我正在开发一个 Java 程序,该程序接收大量文件(最大 3000 个)以及关联的 1/0 数组。目前我有一个数组的可视化,其中有一个网格,其中每个框都用黑色填充 1 或白色填充 0。绘制时它运行良好,但需要大约一分钟才能完全加载(同时可能会锁定计算机。 ) 有什么办法可以:1、在窗口完成之前不显示窗口

(即创建JFrame,

//绘制窗口

frame.setVisible(true))

还有2,跟踪进程的进度,以便我可以使用进度条吗?

编辑:我可以运行一个线程来绘制它,然后简单地创建一个 while 循环以仅在线程完成后显示它吗?

【问题讨论】:

  • 听起来你需要做一些线程。循环摆动工人。 (我相信这就是它的名字)
  • 使用SwingUtilities.invokeLater()EventQueue.invokeLater() 来确保EDT 被正确初始化,但不要在其中调用任何重载方法。
  • 我对此很熟悉,并打算试一试,但我认为它不会解决它进行如此长时间的框架设置的问题。线程不是意味着GUI不会锁定吗?我仍然会遇到页面在加载时可见的问题(并导致系统出现问题>)

标签: java swing


【解决方案1】:

在下面的示例中,SwingWorker 根据从随机文件中读取的数据设置BufferedImage 中的像素。注意Thread.sleep()是用来模拟延迟的;否则不需要。您可以添加JProgressBar,如图所示here

有没有更好的方法来获得简单的彩色框?

是的。在下面的示例中,每个像素代表一个单元格。对于较大的框,返回图像大小的倍数,例如

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

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

【讨论】:

    【解决方案2】:

    在这种情况下,我肯定会使用 SwingWorker。基本上,也许是这样的(我不确定你的“可视化”是什么类型的对象,所以为了简单起见,我只会说它是一个图像)。您可以将其添加到课程的底部。您显然必须对其进行编辑以使其适合您。

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

    要调用此方法,您将运行 (new DrawGridTask(objectToPutImageOn)).execute();

    doInBackground() 中的所有代码都将在它自己的工作线程上运行。 Done() 在事件派发线程上运行,并在调用 get() 时获取 doInBackground() 返回的引用。

    这里有更多信息,包括如何进行进度更新:http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html

    由于我提到了图像,如果您确实使用它们,您可能还想看看 MediaTracker 类,这对于在图像准备好之前阻止非常有用。

    【讨论】:

    • 我会试一试,我有一些摇摆工人的经验,所以应该直截了当。另一方面,我通过使用带有文本框的网格布局来创建我的彩色框,我只是将其设置为黑色背景。有没有更好的方法来获得简单的彩色盒子?我尝试了标签,但系统无法处理那么多(30,000 个)。
    猜你喜欢
    • 1970-01-01
    • 2015-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-25
    • 1970-01-01
    • 1970-01-01
    • 2016-10-30
    相关资源
    最近更新 更多