Используйте полноэкранный эксклюзивный режим Java с Swing Timer - PullRequest
0 голосов
/ 14 мая 2011

Добрый день!Я хотел использовать стандартный таймер Swing с полноэкранным эксклюзивным режимом.Для этого я применил SwingWorker для управления событием, когда должен быть установлен графический режим.Все последующие шаги выполняются в методе run.run () вызывается из main.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, он связан с disp как KeyListener в методе init ():

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 голосов
/ 15 мая 2011

Я использовал возможности 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())
            {
             ...
            }
        }
     }

И я делаю фокусируемый мой 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();
    }   
}

но я не могу поймать события клавиатуры.KeyTyped, KeyPressed, KeyReleased до сих пор не вызваны, так что это моя проблема в этой программе.

Моей первой целью было сделать простую анимацию с полноэкранным режимом.Сначала я использовал простой метод потока - сон - как основной поток.Затем я добавил таймер поворота для той же цели, но, как вы видите, у меня возникла проблема: я не могу заставить работать мой KeyListener.

0 голосов
/ 16 мая 2011

Я решил свою проблему:

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 работают хорошо.

Спасибо за отзывы!

0 голосов
/ 14 мая 2011

Я не делаю все эти звонки Swing из init.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) 
        { 
        }   
    ...
   }

но выВы по-прежнему делаете вызовы Swing в init, когда вы получаете JFrame, устанавливаете его режим отображения и стратегию буфера, это бизнес для обхода фокуса и добавляете ключевого слушателя.Почему эти вызовы выполняются в фоновом потоке, так как они не должны мешать обработке Swing (поэтому не нужно делать это в фоновом режиме) и на самом деле являются "вызовами Swing", так как вы меняете состояние Swingобъекты с ними.doInBackground предназначен для запуска длительных или ресурсоемких процессов, которые при запуске на EDT приведут к зависанию GUI и отключению его.Код, который вы показали, не делает этого.Опасность выполнения вызовов Swing в фоновом потоке заключается в том, что, хотя он будет работать в 95% случаев, он неожиданно завершится сбоем, что приведет к сбою и сбою приложения, обычно в самый неподходящий момент.

Кроме того, почему пустой блок catch?Я бы, по крайней мере, вставил туда ex.printStackTrace (), чтобы не ослепнуть.

2), затем я создаю свой экранный слистер, который реализует ActionListener и Key Listener, он связанс disp в качестве KeyListener в методе init ():

Так правильно ли я заявляю, что вы добавляете KeyListener в JFrame?Я сомневаюсь, что это сработает, так как KeyListeners отвечают, только если связанный компонент имеет фокус, что JFrame редко делает или хочет делать.Возможно, вы захотите использовать более универсальные привязки клавиш, поскольку это даст большую гибкость в отношении фокусировки и отзывчивости.

3) затем я создаю и инициализирую свой Swing Timer и запускаю его;

OK

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

Опять у вас есть пустой блок catch.

И вы можете рассказать нам больше о ваших конкретных проблемах?Мы видим кусочки несвязанного кода с расплывчатым описанием того, что он делает, но на самом деле пока не имеем полного представления о чем-либо.Можете ли вы дать нам более подробное описание вашей программы и ее проблем?Вы пытаетесь создать SSCCE в соответствии с рекомендациями Эндрю?Если бы вы могли создать и опубликовать это, мы были бы намного лучше протестировать и изменить вашу программу и помочь вам найти решение.Желаем удачи

...