Чтобы генерировать KeyEvent, нужно нажать клавишу табуляции перед желаемой ошибкой - PullRequest
0 голосов
/ 21 мая 2019

У меня сейчас есть таймер, и поэтому на моем JPanel есть счетчик, который показывает таймер обратного отсчета. Это все часть игры - пользователь должен ответить на вопрос, поэтому, когда пользователь нажимает стрелку вверх, у него должно быть еще 5 секунд, чтобы ответить на вопрос. Для этого я использую keyListener, который добавлен в JPanel. Но у меня есть эта действительно странная ошибка: JPanel не генерирует KeyEvent, если не нажата клавиша TAB вместе со стрелкой ВВЕРХ. Если я нажму одну стрелку ВВЕРХ, KeyEvent не будет сгенерирован, и ограничение по времени не увеличится.

Я просмотрел несколько ресурсов, но ничего не было связано с моими. Я установил requestFocusInWindow везде, где должен, но решения не существует. Кстати, это для проекта, поэтому я не могу использовать KeyBindings.

Код игровой панели-

// import everything needed
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
// imports for anti-aliasing from Stack Overflow
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.Timer;

// This panel is the panel which has the game. It is mainly based off of graphics.
// It creates a clown which is juggling balls, and also the background is drawn
// and it is all animated. It also has a TextArea-which displays the question
// and a TextField- which is for the user to typeintheir answer
public class GamePanel extends JPanel implements ActionListener, KeyListener
{
    protected TimerHandler th;
    private boolean upPressed;

    private CardPanel cp; // instance of CardPanel from the class 'StartPanel'
    // to use to switch between cards
    private CardLayout cards; // instance of cardLayout
    private Timer timer; // Timer for animation

    private int counter; // counter for animating arms

    private Color colors[]; // array for holding different colors

    private int colorCounter; // counter for animating balls

    private Scanner questionReader; // scanner that reads from the easyequations.txt file

    private Scanner answerReader; // scanner that reads from the easysolutions.txt file

    private String questions[]; // array that contains all the questions
    // from the easyequations.txt file

    private String answers[]; // array that contains all answers from the
    // easysolutions.txt file

    private String ans; // string that will contain each answers every time the while
    // loop is run and used to check if the user
    // entered answer is the correct answer

    private int random; // int variable that will be defined by Math.random(),
    // so every time game is run, a random
    // question from the text file is displayed in the
    // question text area

    private JTextArea questionArea; // the text area which will display a random question each time

    private int score; // score counter- each time a question is answered correct
    // the score increases

    private Timer timeLimit; // timer that keep track of time user has left to
    // answer question

    protected double timeCounter; // a number that is printed to panel to print the time left

    private boolean textEntered;// boolean to check if any sort of text is typed
    // in the answer text field

    private boolean timeAlmostUp;

    private boolean oneWrong;

    private boolean timeUp; // boolean to check if user entered answer before time limit
    // was over

    private int numWrong; // int that tracks how many times the user gets a question gets a question
    // wrong.

    private Color fourColors[]; // array for four balls
    private Color threeColors[]; // array for three balls
    private Color twoColors[]; // array for two balls
    private int fourCounter;
    private int threeCounter;
    private int twoCounter;


    // this panel is also the holder panel- it holds the question TextArea and
    // the TextField which the answer is supposed to be typed into
    public GamePanel(CardPanel cpIn, CardLayout cardsIn)
    {

        score = 0;

        random = (int) (Math.random() * 25);

        ans = new String(" ");

        cards = cardsIn;

        cp = cpIn;

        answers = new String[25];

        timeCounter = 10;

        questions = new String[25];

        QuestionTA qta = new QuestionTA(); // panel that creates the TextArea for
        // user to type answer
        qta.setBounds(300, 35, 400, 100);
        add(qta);

        AnswerTF atf = new AnswerTF(); // panel that creates the TextField
                                        //for entering the answer
        atf.setBounds(450, 150, 100, 30);
        add(atf);

        th = new TimerHandler();
        th.setBounds(700, 200, 230, 200);
        add(th);

        timeLimit = new Timer(1000, th);

        BackButtonPanel bbp = new BackButtonPanel(); // panel that creates a
        // JButton to allow user
        // to go back to home screen
        bbp.setBounds(6, 0, 90, 50);
        add(bbp);



        setLayout(null); // this panel is a null layout
        Color color = new Color(206, 228, 244);

        setBackground(color);

        timer = new Timer(225, this);

        counter = 2;
        colorCounter = 5;
        numWrong = 0;

        fourColors = new Color[4];
        threeColors = new Color[3];
        twoColors = new Color[2];
        fourCounter = 4;
        threeCounter = 3;
        twoCounter = 2;

        setFocusable(true);
        requestFocus();
        addKeyListener(this);


    }

