简体   繁体   中英

KeyEvent in JFrame won't work due to runnable

I am new to java so i really hope the problem is really caused by a runnable that jams the key event listener like i think. I have class Roll that calls another class TimerImageSwapper , that creates a runnable in the builder. Later on Roll is calling TimerImageSwapper#run() through the class main() method.

The purpose of the TimerImageSwapper is to simulate cube rolling by displaying random faces and landing on a certain value. The method's main receives the caller JFrame class as input when it is called so that the result is displayed in the initial JFrame .

Once the number is determined I want the user to be able to darken the screen by pressing spacebar. Thats the part that doesn't work.

PS I am assuming it's a threading problem because it runs just fine in debugging mode.

Roll class looks like this:

package nofis;

import java.awt.Color;
import java.awt.Component;
import java.awt.event.KeyEvent;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;


public class Roll extends javax.swing.JFrame {

    private final long id;
    private final String filename;
    private int clicks = 0;

    public Roll(long id) {
        this.setUndecorated(true);
        this.setExtendedState(Roll.MAXIMIZED_BOTH);
        this.filename = "c:\\results\\test.csv";
        initComponents();
        this.id = id;
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jButton1 = new javax.swing.JButton();
        jLabel1 = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setBackground(new java.awt.Color(204, 204, 255));
        addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                formKeyPressed(evt);
            }
        });

        jButton1.setText("text!");
        jButton1.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                jButton1KeyPressed(evt);
            }
            public void keyReleased(java.awt.event.KeyEvent evt) {
                jButton1KeyReleased(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(162, 162, 162)
                        .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 429, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(399, 399, 399)
                        .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(271, 271, 271)
                        .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 221, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addGap(93, 93, 93)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 89, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 97, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(52, 52, 52))
        );

        pack();
    }// </editor-fold>                        

    private void formKeyPressed(java.awt.event.KeyEvent evt) {                                
        if (evt.getKeyCode() == KeyEvent.VK_SPACE) {
            if (clicks == 0) {
                clicks++;
                try {
                    rollDice();
                } catch (IOException ex) {
                    Logger.getLogger(Roll.class.getName()).log(Level.SEVERE, null, ex);
                }
            } else {
                while (!is.done) {
                    try {
                        this.wait(100);
                    } catch (InterruptedException ex) {
                        Logger.getLogger(Roll.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }

                for (Component c : this.getRootPane().getComponents()) {
                    c.setVisible(false);
                }

                this.setBackground(Color.black);
                revalidate();
//
                repaint();

            }
        }    }                               

    private void jButton1KeyReleased(java.awt.event.KeyEvent evt) {                                     
        // TODO add your handling code here:
    }                                    

    private void jButton1KeyPressed(java.awt.event.KeyEvent evt) {                                    
        if (evt.getKeyCode() == KeyEvent.VK_SPACE) {
            try {
                if (clicks == 0) {
                    clicks++;
                    try {
                        rollDice();
                    } catch (IOException ex) {
                        Logger.getLogger(Roll.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    return;
                } else {
                    while (!is.done) {
                        this.wait(100);
                    }

//here i am going through all form elemets and make them disappear. 
                for (Component c : this.getRootPane().getComponents()) {
                    c.setVisible(false);
                }
                this.setBackground(Color.black);
                revalidate();
                repaint();
                }
            } catch (InterruptedException ex) {
                Logger.getLogger(Roll.class.getName()).log(Level.SEVERE, null, ex);
            }


        }    }                                   

    private void rollDice() throws IOException {
        jButton1.setVisible(false);
        is = new TimerImageSwapper(jLabel1, jLabel2);
        Random rand = new Random();
        int res = 1 + rand.nextInt(6);
        is.main(this, res);

        revalidate();
        repaint();

        {

        }
    }

    private static void updateCsvFile(String sFileName, Long id, Integer result, Date time) throws IOException {

        try (FileWriter writer = new FileWriter(sFileName, true)) {
            writer.append(id.toString());
            writer.append(',');
            writer.append(result.toString());
            writer.append(',');
            writer.append(time.toString());
            writer.append('\n');
            writer.flush();
        } catch (Exception e) {
        }

    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;

                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(Roll.class
                    .getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(Roll.class
                    .getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(Roll.class
                    .getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(Roll.class
                    .getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
    }
    private javax.swing.JLabel jlabel1;
    TimerImageSwapper is;
    // Variables declaration - do not modify                     
    private javax.swing.JButton jButton1;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    // End of variables declaration                   

}

TimerImageSwapper looks like this:

package nofis;

import java.awt.Component;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.swing.*;

public class TimerImageSwapper {

    public static final String[] IMAGES = {
        "dice1.png",
        "dice2.png",
        "dice3.png",
        "dice4.png",
        "dice5.png",
        "dice6.png"
    };

    private static final int TIMER_DELAY = 100;

    private ImageIcon[] icons = new ImageIcon[IMAGES.length];
    private final JLabel mainLabel;// = new JLabel();

    private int iconIndex = 0;
    private int max = 30;
    private int count = 0;
    public int res = 1;
    Timer timer = null;
    JLabel result =null;
    public boolean done = false;
    public TimerImageSwapper(JLabel mainLabel,JLabel jLabel2) throws IOException {
        for (int i = 0; i < icons.length; i++) {
            BufferedImage image = ImageIO.read(new File(IMAGES[i]));
            icons[i] = new ImageIcon(image);
        }
        this.mainLabel = mainLabel;
        this.result=jLabel2;


        mainLabel.setIcon(icons[iconIndex]);

        timer = new Timer(TIMER_DELAY, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                Random rand = new Random();
                if (count >= max) {
                    timer.stop();
                    done=true;

                    res = iconIndex;
                    mainLabel.setIcon(icons[res-1]);
                    result.setFont(new java.awt.Font("Arial", Font.BOLD, 20));
                    result.setText("text: " + Integer.toString(res));

                    return;
                }
                count++;
                iconIndex=rand.nextInt(6)+1;
                mainLabel.setIcon(icons[iconIndex-1]);
            }
        });
        timer.start();
    }


    public Component getMainComponent() {
        return mainLabel;
    }

    private void createAndShowGui() {
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(this.getMainComponent());
        frame.setVisible(true);

    }
    JFrame frame;

    public void main(JFrame frame, int result) {
        this.frame = frame;
        res=result;

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {

                createAndShowGui();
            }
        });
    }
}

I am aware that I've got plenty of badly executed code and would appreciate any tips.

Thanks.

  • There is a reason why we discourage the use of KeyListener as a general rule, instead, we recommend the use of the key bindings API
  • Also, you shouldn't be using a KeyListener on buttons, when happens if the user clicks the button with the mouse? Instead, you should be using a ActionListener . See How to Use Buttons, Check Boxes, and Radio Buttons and How to Write an Action Listener
  • while (!is.done) { is going to cause you issues as Swing is single threaded, so you should never do anything that will block the Event Dispatching Thread, this will prevent the UI from been updated or respond to a new events. Have a look at Concurrency in Swing for more details. In your case, I'd consider using a Observer Pattern , which your Timer would trigger a notification which your Roll class would respond to

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM