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

时间:2022-11-30 20:31:57

Good day! I wanted use a standart Swing Timer with Full Screen Exclusive Mode. To this effect I applied a SwingWorker to control the event when graphic mode should be set. All following steps are executed in run method. run() is called from main. 1)First of all, I create my SwingWorker object and override two its methods(doInBackground and done). Init is important method because it should set all needfull graphic setting to current JFrame object and bind my key listener objet(called screen_list) with it:

美好的一天!我想使用具有全屏独占模式的标准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)then I create my screenlistener that implements an ActionListener and a Key Listener, it is bound with disp as KeyListener in init() method:

2)然后我创建了我的screenlistener,它实现了一个ActionListener和一个Key Listener,它与disp绑定为init()方法中的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)I create and initialize my Swing Timer and start it; 4)And finally i call execute method:

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)
    {}
    ...
}

Class ScreenListener as i have written implements a KeyListener and an ActionListener. In ActionPerfomed method i check out did worker do its job(init method), if yes, i get ref to current display mode and draw something:

我编写的类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);
                            ...
                        }
                    }
          }
    ...
    }

Why aren't events from keyboard processed?

为什么不处理键盘事件?

3 个解决方案

#1


0  

I don't make all of those Swing calls from init. Init should set all needfull graphic setting to current JFrame object and bind key listener with it.

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

OK, I see you've changed your code some:

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

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) 
        { 
        }   
    ...
   }

but you're still making Swing calls in init when you get the JFrame, set its display mode and buffer strategy, it's focus traversal business, and add a key listener. Why are these calls being made in a background thread as they wouldn't be expected to interfere with Swing processing (so no need to be done on the background), and are actually "Swing calls" since you're changing the state of Swing objects with them. doInBackground is for running long-running or cpu-intensive processes that if run on the EDT would freeze the GUI and make it unresponsive. The code you've shown does not do this. The danger of doing Swing calls in a background thread is that while it will work 95% of the time, it will fail at unexpected times causing your app to crash and burn, usually at the most inopportune time.

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

Also, why the empty catch block? I'd at least put in an ex.printStackTrace() in there so as not to fly blind.

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

2)then I create my screenlistener that implements an ActionListener and a Key Listener, it is bound with disp as KeyListener in init() method:

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

So am I right in stating that you're adding a KeyListener to a JFrame? I doubt that this will work since KeyListeners only respond if the bound component has the focus, something a JFrame would rarely do or want to do. Perhaps you wish to use the more versatile key bindings as this will allow greater flexibility with regards to focus and responsiveness.

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

3)then I create and initialize my Swing Timer and start it;

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

OK

4)And finally i call execute method. –

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)
    {}
    ...
}

Again you've got an empty catch block.

你又有一个空的挡块。

And can you tell us more about your specific problems? We see bits and pieces of unrelated code with a vague description of sort of what it does, but don't really have a full idea of anything yet. Can you give us a more detailed description of your program and its problems? Are you trying to create the SSCCE as recommended by Andrew? If you could create and post this, we'd be much better able to test and modify your program and help you to a solution. Best of luck

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

#2


0  

I used a SwingWorker capabilities because full screen mode as yet had not set by the time timer already started. Ок. I passed up using a SwingWorker. Instead of this I added a simple condition:

我使用了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
                 ...
                }
            }

}

So now my run method looks like this

所以现在我的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())
            {
             ...
            }
        }
     }

And I make a focusable my disp:

而且我的关注点是:

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();
    }   
}

but I can't still catch my keyboard events. KeyTyped, KeyPressed, KeyReleased aren't still called so it is my problem in that programm.

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

My first aim was make a simple animation with full screen mode. At first i used a simple thread method - sleep - as for main thread. Then I added a swing timer for the same purpose but as you look I got a problem: I can't make to work my KeyListener.

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

#3


0  

I decided my problem:

我决定了我的问题:

1)Now FullScreen class extends from JFrame:

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)Add loop in the run method, it checks out is timer running:

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 and KeyPressed became the synchronized methods.

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

So ActionListener and KeyListener works good.

所以ActionListener和KeyListener运行良好。

Thanks for responses!

谢谢你的回复!

#1


0  

I don't make all of those Swing calls from init. Init should set all needfull graphic setting to current JFrame object and bind key listener with it.

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

OK, I see you've changed your code some:

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

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) 
        { 
        }   
    ...
   }

but you're still making Swing calls in init when you get the JFrame, set its display mode and buffer strategy, it's focus traversal business, and add a key listener. Why are these calls being made in a background thread as they wouldn't be expected to interfere with Swing processing (so no need to be done on the background), and are actually "Swing calls" since you're changing the state of Swing objects with them. doInBackground is for running long-running or cpu-intensive processes that if run on the EDT would freeze the GUI and make it unresponsive. The code you've shown does not do this. The danger of doing Swing calls in a background thread is that while it will work 95% of the time, it will fail at unexpected times causing your app to crash and burn, usually at the most inopportune time.

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

Also, why the empty catch block? I'd at least put in an ex.printStackTrace() in there so as not to fly blind.

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

2)then I create my screenlistener that implements an ActionListener and a Key Listener, it is bound with disp as KeyListener in init() method:

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

So am I right in stating that you're adding a KeyListener to a JFrame? I doubt that this will work since KeyListeners only respond if the bound component has the focus, something a JFrame would rarely do or want to do. Perhaps you wish to use the more versatile key bindings as this will allow greater flexibility with regards to focus and responsiveness.

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

3)then I create and initialize my Swing Timer and start it;

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

OK

4)And finally i call execute method. –

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)
    {}
    ...
}

Again you've got an empty catch block.

你又有一个空的挡块。

And can you tell us more about your specific problems? We see bits and pieces of unrelated code with a vague description of sort of what it does, but don't really have a full idea of anything yet. Can you give us a more detailed description of your program and its problems? Are you trying to create the SSCCE as recommended by Andrew? If you could create and post this, we'd be much better able to test and modify your program and help you to a solution. Best of luck

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

#2


0  

I used a SwingWorker capabilities because full screen mode as yet had not set by the time timer already started. Ок. I passed up using a SwingWorker. Instead of this I added a simple condition:

我使用了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
                 ...
                }
            }

}

So now my run method looks like this

所以现在我的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())
            {
             ...
            }
        }
     }

And I make a focusable my disp:

而且我的关注点是:

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();
    }   
}

but I can't still catch my keyboard events. KeyTyped, KeyPressed, KeyReleased aren't still called so it is my problem in that programm.

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

My first aim was make a simple animation with full screen mode. At first i used a simple thread method - sleep - as for main thread. Then I added a swing timer for the same purpose but as you look I got a problem: I can't make to work my KeyListener.

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

#3


0  

I decided my problem:

我决定了我的问题:

1)Now FullScreen class extends from JFrame:

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)Add loop in the run method, it checks out is timer running:

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 and KeyPressed became the synchronized methods.

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

So ActionListener and KeyListener works good.

所以ActionListener和KeyListener运行良好。

Thanks for responses!

谢谢你的回复!