Java等待代码直到JFrame keyPressed

时间:2017-05-25 09:42:04

标签: java jframe

我正在使用JFrame,我希望显示图像并暂停代码,直到用户按下任意键。按下该键后,图像将关闭,代码将继续运行。

我做了什么:

  • 创建了一个标志

    final boolean[] flag = {true};

  • 在JFrame对象中添加了一个addKeyListener,用于更改标志

    frame.addKeyListener(new KeyListener() {
    
    @Override
    public void keyTyped(KeyEvent e) {
    }
    
    @Override
    public void keyReleased(KeyEvent e) {
    }
    
    @Override
    public void keyPressed(KeyEvent e) {
        frame.setVisible(false);
        frame.dispose();
        flag[0] = false;
    }
    });
    
  • 等待循环直到标记为

    while (flag[0]){
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    

这是有效的,但我知道它有点资源。

还有其他方法可以进行等待循环吗?是否有听众的倾听者?

第二次尝试,使用 CountDownLatch

  • 设置闩锁

        final CountDownLatch latch = new CountDownLatch(1);
    
  • 倒计时     for(JFrame frame:framesList){

        frame.addKeyListener(new KeyListener() {
    
            @Override
            public void keyTyped(KeyEvent e) {
            }
    
            @Override
            public void keyReleased(KeyEvent e) {
            }
    
            @Override
            public void keyPressed(KeyEvent e) {
                    frame.setVisible(false);
                    frame.dispose();
                    latch.countDown();
            }
        });
    
  • 等待

        latch.await();
    

1 个答案:

答案 0 :(得分:2)

因此,您希望显示图像并在窗口关闭之前停止执行。这只是尖叫模态对话给我。模态对话框将停止代码执行从可见的位置开始,它将在此处执行,以便不阻止事件调度线程并使整个问题停止尖叫并挂起程序。有关详细信息,请参阅How to use dialogs

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.Image;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    BufferedImage img = ImageIO.read(...);
                    ImageShower.show(null, img);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    public static class ImageShower extends JPanel {

        private JLabel label = new JLabel();

        public ImageShower() {
            setLayout(new BorderLayout());
            add(label);

            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am = getActionMap();

            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "close");
            am.put("close", new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Window window = SwingUtilities.windowForComponent(ImageShower.this);
                    if (window != null) {
                        window.dispose();
                    }
                }
            });
        }

        public void setImage(Image img) {
            label.setIcon(new ImageIcon(img));
        }

        public static void show(Component owner, Image img) {
            Window parent = null;
            if (owner != null) {
                parent = SwingUtilities.windowForComponent(owner);
            }

            JButton close = new JButton("Close");
            close.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    JButton btn = (JButton) e.getSource();
                    Window window = SwingUtilities.windowForComponent(btn);
                    if (window != null) {
                        window.dispose();
                    }
                }
            });

            JDialog dialog = new JDialog(parent, Dialog.ModalityType.APPLICATION_MODAL);
            ImageShower shower = new ImageShower();
            shower.setImage(img);
            dialog.add(shower);
            dialog.add(close, BorderLayout.SOUTH);
            dialog.getRootPane().setDefaultButton(close);
            dialog.pack();
            dialog.setLocationRelativeTo(owner);
            dialog.setVisible(true);
        }

    }

}

"但是等等,可能图片很大,需要时间加载,我不想在加载时冻结用户界面 ......

好的,为此,我希望使用SwingWorker,它可以在后台加载图像,但提供了简单的方法来确保图像在EDT的上下文中正确显示...

public class ImageLoadAndShow extends SwingWorker<Void, Image> {

    @Override
    protected Void doInBackground() throws Exception {
        BufferedImage img = ImageIO.read(...);
        publish(img);
        return null;
    }

    @Override
    protected void process(List<Image> chunks) {
        Image img = chunks.get(chunks.size() - 1);
        ImageShower.show(null, img);
    }

}

不是,如果图片无法加载,您就不会知道它,因为doInBackground方法会将Exception传递出方法。您需要使用PropertyChangeListenerSwingWorker get方法的组合来捕获它,只需记住,get是阻塞的,所以在里面调用它EDT的上下文将一直阻止,直到工人完成

&#34;但是当对话框关闭时我需要执行其他操作&#34;

有几种方法可以实现这一点,具体取决于您想要做什么,对于此示例,我已经坚持使用SwingWorker,因为它很容易复制并粘贴基本结构,但您可以使用Runnable

中包含的Thread
public class ImageLoadShowAndWait extends SwingWorker<Void, Void> {

    @Override
    protected Void doInBackground() throws Exception {
        BufferedImage img = ImageIO.read(...);
        SwingUtilities.invokeAndWait(new Runnable() {
            @Override
            public void run() {
                ImageShower.show(null, img);
            }
        });
        return null;
    }

}

现在,如果这些都不符合您的要求......那么我想知道您实际在做什么:P,看看Foxtrot提供了一个API,它允许您在EDT中异步执行代码而不会阻塞它(整齐地),但这将阻止代码执行,直到它完成为止

  

问题是我希望它在按下任意键时关闭JFrame

KeyListener会给你一些问题,也许不是今天,也许不是明天,但它最终会在你面前爆发。我提供的示例绑定 Escape 键来处置窗口。它也使得&#34;关闭&#34;按下默认按钮,它提供 Space 和/或 Enter 键以及一个很好的可视队列给用户。

如果您想使用KeyListener,这取决于您,但您的核心问题似乎并未围绕它展开,而是能够显示窗口并暂停代码执行直到它关闭