我想在一个C/S方式的客户端实现一种效果,就是当客户端与服务器传输数据(数据量很大)时,会弹出一个窗口告诉用户“正在传输数据”,否则客户端传数据时程序就很锁死了一样。这是例子代码。
所有代码一起放在一个名为TestWaitWindow.java文件中即可。import javax.swing.*;
import java.awt.*;
import java.awt.event.*;public class TestWaitWindow {
    public static void main(String[] args) {
        JFrame j = new JFrame();
        Dimension scmSize = Toolkit.getDefaultToolkit().getScreenSize();
        int imgWidth = 400;
        int imgHeight = 300;
        j.setLocation(scmSize.width / 2 - (imgWidth / 2),
                         scmSize.height / 2 - (imgHeight / 2));
        j.setSize(imgWidth, imgHeight);
        JButton btn = new JButton("连接");
        btn.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                Connector.asyncConnect();  // 这种方式调用只能显示窗口底色
            }
        });
        Container c = j.getContentPane();
        c.setLayout(new FlowLayout());
        c.add(btn);
        j.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        j.setVisible(true);
        Connector.asyncConnect();  // 这种方式调用可以正常显示
        Connector.asyncConnect();  // 这种方式调用可以正常显示
    }
}/**
 * 用于和远程服务器通信的连接器
 * @author Zn(CN)2
 */
class Connector
{
    /**
     * 等待窗口
     * @author Zn(CN)2
     */
    private static class WaitingWindow extends JDialog
    {
        public void paint(Graphics g) {
            System.out.println(Thread.currentThread().getName());
            System.out.println("------painting---------");
            g.setFont(new Font("宋体", Font.PLAIN, 25));
            g.setColor(Color.white);
            g.drawString("请稍等,正在传输数据...",0,100);
        }        public WaitingWindow()
        {
            this.setTitle("请稍等...");
            this.setModal(true);
            this.setUndecorated(true);
            this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
            Toolkit toolkit = Toolkit.getDefaultToolkit();
            Dimension scmSize = toolkit.getScreenSize();
            int w = 300;
            int h = 200;
            this.setLocation(scmSize.width / 2 - (w / 2),
                scmSize.height / 2 - (h / 2));
            this.setSize(w, h);
            this.setBackground(new Color(163,169,219));
        }        public String connect() throws Exception{
            try{
                new Thread(){
                    public void run(){
                        WaitingWindow.this.toFront();
                        WaitingWindow.this.setVisible(true);
                    }
                }.start();
                Thread.currentThread().sleep(3000);  // 模拟与远程数据库通信
                return "结果";
            }catch(Exception ex){
                throw ex;
            }finally{
                this.toHide();
            }
        }        private void toHide(){
            this.toBack();
            this.setVisible(false);
            this.dispose();
        }
    }
    private static WaitingWindow w = new WaitingWindow();
    public static void asyncConnect()
    {
        System.out.println("调用者:"+Thread.currentThread().getName());
        try{
            w.connect();
        }catch(Exception ex){
            JOptionPane.showMessageDialog(null, "错误");
        }
    }
}弹出窗口使用模态JDialog。
问题就是main中调用连接函数可以正常显示,但在按钮事件处理函数中调用却只能显示出窗口底色,其上的文字根本显示不出来,这时paint都没被调用。
我用了各种方法,包括validate、invalidate、repaint,可就是不行。希望哪位大侠帮忙解决一下。

