使用Java全屏独占模式和Swing Timer

时间:2011-05-13 21:42:11

标签: java swing timer fullscreen edt

美好的一天! 我想使用具有全屏独占模式的标准Swing Timer。为此,我应用SwingWorker来控制应该设置图形模式的事件。以下所有步骤均在run方法中执行。从main调用run()。 1)首先,我创建我的SwingWorker对象并覆盖其两个方法(doInBackground和done)。 Init是一个重要的方法,因为它应该将所有需要的图形设置设置为当前的JFrame对象,并将其与我的密钥监听器对象(称为screen_list)绑定:

...
worker = new SwingWorker<Window, Void>() 
    {
            public Window doInBackground() 
            {
                init();
                return gdev.getFullScreenWindow();
            }

            public void done() 
            {
                try {
                    disp = get();
                } 
                catch (InterruptedException ignore) {}
                catch (java.util.concurrent.ExecutionException e) {
                    String why = null;
                    Throwable cause = e.getCause();
                    if (cause != null) {
                        why = cause.getMessage();
                    } else {
                        why = e.getMessage();
                    }
                    System.err.println("Error retrieving file: " + why);
                }
            }
    };

...

2)然后我创建了我的screenlistener,它实现了一个ActionListener和一个Key Listener,在init()方法中它与disp绑定为KeyListener:

private void init()
    {

        ...
    try 
            {
                disp = gdev.getFullScreenWindow();
                if(disp != null)
                {
                    gdev.setDisplayMode(use_dm);
                    disp.createBufferStrategy(2);
                    disp.setFocusTraversalKeysEnabled(false);
                    disp.addKeyListener((KeyListener)screen_list);
                }   
            }
            catch(IllegalArgumentException ex) 
            { 
            }   
        ...
       }

3)我创建并初始化我的Swing Timer并启动它; 4)最后我调用了execute方法:

public void run(int pause, int delay)
{
...
try
    {   
        screen_list = new ScreenListener();
        tm = new Timer(delay, screen_list);
        tm.setInitialDelay(pause);
        tm.setRepeats(true);
        tm.start();
        worker.execute();
    }
    catch(Exception e)
    {}
    ...
}

我编写的类ScreenListener实现了一个KeyListener和一个ActionListener。在ActionPerfomed方法中,我检查了工作人员是否完成了它的工作(init方法),如果是的话,我会参考当前的显示模式并绘制一些东西:

    class ScreenListener implements ActionListener, KeyListener 
    {

        public void actionPerformed(ActionEvent e)
        {

        if(!worker.isDone())
                    {
                        return;
                    }
                    else
                    {
                        //gdev - GraphicsDevice type
                        disp = gdev.getFullScreenWindow();
                        if (disp != null) 
                        {
                            ...         
                            draw(gr);
                            ...
                        }
                    }
          }
    ...
    }

为什么不处理键盘事件?

3 个答案:

答案 0 :(得分:0)

  

我没有从init进行所有那些Swing调用。 Init应该将所有需要的图形设置设置为当前的JFrame对象,并将密钥监听器与它绑定。

好的,我看到你已经改变了一些代码:

private void init()
{

    ...
try 
        {
            disp = gdev.getFullScreenWindow();
            if(disp != null)
            {
                gdev.setDisplayMode(use_dm);
                disp.createBufferStrategy(2);
                disp.setFocusTraversalKeysEnabled(false);
                disp.addKeyListener((KeyListener)screen_list);
            }   
        }
        catch(IllegalArgumentException ex) 
        { 
        }   
    ...
   }

但是当你获得JFrame时,你仍然在init中进行Swing调用,设置它的显示模式和缓冲策略,它是焦点遍历业务,并添加一个键监听器。为什么这些调用是在后台线程中进行的,因为它们不会干扰Swing处理(所以不需要在后台完成),实际上是“Swing调用”,因为你正在改变Swing的状态与他们对象。 doInBackground用于运行长时间运行或CPU密集型进程,如果在EDT上运行,则会冻结GUI并使其无响应。您显示的代码不会这样做。在后台线程中进行Swing调用的危险在于,虽然它会在95%的时间内工作,但它会在意外时间失败,从而导致应用程序崩溃和刻录,通常是在最不合适的时间。

另外,为什么空挡块?我至少在那里放了一个ex.printStackTrace(),以免盲目飞行。

  

2)然后我创建了我的screenlistener,它实现了一个ActionListener和一个Key Listener,在init()方法中它与disp绑定为KeyListener:

我是否正确地声明您正在向JFrame添加KeyListener?我怀疑这是否有效,因为KeyListeners仅在绑定组件具有焦点时才响应,这是JFrame很少会做或想做的事情。也许您希望使用更通用的键绑定,因为这样可以在焦点和响应方面提供更大的灵活性。

  

3)然后我创建并初始化我的Swing Timer并启动它;

  

