等待光标并禁用java应用程序

时间:2012-01-31 02:34:57

标签: java swing cursor glasspane busy-cursor

我想让用户按下按钮开始后台线程。

当线程处理时,我想要发生两件事:

1)应显示WAIT_CURSOR。

2)应用程序不应响应鼠标事件。

根据setCursor documentation“当此组件的contains方法对当前光标位置返回true时,将显示此光标图像,并且此Component可见,可显示和启用。”。

我希望在后台线程正在处理时禁用我的应用程序。

如何获得我想要的功能?

import java.awt.Component;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class WaitCursor extends JFrame
{
    private static final long    serialVersionUID    = 1L;

    public WaitCursor()
    {
        setResizable(false);

        setName(getClass().getSimpleName());
        setTitle("My Frame");
        setSize(300, 300);

        getContentPane().add(new MyButtonPanel());

    }

    private class MyButtonPanel extends JPanel
    {

        private static final long    serialVersionUID    = 1L;

        public MyButtonPanel()
        {
            JButton btnStart = new JButton("Start");
            btnStart.addActionListener(new BtnStartActionListener());
            add(btnStart);
        }

        private class BtnStartActionListener implements ActionListener
        {
            public void actionPerformed(ActionEvent e)
            {
                // Change to WAIT_CURSOR
                Component root = SwingUtilities.getRoot((JButton) e.getSource());
                JOptionPane.showMessageDialog(root, "Wait 10 seconds");
                root.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

                // TODO: Disabling the root component prevents the WAIT_CURSOR from being displayed
                root.setEnabled(false);
                new Thread(new TimeKiller(root)).start();
            }
        }
    }

    private class TimeKiller implements Runnable
    {
        Component    _root;

        public TimeKiller(Component root)
        {
            _root = root;
        }

        public void run()
        {
            try
            {
                Thread.sleep(10 * 1000);
            }
            catch (InterruptedException e)
            {
                // Ignore it
            }
            // Change back to DEFAULT CURSOR
            JOptionPane.showMessageDialog(_root, "Done waiting");
            _root.setCursor(Cursor.getDefaultCursor());
            _root.setEnabled(true);
        }
    }

    private static void createAndShowGUI()
    {
        // Create and set up the window.
        WaitCursor frame = new WaitCursor();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                try
                {
                    createAndShowGUI();
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                    System.exit(0);
                }
            }
        });
    }

}

2 个答案:

答案 0 :(得分:4)

禁用它的一种方法是使用玻璃窗格阻止鼠标输入。

例如:

import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;

import javax.swing.*;

@SuppressWarnings("serial")
public class WaitCursor2 extends JPanel {

   private static final int PREF_W = 400;
   private static final int PREF_H = PREF_W;
   private JComponent glassPane;
   private JButton runBackgroundProcBtn;
   private JTextArea textarea = new JTextArea(15, 30);

   public WaitCursor2(JComponent glassPane) {
      this.glassPane = glassPane;
      glassPane.setFocusable(true);
      glassPane.addMouseListener(new MouseAdapter() {
      }); // so it will trap mouse events.

      add(new JTextField(10));
      add(runBackgroundProcBtn = new JButton(new AbstractAction(
            "Run Background Process") {

         @Override
         public void actionPerformed(ActionEvent arg0) {
            runBackgroundProcessAction();
         }
      }));
      add(new JScrollPane(textarea));
   }

   private void runBackgroundProcessAction() {
      disableSystem(true);
      glassPane.setVisible(true);
      new SwingWorker<Void, Void>() {
         @Override
         protected Void doInBackground() throws Exception {
            long sleepTime = 5000;
            Thread.sleep(sleepTime);
            return null;
         }

         @Override
         protected void done() {
            disableSystem(false);
         }
      }.execute();
   }

   public void disableSystem(boolean disable) {
      glassPane.setVisible(disable);
      runBackgroundProcBtn.setEnabled(!disable);
      if (disable) {
         System.out.println("started");
         glassPane.requestFocusInWindow(); // so can't add text to text components
         glassPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
      } else {
         System.out.println("done");
         glassPane.setCursor(Cursor.getDefaultCursor());
      }
   }

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

   private static void createAndShowGui() {
      JFrame frame = new JFrame("WaitCursor2");
      WaitCursor2 mainPanel = new WaitCursor2((JComponent) frame.getGlassPane());

      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

如果鼠标事件设置为可见并且给定了MouseListener,则它将捕获鼠标事件。如果设置为隐形,它将失去他的能力。同样,如果您将其放在焦点上并将焦点放在焦点上,它将从文本组件中拉出插入符号。

答案 1 :(得分:0)

添加了一个字段current_active,并在方法actionPerformed中,进行简单的检查。虽然它并不完美,但对于简单的应用程序,我认为这样做。解决你的两个要求的粗略方法。 :-)希望它也适合你。

import java.awt.Component;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


public class WaitCursor extends JFrame
{
    private static boolean current_active = false;

    public WaitCursor()
    {
        setResizable(false);

        setName(getClass().getSimpleName());
        setTitle("My Frame");
        setSize(300, 300);

        getContentPane().add(new MyButtonPanel());
    }

    private class MyButtonPanel extends JPanel
    {

        public MyButtonPanel()
        {
            JButton btnStart = new JButton("Start");
            btnStart.addActionListener(new BtnStartActionListener());
            add(btnStart);
        }

        private class BtnStartActionListener implements ActionListener
        {



            // change to wait_cursor
            public void actionPerformed(ActionEvent e)
            {
                if (!current_active)
                {
                    Component root = SwingUtilities.getRoot((JButton) e.getSource());
                    JOptionPane.showMessageDialog(root, "Wait 10 seconds");
                    root.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

                    // TODO: Disabling the root component prevents the WAIT_CURSOR from being displayed
                    //root.setEnabled(false);
                    current_active = true;
                    new Thread(new TimeKiller(root)).start();   

                }
            }
        }   
    }

    private class TimeKiller implements Runnable
    {
        Component m_root;

        public TimeKiller(Component p_root)
        {
            m_root = p_root;

        }       

        @Override
        public void run()
        {
            try
            {
                Thread.sleep(10 * 1000);                
            }
            catch (InterruptedException e)
            {
                //Ignore it
            }
            // Change back to DEFAULT CURSOR
            JOptionPane.showMessageDialog(m_root, "Done waiting");
            m_root.setCursor(Cursor.getDefaultCursor());
            current_active = false;
        }

    }

    // create and setup the window.
    public static void createAndShowGUI() 
    {
        WaitCursor frame = new WaitCursor();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);

    }

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                try
                {
                    createAndShowGUI();
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                    System.exit(0);
                }
            }
        });
    }

}