Панель изменения содержимого Java

Недавно я делал игру и столкнулся с проблемой, которую не смог решить. Моя проблема заключается в удалении панели содержимого JFrame и установке чего-то другого. Хотя это работает, KeyListener в классе панели содержимого не работает, если я не изменю основное окно на компьютере на что-то другое, а затем вернусь к JFrame.

Я воспроизвел проблему в меньшем количестве кода, чем было изначально:

import java.awt.*;
import java.awt.event.*;
import javax.awt.swing.*;

public class TheFrame extends JFrame{

    private JButton play;
    private FirstPanel fp;
    private SecondPanel sp;

    public TheFrame(){

        setSize(800, 600);
        setLocationRelativeTo(null);
        setResizable(false);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        fp = new FirstPanel();
        setContentPane(fp);

        setVisible(true);
    }

    public static void main(String args[]){

        TheFrame tf = new TheFrame();
    }

    class FirstPanel() extends JPanel{

        private boolean test = false;

        public FirstPanel(){

            play = new JButton("play");
            play.addActionListener(new PlayListener());
            add(play);
        }

        public void paintComponent(Graphics g){

            if(test == true){

                sp = new SecondPanel();
                removeAll();
                revalidate();
                setContentPane(sp);
            }
        }

        class PlayListener implements ActionListener{

            public void actionPerformed(ActionEvent e){

                test = true;
                repaint();
            }
        }
    }
}

Вот также код класса SecondPanel:

import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;

public class SecondPanel extends JPanel implements KeyListener{

    private int draw = 0;

    public SecondPanel(){

        addKeyListener(this);

    }

    public void paintComponent(Graphics g){

        super.paintComponent(g);

        g.drawString("press f to draw circles", 90, 40);

        if(draw > 0){

            for(int i = 0; i < draw; i++){

                g.drawOval((i*100)+100, (i*100)+100, 100, 100);
            }
        }
    }

    public void keyTyped(KeyEvent e){

        if(e.getKeyChar() == 'f' || e.getKeyChar() == 'F'){
            draw++;
            repaint();
        }
    }
}

person Raywl    schedule 03.12.2014    source источник


Ответы (2)


Так что, прежде всего, это...

public void paintComponent(Graphics g){
    if(test == true){
        sp = new SecondPanel();
        removeAll();
        revalidate();
        setContentPane(sp);
    }
}

Это невероятно плохо! Во-первых, вы разрываете цепочку отрисовки (не вызывая super.paintComponent), а во-вторых, вы меняете состояние компонента внутри цикла отрисовки, это вызовет новый запрос на перерисовку и вызовет ваш paintComponent снова и снова, и снова, и снова. ...

Рисование предназначено для рисования текущего состояния компонента, не более того. НИКОГДА не изменяйте состояние любого компонента из ЛЮБОГО paint метода НИКОГДА

Вместо того, чтобы пытаться использовать remove/add, рассмотрите возможность использования CardLayout, см. Как использовать CardLayout. Это позволит вам переключаться между первой и второй панелями в зависимости от ваших потребностей из централизованного пункта управления.

KeyListener непостоянная любовница, она все время хочет внимания. Он будет вызывать ключевые события только в том случае, если компонент, на который он зарегистрирован, является фокусируемым И имеет фокус. Лучшим решением является использование API привязки клавиш, который был разработан для преодоления этого ограничения и предоставления вам уровня контроля над уровнем фокуса, необходимым для запуска связанных действий.

Дополнительные сведения см. в разделе Как использовать привязки клавиш.

person MadProgrammer    schedule 03.12.2014

Чтобы поменять содержимое контейнера, будь то ContentPane JFrame или любая JPanel, рассмотрите возможность использования CardLayout, так как этот инструмент был создан специально для этой работы.

Обратите внимание, что этот код:

sp = new SecondPanel();
removeAll();
revalidate();
setContentPane(sp);

никогда не должен находиться внутри метода paintComponent. Этот метод не находится под нашим непосредственным контролем и должен быть только для рисования и рисования. Кроме того, не вызывая метод super, вы разорвали цепочку рисования.

Кроме того, вместо KeyListeners используйте Key Bindings, и ваша функциональность должна работать.

Например, взгляните на аналогичный код CardLayout, который я создал сегодня для другого похожего вопроса.

person Hovercraft Full Of Eels    schedule 03.12.2014