解决方案 »

  1.   

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;public class Test extends JFrame 
    {
    public Test()
    {
    super();
            JButton btn = new JButton("连接");
            setSize(400, 300);
            btn.addActionListener(new ActionListener(){
                public void actionPerformed(ActionEvent e){
                    new A().start();;  // 这种方式调用只能显示窗口底色
                }
            });
            setLayout(new FlowLayout());
            add(btn);
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setVisible(true);
            new A().start();
    }
        public static void main(String[] args) {
            new Test();
        }
    }
    class A extends Thread
    {
    public void run()
    {
    try {
    WaitingWindow w=new WaitingWindow();
    sleep(5000);
    w.dispose();
        }
        catch (Exception ex) {
         ex.printStackTrace();
        }
    }
    }class WaitingWindow extends JDialog
    {
        public WaitingWindow()
        {
         setTitle("wait...");
    //setModal(true);
            setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
            setSize(200, 100);
            JLabel label=new JLabel("接收数据中, 请稍侯...");
    add(label);
            setBackground(new Color(163,169,219));
            setVisible(true);
        }
    }好像还是有问题,那个setModal(true);一旦用上后,JDialog窗口就不会关闭,也就是说那个线程不起作用了,不过如果不用模态显示的话,就没有问题了,可能那个模态显示和线程之间有点冲突吧。
      

  2.   

    这种方式的确可以,但我要的不是这种方式。
    我的应用是这样的:
    一个JTable显示一堆数据,上面有翻页之类的按钮。
    用户点击翻页按钮时,开始与远程服务器通信,接收到数据后将界面更新。
    与服务器通信时传输数据时我不想让用户作任何操作,干等着就行了,可是如果响应事件时新开线程来实现就意味着用户点击按钮后还可以作其它操作,我不想要这种效果,所以我才使用的是“模态对话框”。因为模态对话框出现时除了对话框之外用户无法点击任何其它组件,但由于对话框没有关闭按钮,用户只能干等,直到数据传输成功。
    由于模态对话框一旦setVisible(true),代码就不往下走了,所以我在原程序里新开了一个线程来将对话框setVisible(true)。我现在只现在原来代码的基础上改,不想再多开线程,或用同步互斥机制之类的东西。哪位高人找到解决办法了吗?
      

  3.   

    是不是因为处理线程是消息队列线程,而重绘消息也需要排队?像这样:消息队列头指针 -->  用户点击按钮事件(与服务器通信)  --->  重绘事件  ---> 其他事件由于通信导致消息处理线程一直停滞在点击按钮事件上,而重绘事件永远得不到处理,直到通信完毕,但此时窗口已关闭,重绘无用?
      

  4.   

    My God,好像还真是这样。
    我在通信最后新开了一个线程,让它等待3秒后再关闭窗口,而不让事件处理线程去关闭窗口。结果点击按钮后,前3秒只显示底色,3秒后(通信完毕),窗口正常显示(包括文字),然后3秒后再关闭窗口。import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;public class TestWaitWindow {
        public static void main(String[] args) {
            JFrame j = new JFrame();
            Dimension scmSize = Toolkit.getDefaultToolkit().getScreenSize();
            int imgWidth = 400;
            int imgHeight = 300;
            j.setLocation(scmSize.width / 2 - (imgWidth / 2),
                             scmSize.height / 2 - (imgHeight / 2));
            j.setSize(imgWidth, imgHeight);
            JButton btn = new JButton("连接");
            btn.addActionListener(new ActionListener(){
                public void actionPerformed(ActionEvent e){
                    Connector.asyncConnect();  // 这种方式调用只能显示窗口底色
                }
            });
            Container c = j.getContentPane();
            c.setLayout(new FlowLayout());
            c.add(btn);
            j.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            j.setVisible(true);
            Connector.asyncConnect();  // 这种方式调用可以正常显示
            Connector.asyncConnect();  // 这种方式调用可以正常显示
        }
    }/**
     * 用于和远程服务器通信的连接器
     * @author Zn(CN)2
     */
    class Connector
    {
        /**
         * 等待窗口
         * @author Zn(CN)2
         */
        private static class WaitingWindow extends JDialog
        {
            public void paint(Graphics g) {
                System.out.println(Thread.currentThread().getName());
                System.out.println("------painting---------");
                g.setFont(new Font("宋体", Font.PLAIN, 25));
                g.setColor(Color.white);
                g.drawString("请稍等,正在传输数据...",0,100);
            }        public WaitingWindow()
            {
                this.setTitle("请稍等...");
                this.setModal(true);
                this.setUndecorated(true);
                this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
                Toolkit toolkit = Toolkit.getDefaultToolkit();
                Dimension scmSize = toolkit.getScreenSize();
                int w = 300;
                int h = 200;
                this.setLocation(scmSize.width / 2 - (w / 2),
                    scmSize.height / 2 - (h / 2));
                this.setSize(w, h);
                this.setBackground(new Color(163,169,219));
            }        public String connect() throws Exception{
                try{
                    new Thread(){
                        public void run(){
                            WaitingWindow.this.toFront();
                            WaitingWindow.this.setVisible(true);
                        }
                    }.start();
                    Thread.currentThread().sleep(3000);  // 模拟与远程数据库通信
                    
                    // 新开一个线程负责3秒后关闭窗口
                    new Thread(){
                        public void run(){
                            try{
                                Thread.currentThread().sleep(3000);
                            }catch(Exception ex){}
                            WaitingWindow.this.toHide();
                        }
                    }.start();
                    return "结果";
                }catch(Exception ex){
                    throw ex;
                }finally{
    //                this.toHide();
                }
            }        private void toHide(){
                this.toBack();
                this.setVisible(false);
                this.dispose();
            }
        }
        private static WaitingWindow w = new WaitingWindow();
        public static void asyncConnect()
        {
            System.out.println("调用者:"+Thread.currentThread().getName());
            try{
                w.connect();
            }catch(Exception ex){
                JOptionPane.showMessageDialog(null, "错误");
            }
        }
    }这么看来只能新开线程了
    唉,那得改多少代码啊,看来以后得注意了。