如何使用动态消息显示忙/工作/加载对话框

时间:2012-01-17 14:00:59

标签: java multithreading swing jdialog

我想显示模态对话框,它将阻止我的主窗口,我想通过方法showLoadingDialog(),hideLoadingDialog()和setLoadingMessage(字符串消息)从外部控制它 - 我尝试了这段代码,但它没有工作 - 加载对话框可见,但没有消息

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class LoadingExample {


private static class LoadingDialog extends JDialog {

private JLabel label = new JLabel("working");

public LoadingDialog(JFrame owner) {

    super(owner, ModalityType.APPLICATION_MODAL);

    setUndecorated(true);
    add(label);
    pack();

    // move window to center of owner
    int x = owner.getX()
        + (owner.getWidth() - getPreferredSize().width) / 2;
    int y = owner.getY()
        + (owner.getHeight() - getPreferredSize().height) / 2;
    setLocation(x, y);



    repaint();


}

public void setMessage(String message) {
    label.setText(message);
}


}



private static LoadingDialog loadingDialog;


public static void main(String[] args) {


final JFrame mainWindow = new JFrame("Main frame");
mainWindow.setLayout(new GridLayout(3, 3));


for (int i = 1; i <= 9; i++) {

    final int workTime = i;

    JButton workButton = new JButton("work for " + i + " second");

    //action listener, which had to show loading dialog and countdown seconds before finish
    workButton.addActionListener(new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent e) {

        showLoadingDialog(mainWindow);

        for (int j = 0; j < workTime; j++)
        try {

            // ... do some work here

            setLoadingMessage("remain " + (workTime - j)
                + " second(s)");
            loadingDialog.repaint();
            Thread.sleep(1000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }

        hideLoadingDialog();
    }
    });


    mainWindow.add(workButton);

}

mainWindow.pack();
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setLocationRelativeTo(null);



mainWindow.setVisible(true);

}




public static void showLoadingDialog(JFrame owner) {
if (loadingDialog != null)
    loadingDialog.dispose();



loadingDialog = new LoadingDialog(owner);

new Thread() {
    @Override
    public void run() {
    loadingDialog.setVisible(true);
    };
}.start();

}

public static void setLoadingMessage(String message) {
loadingDialog.setMessage(message);
}


public static void hideLoadingDialog() {

if (loadingDialog != null) {
    loadingDialog.setVisible(false);
    loadingDialog.dispose();
    loadingDialog = null;
}


}

}

import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; public class LoadingExample { private static class LoadingDialog extends JDialog { private JLabel label = new JLabel("working"); public LoadingDialog(JFrame owner) { super(owner, ModalityType.APPLICATION_MODAL); setUndecorated(true); add(label); pack(); // move window to center of owner int x = owner.getX() + (owner.getWidth() - getPreferredSize().width) / 2; int y = owner.getY() + (owner.getHeight() - getPreferredSize().height) / 2; setLocation(x, y); repaint(); } public void setMessage(String message) { label.setText(message); } } private static LoadingDialog loadingDialog; public static void main(String[] args) { final JFrame mainWindow = new JFrame("Main frame"); mainWindow.setLayout(new GridLayout(3, 3)); for (int i = 1; i <= 9; i++) { final int workTime = i; JButton workButton = new JButton("work for " + i + " second"); //action listener, which had to show loading dialog and countdown seconds before finish workButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { showLoadingDialog(mainWindow); for (int j = 0; j < workTime; j++) try { // ... do some work here setLoadingMessage("remain " + (workTime - j) + " second(s)"); loadingDialog.repaint(); Thread.sleep(1000); } catch (InterruptedException e1) { e1.printStackTrace(); } hideLoadingDialog(); } }); mainWindow.add(workButton); } mainWindow.pack(); mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mainWindow.setLocationRelativeTo(null); mainWindow.setVisible(true); } public static void showLoadingDialog(JFrame owner) { if (loadingDialog != null) loadingDialog.dispose(); loadingDialog = new LoadingDialog(owner); new Thread() { @Override public void run() { loadingDialog.setVisible(true); }; }.start(); } public static void setLoadingMessage(String message) { loadingDialog.setMessage(message); } public static void hideLoadingDialog() { if (loadingDialog != null) { loadingDialog.setVisible(false); loadingDialog.dispose(); loadingDialog = null; } } }

感谢任何建议

2 个答案:

答案 0 :(得分:0)

您不能从与您尝试更改的控件关联的调度程序线程之外的其他线程更改GUI。要正确执行此操作,您可以使用SwingUtilities.InvokeLater

new Thread() {
    @Override
    public void run() {

       SwingUtilities.InvokeLater(new Runnable() {
           public void run() {
              loadingDialog.setVisible(true);
           }
       });

    };
}.start();

答案 1 :(得分:0)

我想编写一些示例代码,但在启动我的IDE之前,我在优秀的Swing concurrency tutorial中进行了一次小搜索,并且它包含了您正在寻找的示例代码。你拥有的是'task that has interim results'。因此,当您有中间结果时,可以调用SwingWorker#publish方法。在SwingWorker#process方法中,使用刚刚发布的新消息更新模式对话框。 SwingWorker#done方法允许您在之后删除模式对话框。

但我建议你从头到尾阅读整个并发教程,因为你的示例代码显示你缺少一些基本的Swing线程知识。