    public void actionPerformed(ActionEvent evt)
    {
        timeLimit.setInitialDelay(1000);
        timeCounter -= 0.225;

        if(textEntered)
            timeAlmostUp = false;


        if (timeCounter <=5 && !textEntered)
            timeAlmostUp = true;

        if (timeCounter<=1)
        {
            timeCounter =0;
            timeAlmostUp = false;
            timeUp = true;
            repaint();
        }


        if (numWrong > 0)
        {
            repaint();
        }
        repaint();
    }

    public void keyTyped(KeyEvent e)
    {
        System.out.println("up");
    }

    public void keyPressed(KeyEvent evt)
    {
        requestFocusInWindow();
        int code = evt.getKeyCode();
        System.out.println("up");
        if(code == KeyEvent.VK_UP)
        {
            timeCounter+=7;
            th.repaint();
        }
    }


    public void keyReleased(KeyEvent e)
    {
        System.out.println("up");
    }







Рамка, в которой находится JPanel-

// Prasanth Dendukuri
// 4-23-19
// StartPanel.java

//import everything needed
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

//This class is the Main Menu, the first screen that the user will be taken
//to when he starts the game. Based on the button the user presses, he will
//be taken to the appropriate screen, ex: the 'how to play button' will take the 
//user to the instructions screen, etc

// Creates the JFrame, which will hold the panel. The panel that is added to the
// JFrame is "CardPanel", which is the panel that creates all the cards of each panel
// for card layout.
public class StartPanel
{
    public static void main(String[] args)
    {

        JFrame.setDefaultLookAndFeelDecorated(true);
        JFrame frame = new JFrame("Start");
        frame.requestFocus();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(1000,700);
        frame.setLocation(60,0);
        frame.setResizable(true);
        CardPanel cp = new CardPanel();
        frame.getContentPane().add(cp);
        frame.setVisible(true);
        cp.requestFocus();
    }

}

// this class creates all the cards for each panel created so far and
// adds it to card layout, so the user can navigate through our game.
class CardPanel extends JPanel
{

    private CardLayout cards; // instance of card layout
    private CardPanel cp; //instance of this panel so other classes can use them
                          // for card layout, which includes the nested classes
                          // in this file

    private StartHolderPanel ghp; // instance of clas 'StartHolderPanel' which is to be used when creating
                                 // a card for that class

    private InstructionPanel instructCard;// instance of clas 'InstructionPanel' 
                                        //which is to be used when creating a card for that class

    private GamePanel gameCard; // instance of clas 'GamePanel' which is to be used when 
                                // creating a card for that class

    private GamePanelMedium gameMediumCard;

    private SelectDiff sp;// instance of class 'HolderPanel' which is to be used when creating 
                            // a card for that class



    // constructor - initialize all field variables and add cards to card layout
    public CardPanel()
    {

        cards = new CardLayout();
        setLayout(cards);

        cp = this;

        ghp = new StartHolderPanel(this, cards);
        add(ghp,"home");


        instructCard = new InstructionPanel(this, cards);
        add(instructCard, "first");

        gameCard = new GamePanel(this, cards);
        gameCard.setFocusable(true);
        gameCard.requestFocusInWindow();

        add(gameCard, "second");

        gameMediumCard = new GamePanelMedium(this, cards);
        add(gameMediumCard, "medium");

        sp = new SelectDiff(this, cards);
        add(sp, "third");


    }

