【问题标题】:Use Java Full Screen Exclusive Mode with Swing Timer使用带有 Swing Timer 的 Java 全屏独占模式
【发布时间】:2011-05-13 21:42:10
【问题描述】:

美好的一天! 我想使用具有全屏独占模式的标准摇摆计时器。为此,我应用了 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) 然后我创建了实现 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)最后我调用执行方法:

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 方法中,我检查了 worker 是否完成了它的工作(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);
                            ...
                        }
                    }
          }
    ...
    }

为什么不处理来自键盘的事件?

【问题讨论】:

  • 您不应该从在 doInBackground 中调用的 init 中进行所有 Swing 调用。相反,此方法用于调用必须后台对 Swing 主线程,EDT(因此得名)进行的调用。
  • 问题编号 2,您声明:External class implements a KeyListener but key event processing doesn't work! why???,我想这是您遇到的主要问题以及发布此帖子的原因,但您并没有真正告诉我们有关关键监听器或显示它的任何代码(不是我能看到的),而是发布很多不相关的代码。也许您正在将关键侦听器添加到没有焦点的组件中——我不知道。您可能希望将您的问题简化为基本问题并澄清您的问题。
  • 如需尽快获得更好的帮助,请发帖SSCCE。
  • 我不会从 init 进行所有这些 Swing 调用。 Init 应该将所有需要的设置设置为当前 JFrame 对象并与它绑定键侦听器:
  • 我不会从 init 进行所有这些 Swing 调用。 Init 应该将所有需要的图形设置设置为当前的 JFrame 对象并与它绑定键侦听器。步骤: 1)首先,我创建我的 SwingWorker 对象并覆盖它的两个方法(doInBackground 和 done),从 doInBackground 调用 init; 2)我创建了实现 ActionListener 和 Key Listener 的屏幕监听器; 3)然后我创建并初始化我的 Swing Timer 并启动它; 4)最后我调用执行方法。

标签: java swing timer fullscreen edt


【解决方案1】:

我不会从 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% 的时间内工作,但它会在意想不到的时间失败,导致您的应用程序崩溃和烧毁,通常是在最不合时宜的时候。

另外,为什么是空的 catch 块?我至少会在那里放一个 ex.printStackTrace() 以免失明。

2) 然后我创建了实现 ActionListener 和 Key Listener 的屏幕监听器,它在 init() 方法中与 disp 绑定为 KeyListener:

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

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

好的

4) 最后我调用执行方法。 ——

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

你又得到了一个空的 catch 块。

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

【讨论】:

    【解决方案2】:

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

    }

    所以现在我的运行方法是这样的

       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 仍然没有被调用,所以这是我在那个程序中的问题。

    我的第一个目标是制作一个全屏模式的简单动画。起初我使用了一个简单的线程方法——睡眠——作为主线程。然后我出于同样的目的添加了一个摇摆计时器,但正如你所见,我遇到了一个问题:我无法让我的 KeyListener 工作。

    【讨论】:

      【解决方案3】:

      我决定了我的问题:

      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 效果很好。

      感谢您的回复!

      【讨论】:

        猜你喜欢
        • 2012-02-26
        • 1970-01-01
        • 2014-05-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-07
        相关资源
        最近更新 更多