【问题标题】:Show custom loading dialog with gif用 gif 显示自定义加载对话框
【发布时间】:2016-12-21 17:30:13
【问题描述】:

我正在尝试让我的应用程序显示一个简单的加载对话框,以便用户知道时间密集型进程何时工作以及何时完成。我只是希望它使用我下载的 gif 显示一个简单的“加载”。我已经尝试过只使用文本,但它仍然不起作用。

我可以让对话框在我想要的时候显示(并消失),问题是显示后对话框(或框架)上不会显示任何内容。我尝试了许多不同的技术,都给出了相同的结果,一个空白对话框。

我终于创建了一个单独的类来显示对话框(加载 gif)并且我让它正确显示(单独),但是当我从我的主应用程序运行它时,它再次显示一个黑色对话框。我测试了将 gif 放入 JOptionPane 并且它可以工作,问题是我无法随意关闭它。

这是我的自定义代码。

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.xml.parsers.*;
import javax.xml.xpath.*;
import java.util.logging.*;
import org.w3c.dom.*;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import javax.swing.filechooser.FileNameExtensionFilter;

public class Loader implements Runnable  {

    final JFileChooser jfc = new JFileChooser();
    static JFrame frame = new JFrame();
    Frame parentUI = new  Frame();
    JDialog dialog = new JDialog();
    JLabel lbl_filename = new JLabel();
    JLabel lbl_path = new JLabel();

    static Loader load = new Loader(null);


    public static void main(String[] args) throws InterruptedException, InvocationTargetException {
        load.run();
        frame.setVisible(true);
    } 

    public Loader(Frame parent) {
        init();
        parentUI = parent;
    }

    @Override
    public void run() {
        createDialog(parentUI);
    }  

    public final void init() {
        JButton btn = new JButton("Open");

        frame.setTitle("Loader Test");
        frame.setSize(500, 200);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setLayout(new FlowLayout());

        btn.addActionListener(new Action1());

        frame.add(btn);
        frame.add(lbl_filename);
        frame.add(lbl_path);
    }

    class Action1 implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {

            openFile();
            load.Close();
        }
    }

    private void createDialog(final Frame parent) {

        dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        dialog.setTitle("Loader");

        URL url = this.getClass().getResource("/resource/loader.gif");
        Icon icon = new ImageIcon(url);
        JLabel label = new JLabel(icon);
        dialog.add(label);

        dialog.pack();
        dialog.setLocationRelativeTo(parent);
    }


    public void Show(Boolean visible) {
        this.run();
        dialog.setVisible(visible);
    }

    public void Close() {
        dialog.setVisible(false);
    }

    private void setJFCFilter(String file, String ext) {
        FileNameExtensionFilter filter = new FileNameExtensionFilter(file, ext);
        jfc.setFileFilter(filter);
    }

    private void openFile() {
        File default_dir = new File(".");
        jfc.setCurrentDirectory(default_dir);
        setJFCFilter("Scalable Vector Graphics", "svg");

        int returnVal = jfc.showOpenDialog(parentUI);

        if (returnVal == JFileChooser.APPROVE_OPTION) {
            String path = jfc.getSelectedFile().getAbsolutePath();
            String fileName = jfc.getSelectedFile().getName();

            lbl_filename.setText(fileName);
            lbl_path.setText(path);

            load.Show(true);
            createDoc(path);
            load.Close();

        }
    }

    private void createDoc(String file) {
        try {
            NodeList svgIDPaths;

            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(file);

            String xpathIDExp = "//g/@id";

            XPathFactory xpf = XPathFactory.newInstance();
            XPath xpath = xpf.newXPath();
            XPathExpression expression = xpath.compile(xpathIDExp);

            svgIDPaths = (NodeList)expression.evaluate(doc, XPathConstants.NODESET);

        } catch (Exception ex) {
            Logger.getLogger(Loader.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}  

编辑:使用此文件进行测试 -> svg_test.svg

我试过这样称呼它:

loader.show(true);

而且在它自己的线程中也是这样:

private void load(final Boolean visible) {
    Thread t = new Thread(new Runnable() {
        @Override
        public void run() {
            loader.show(visible);
        }
    });

    t.start();
}

这两种方法都不起作用并且给我相同的结果,一个空白对话框。我过去曾遇到过这个问题,但只是放弃并删除了它(加载对话框)。我已经用进度条和简单的文本尝试过,似乎没有任何效果。

我也在 JOptionPane 中尝试过它并且它有效,但这是不可取的(当我不想通过按钮单击时我想关闭/打开)。

 private void load() {
        ImageIcon icon = new ImageIcon(MainForm.class.getResource("/resource/loader.gif").getFile());
        JOptionPane.showMessageDialog(null, "Loading...", "Loader", JOptionPane.INFORMATION_MESSAGE, icon);
    }

我知道您不能在 EDT 上运行多个对话框并且必须使用单独的线程,但我使用的是单独的线程并且它不工作(它自己工作)。

(另请注意,我有一个主应用程序(框架)正在运行/打开第二个对话框)。

感谢任何帮助。

【问题讨论】:

  • 抱歉,忘记了。完成后我会更新。
  • 更新了,打开任何SVG文件都不行。
  • // Java OutOfMemory 是什么意思?
  • 另外,“ETF”是什么意思?您指的是 Swing EDT -- 事件调度线程吗?

标签: java swing


【解决方案1】:

您看起来有一个 Swing 线程问题,您在事件线程上有长时间运行的代码弄乱了图像的绘制,我猜测长时间运行的代码在您的 createDoc 方法中。考虑从后台线程调用它,例如从 SwingWorker 调用,并且仅在 worker 完成其工作后才在加载对象上调用 close。例如这样的:

class Action1 implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {

        openFile();
        // load.Close();  // get rid of this
    }
}

// .......

private void openFile() {

    // ....

    load.Show(true);  // load dialog on event thread

    new SwingWorker<Void, Void>() {
        protected Void doInBackground() throws Exception {
            createDoc(path);  // call this from background thread
            return null;
        };

        protected void done() {
            load.Close();  // only call this once createDoc has completed
            // probably should call get() in here to catch all exceptions
        };
    }.execute();
}

【讨论】:

  • 你是对的,包含“expression.evaluate”的行将 SVG 文档加载到需要一些加载的对象中(也可能到内存中)。这是加载对话框的原因。我会试试这个,看看它是否有效。
  • 另一个问题(一个小问题),我如何在模态对话框中使用它?我当前的对话框是非模态的,允许用户单击它并移动它。我希望它在加载时限制任何操作(以防止任何问题或问题)。我尝试在创建时将其设置为模态,但它只是挂断并且什么都不做。有什么建议吗?
  • @LloydSmith:确保在设置对话框可见之前 正确连接并运行所有内容。如果仍然有问题,请提出一个新问题,一个有效的minimal reproducible example,类似于上面的问题(尽管对于长时间运行的过程使用Thread.sleep)。
  • 您所说的“一切都正确连接”是什么意思?
  • 所有需要添加的监听器。了解所有来自调用代码的代码流在对话框设置为可见后都会停止,因此需要在此之前做好所有准备工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-04
  • 1970-01-01
  • 2012-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多