    // this class is the holder panel. It holds all the panels in the file 
    // and adds it to this class
    class StartHolderPanel extends JPanel 
    {
        public StartHolderPanel(CardPanel cp, CardLayout cards)
        {

            setLayout(new GridLayout(4,1,0,0));

            TitlePanel tp = new TitlePanel();
            add(tp);
            PlayButtonPanel pbp = new PlayButtonPanel();
            add(pbp);
            HowToPlayPanel htpp = new HowToPlayPanel();
            add(htpp);
            HighScoresPanel hsp = new HighScoresPanel();
            add(hsp);

        }

    }

    // this class creates a JLabel which is the title of the Panel
    class TitlePanel extends JPanel
    {
        public TitlePanel()
        {
            setBackground(new Color(254,195,195));
            Font font = new Font("Serif", Font.BOLD, 50);
            JLabel title = new JLabel("Equation Juggler!");
            title.setFont(font);
            add(title);
        }

    }


    // this class creates a JButton called 'Play' and adds it to the panel. If the button is clicked
    // the user is taken to the Game screen.

    class PlayButtonPanel extends JPanel implements ActionListener
    {

        public PlayButtonPanel()
        {
            setBackground(new Color(254,195,195));
            JButton play = new JButton("Play");
            play.setOpaque(true);
            play.setBackground(new Color(206,228,244));
            play.setPreferredSize(new Dimension(300,200));
            play.addActionListener(this);
            add(play);
            System.out.println("hi");

        }

        // this method checks if the 'play' JButton was pressed, and if it was, takes 
        // the user to the game panel, using card layout.
        public void actionPerformed(ActionEvent evt)
        {
            if(evt.getActionCommand().equals("Play"))
            {

                cards.show(cp, "third");


            }

        }
    }

    // This class creates a JButton, 'How tp Play' and adds it to the panel.
    class HowToPlayPanel extends JPanel implements ActionListener
    {
        public HowToPlayPanel()
        {
            setBackground(new Color(254,195,195));

            JButton howToPlay = new JButton("How to Play");

            howToPlay.setOpaque(true);
            howToPlay.setBackground(new Color(206,228,244));
            howToPlay.setPreferredSize(new Dimension(300,200));
            howToPlay.addActionListener(this);

            add(howToPlay);
        }

        // This method checks if the 'How to Play' Jbutton was pressed. If it was pressed, the
        // user is taken to the Instructions Panel, using card layout.
        public void actionPerformed(ActionEvent e)
        {
            if(e.getActionCommand().equals("How to Play"))
            {
                cards.show(cp, "first");
            }
        }

    }

    // This class creates the JButton, 'High Scores' and adds it to the panel.
    // There is no High Scores JPanel yet.
    class HighScoresPanel extends JPanel implements ActionListener
    {
        public HighScoresPanel()
        {
            setBackground(new Color(254,195,195));
            JButton highScores = new JButton("High Scores");
            highScores.setOpaque(true);
            highScores.setBackground(new Color(206,228,244));
            highScores.setPreferredSize(new Dimension(300,200));
            add(highScores);
        }

        public void actionPerformed(ActionEvent e)
        {
        }
    }
}





Мне нужно буквально нажать клавишу TAB одновременно со стрелкой ВВЕРХ, чтобы получить желаемый результат - приращение переменной timeCounter на 7, но для того, чтобы это произошло прямо сейчас, я должен нажать TAB одновременно как UP. Я думаю, что у меня есть идея, почему эта ошибка существует, но я не уверен - поэтому у меня есть JTextField, который создается в другой панели, но панель, которая создает TextField, находится в этой панели - GamePanel - той, к которой я собираюсь покажись. Поэтому каждый раз, когда я нажимаю клавишу Tab, я думаю, что фокус от TextField отводится от TextField к панели - что тогда, если я нажимаю TAB в то же время, что и время UP-timeCounter, - это моя идея.

Я хочу, чтобы все работало нормально, мне нужно только нажимать стрелку ВВЕРХ для достижения желаемого результата. KeyPressed срабатывает только в том случае, если я нажимаю клавишу TAB перед любой другой клавишей, и это странная ошибка. Не стесняйтесь спрашивать у меня больше кода, такого как рамка, в которой эта панель содержится. Заранее спасибо

Редактировать: я удалил paintComponent, основываясь на предложении, но не стесняйтесь просить меня показать paintComponent (), потому что он имеет отношение к actionListener и логическим значениям.

...