4)最后我调用了execute方法。 -

public void run(int pause, int delay)
{
...
try
    {   
        screen_list = new ScreenListener();
        tm = new Timer(delay, screen_list);
        tm.setInitialDelay(pause);
        tm.setRepeats(true);
        tm.start();
        worker.execute();
    }
    catch(Exception e)
    {}
    ...
}

你又有一个空的挡块。

你能告诉我们更多你的具体问题吗?我们看到一些不相关的代码,其中含有模糊的描述,但实际上并没有完全了解任何东西。您能否详细介绍一下您的计划及其问题?您是否正在尝试按照Andrew的建议创建SSCCE?如果您可以创建并发布此文件,我们将能够更好地测试和修改您的程序并帮助您找到解决方案。祝你好运

答案 1 :(得分:0)

我使用了SwingWorker功能,因为时间计时器尚未设置全屏模式。 Ок。我放弃了使用SwingWorker。而不是这个,我添加了一个简单的条件:

class ScreenListener implements ActionListener, KeyListener 
{
    public void actionPerformed(ActionEvent e)
            {
                System.out.println("ScreenListener: actionPerformed");
                disp = gdev.getFullScreenWindow();
                if(disp == null)
                {
                    return;
                }
                else
                {
                 //draw something
                 ...
                }
            }

}

所以现在我的run方法看起来像这样

   public void run(int pause, int delay)
    {
        screen_list = new ScreenListener();
        init();
        try
        {   
            tm = new Timer(delay, (ActionListener)screen_list);
            tm.setInitialDelay(pause);
            tm.setRepeats(true);
            tm.start();
        }
        catch(Exception ex)
        {
             ex.printStackTrace();
        }
        finally
        {
            if(!tm.isRunning())
            {
             ...
            }
        }
     }

我做了一个可调焦的事情:

private void init()
{
    JFrame frame = new JFrame();
    ...
    disp = new Window(frame);

    DisplayMode[] dms = gdev.getDisplayModes();

    DisplayMode use_dm = null;

    if(gdev.isFullScreenSupported())
    {
        disp.setBackground(Color.CYAN);
        disp.setForeground(Color.WHITE);
        gdev.setFullScreenWindow(disp);
    }

    use_dm = getMatchMode(dms, def_dm);

    try 
    {
        disp = gdev.getFullScreenWindow();
        if(disp != null)
        {
            ...
            disp.setFocusable(true);
            disp.addKeyListener((KeyListener)screen_list);
            ...
        }   
    }
    catch(IllegalArgumentException ex) 
    { 
         ex.printStackTrace();
    }   
}

但我仍然无法抓住我的键盘事件。 KeyTyped,KeyPressed,KeyReleased仍然没有被调用,所以这是我在该程序中的问题。

我的第一个目标是制作一个全屏模式的简单动画。起初我使用了一个简单的线程方法 - sleep - 就像主线程一样。然后我添加了一个摆动计时器用于相同的目的,但你看起来我遇到了一个问题:我无法使我的KeyListener工作。

答案 2 :(得分:0)

我决定了我的问题:

1)现在,FullScreen类从JFrame扩展:

public class SimpleFullScreen extends JFrame 
{
...
    private synchronized void init()
    {
        Window disp = null;
        //customize my display
        setFocusable(true);
        setResizable(false);
        setIgnoreRepaint(true);
        setUndecorated(true);
        setBackground(Color.CYAN);
        setForeground(Color.WHITE);     
        addKeyListener((KeyListener)screen_list);

        DisplayMode[] dms = gdev.getDisplayModes();

        DisplayMode use_dm = null;

        if(gdev.isFullScreenSupported())
            gdev.setFullScreenWindow(this);

        use_dm = getMatchMode(dms, def_dm);

        try 
        {
            disp = gdev.getFullScreenWindow();
            if(disp != null)
            {
                gdev.setDisplayMode(use_dm);
                createBufferStrategy(2);
            }   
        }
        catch(IllegalArgumentException ex) 
        { 
             ex.printStackTrace();
        }   
    }
...
}

2)在run方法中添加循环,它检出计时器正在运行:

public void run(int pause, int delay)
{
    Window disp = null;
    screen_list = new ScreenListener();
    init();
    try
    {   
        //Initialize and start timer 
                    ...
        while(tm.isRunning())
        {
            System.out.println("Run: timer running");
        }
    }
    catch(Exception ex)
    {
         ex.printStackTrace();
    }
    finally
    {
        try
        {
            if(!tm.isRunning())
            {
                disp = gdev.getFullScreenWindow();
                disp.setVisible(false);
                disp.dispose();
                gdev.setFullScreenWindow(null);
                System.exit(0);
            }
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
        }
    }
}

3)init,actionPerfomed和KeyPressed成为同步方法。

所以ActionListener和KeyListener运行良好。

感谢您的回复!