0

再会!我想使用具有全屏独占模式的标准摇摆计时器。为此,我应用了 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)我创建并初始化我的摇摆定时器并启动它;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);
                            ...
                        }
                    }
          }
    ...
    }

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

4

3 回答 3

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

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

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

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

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

好的

4)最后我调用执行方法。——</p>

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?如果您可以创建并发布此内容,我们将能够更好地测试和修改您的程序并帮助您找到解决方案。祝你好运

于 2011-05-14T12:02:03.713 回答
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
                 ...
                }
            }

}

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

   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 工作。

于 2011-05-15T14:13:34.027 回答
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 效果很好。

感谢您的回复!

于 2011-05-15T22:40:56.293 回答