1

I'm trying to make an ActionListener for a specific JComponent, but in my code, there are two JComponents which have ActionListeners.

Here's my code:

/**
 * This is a Java Swing program that lets you play Minesweeper! Make sure to play it in fullscreen or else it's not going to work.
 * @author  Joshua Diocares
 * @version  JDK14.0
 * @since  Still in development!
 */

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;

/**
 * A class that shows the xy coordinates near the mouse cursor.
 */
class AlsXYMouseLabelComponent extends JComponent {

  public int x;
  public int y;

  /**
   * Uses the xy coordinates to update the mouse cursor label.
   */
  @Override
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    String coordinates = x + ", " + y; // Get the cordinates of the mouse
    g.setColor(Color.red);
    g.drawString(coordinates, x, y); // Display the coordinates of the mouse
  }

}

public class Minesweeper implements ActionListener {

  private static JComboBox < String > gameModeDropdown;
  private static JComboBox < String > difficultyDropdown;

  public static void main(String[] args) {

    JPanel panel = new JPanel();

    JFrame frame = new JFrame();
    frame = new JFrame();
    frame.setSize(1365, 767);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setTitle("Tic Tac Toe");
    frame.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
    frame.setVisible(true);
    frame.add(panel);

    panel.setLayout(null);

    AlsXYMouseLabelComponent alsXYMouseLabel = new AlsXYMouseLabelComponent();

    /**
     * Add the component to the DRAG_LAYER of the layered pane (JLayeredPane)
     */
    JLayeredPane layeredPane = frame.getRootPane().getLayeredPane();
    layeredPane.add(alsXYMouseLabel, JLayeredPane.DRAG_LAYER);
    alsXYMouseLabel.setBounds(0, 0, frame.getWidth(), frame.getHeight());

    /**
     * Add a mouse motion listener, and update the crosshair mouse cursor with the xy coordinates as the user moves the mouse
     */
    frame.addMouseMotionListener(new MouseMotionAdapter() {

      /**
       * Detects when the mouse moved and what the mouse's coordinates are.
       * @param event the event that happens when the mouse is moving.
       */
      @Override
      public void mouseMoved(MouseEvent event) {
        alsXYMouseLabel.x = event.getX();
        alsXYMouseLabel.y = event.getY();
        alsXYMouseLabel.repaint();
      }

    });

    JLabel title = new JLabel("Minesweeper");
    title.setBounds(500, 100, 550, 60);
    title.setFont(new Font("Verdana", Font.PLAIN, 50));
    panel.add(title);

    JLabel gameModePrompt = new JLabel("Game Mode: ");
    gameModePrompt.setBounds(280, 335, 300, 25);
    gameModePrompt.setFont(new Font("Verdana", Font.PLAIN, 20));
    panel.add(gameModePrompt);

    String[] gameModes = {
      "Normal"
    };
    JComboBox < String > gameModeDropdown = new JComboBox < String > (gameModes);
    gameModeDropdown.setBounds(415, 335, 290, 25);
    gameModeDropdown.setFont(new Font("Verdana", Font.PLAIN, 20));
    gameModeDropdown.addActionListener(new Minesweeper());
    panel.add(gameModeDropdown);

    JLabel difficultyPrompt = new JLabel("Difficulty: ");
    difficultyPrompt.setBounds(800, 335, 240, 25);
    difficultyPrompt.setFont(new Font("Verdana", Font.PLAIN, 20));
    panel.add(difficultyPrompt);

    String[] difficulties = {
      "Medium"
    };
    JComboBox < String > difficultyDropdown = new JComboBox < String > (difficulties);
    difficultyDropdown.setBounds(910, 335, 120, 25);
    difficultyDropdown.setFont(new Font("Verdana", Font.PLAIN, 20));
    panel.add(difficultyDropdown);

    JButton playButton = new JButton("Play");
    playButton.setBounds(530, 480, 220, 25);
    playButton.setFont(new Font("Verdana", Font.PLAIN, 20));
    playButton.addActionListener(new Minesweeper());
    panel.add(playButton);

  }


  @Override
  public void actionPerformed(ActionEvent e) {

  }

}

Any suggestions would be really helpful

Frakcool
  • 10,915
  • 9
  • 50
  • 89
  • 1
    I think [this](https://stackoverflow.com/questions/5936261/how-to-add-action-listener-that-listens-to-multiple-buttons) thread answers your question – gerynix Jul 16 '20 at 17:23
  • *"`Make sure to play it in fullscreen or else it's not going to work.`"* I was about to delete that code comment as irrelevant to the question, but it raises a number of issues. 1) Don't tell the user what to do. If an app. absolutely requires full-screen, call [`Frame.setExtendedState(MAXIMIZED_BOTH)`](https://docs.oracle.com/en/java/javase/13/docs/api/java.desktop/java/awt/Frame.html#setExtendedState(int)). Then call `setResizable(false)`, **But..** 2) `frame.setSize(1365, 767);` both contradicts the code comment **as well as** being wider than my screen! 3) **And *most* importantly..** – Andrew Thompson Jul 17 '20 at 01:11
  • 1
    Don't. Use. Null. Layouts! Java GUIs have to work on different OS', screen size, screen resolution etc. using different PLAFs in different locales. As such, they are not conducive to pixel perfect layout. Instead use layout managers, or [combinations of them](http://stackoverflow.com/a/5630271/418556) along with layout padding and borders for [white space](http://stackoverflow.com/a/17874718/418556). 4) `alsXYMouseLabel.setBounds(0, 0, frame.getWidth(), frame.getHeight());` Well the layout conundrum continues! No component in a `JFrame` can be as wide & tall as the frame given it's borders! – Andrew Thompson Jul 17 '20 at 01:13
  • `frame.setSize(1365, 767)` does not contradict the code comment. The app is still technically not in full-screen, the frame just covers the whole screen, making it _look_ like it is. And please don't embarrass me with your second comment. I'm sorry I made my layout set to null, so please forgive me. – XeroxMachine808 Jul 17 '20 at 04:17
  • @gerynix that thread does not answer my question. I do know how to make `ActionListener`s for `JComponent`s, but I'm trying to add `ActionListener`s to specific `JComponent`s. – XeroxMachine808 Jul 17 '20 at 04:26
  • @AndrewThompson your second comment was kinda embarrassing, and to that comment I say, "G#d f###, I hate my life." Sorry for the profanity of the comment. My point is that your comment's tone was really harsh and it embarrassed me. Also, remember that I'm a new contributor, so please be nice to me. – XeroxMachine808 Jul 17 '20 at 04:28
  • If you're going to have more than one ActionListener, you can't implement them as part of the main class. You have to create a separate inner class for each ActionListener you want to implement. – Gilbert Le Blanc Jul 17 '20 at 14:28
  • @AndrewThompson, having a tone harsh enough can demotivate and deter people from coding. They feel like they're embarrassed that they're doing bad coding practices. They feel demotivated. They are pushed to a corner where they don't enjoy coding anymore. They don't even bother with coding anymore when someone like you has a really harsh tone. So please don't make any more comments like that, or else I'm going to report you and you'll never comment or answer on my questions ever again. – XeroxMachine808 Jul 19 '20 at 01:23
  • @GilbertLeBlanc can you show me a code snippet of what that looks like? – XeroxMachine808 Jul 19 '20 at 01:32

1 Answers1

1

I cleaned up your code. I added a PlayListener class as the ActionListener to your Play button. You don't need an ActionListener for either dropdown. You can get the selected dropdown values when you need them in the PlayListener class.

I added a call to the SwingUtilities invokeLater method. This method ensures that your Swing components are created and executed on the Event Dispatch Thread.

I rearranged your JFrame method calls. I don't know if you noticed, but you made the JFrame visible before you created the components. You have to create all the components before you display your JFrame.

Using a null layout and absolute positioning are discouraged. Swing GUIs have to run on different operating systems with different screen monitor pixel sizes. Your GUI barely fit on my monitor. I left your absolute positioning code alone, but in the future, you should learn to use Swing layout managers.

I made the AlsXYMouseLabelComponent class an inline class. You can have as many inline classes as you want. Generally, though, each class should be in a separate file. I made the classes inline to show you how inline classes are defined, and also so I can paste a runnable example file.

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Minesweeper implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Minesweeper());
    }

    private JComboBox<String> gameModeDropdown;
    private JComboBox<String> difficultyDropdown;

    @Override
    public void run() {
        JPanel panel = new JPanel();

        JFrame frame = new JFrame("Minesweeper");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));

        panel.setLayout(null);

        AlsXYMouseLabelComponent alsXYMouseLabel =
                new AlsXYMouseLabelComponent();

        /**
         * Add the component to the DRAG_LAYER of the layered pane (JLayeredPane)
         */
        JLayeredPane layeredPane = frame.getRootPane().getLayeredPane();
        layeredPane.add(alsXYMouseLabel, JLayeredPane.DRAG_LAYER);
        alsXYMouseLabel.setBounds(0, 0, frame.getWidth(), frame.getHeight());

        /**
         * Add a mouse motion listener, and update the crosshair mouse cursor with the
         * xy coordinates as the user moves the mouse
         */
        frame.addMouseMotionListener(new MouseMotionAdapter() {

            /**
             * Detects when the mouse moved and what the mouse's coordinates are.
             *
             * @param event the event that happens when the mouse is moving.
             */
            @Override
            public void mouseMoved(MouseEvent event) {
                alsXYMouseLabel.x = event.getX();
                alsXYMouseLabel.y = event.getY();
                alsXYMouseLabel.repaint();
            }

        });

        JLabel title = new JLabel("Minesweeper");
        title.setBounds(500, 100, 550, 60);
        title.setFont(new Font("Verdana", Font.PLAIN, 50));
        panel.add(title);

        JLabel gameModePrompt = new JLabel("Game Mode: ");
        gameModePrompt.setBounds(280, 335, 300, 25);
        gameModePrompt.setFont(new Font("Verdana", Font.PLAIN, 20));
        panel.add(gameModePrompt);

        String[] gameModes = { "Normal" };
        gameModeDropdown = new JComboBox<String>(gameModes);
        gameModeDropdown.setBounds(415, 335, 290, 25);
        gameModeDropdown.setFont(new Font("Verdana", Font.PLAIN, 20));
        panel.add(gameModeDropdown);

        JLabel difficultyPrompt = new JLabel("Difficulty: ");
        difficultyPrompt.setBounds(800, 335, 240, 25);
        difficultyPrompt.setFont(new Font("Verdana", Font.PLAIN, 20));
        panel.add(difficultyPrompt);

        String[] difficulties = { "Easy", "Medium", "Hard" };
        difficultyDropdown = new JComboBox<String>(difficulties);
        difficultyDropdown.setSelectedIndex(1);
        difficultyDropdown.setBounds(910, 335, 120, 25);
        difficultyDropdown.setFont(new Font("Verdana", Font.PLAIN, 20));
        panel.add(difficultyDropdown);

        JButton playButton = new JButton("Play");
        playButton.setBounds(530, 480, 220, 25);
        playButton.setFont(new Font("Verdana", Font.PLAIN, 20));
        playButton.addActionListener(new PlayListener());
        panel.add(playButton);

        frame.add(panel);
        frame.setSize(1365, 767);
        frame.setVisible(true);
    }

    public class PlayListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent event) {
            // TODO Auto-generated method stub

        }

    }

    /**
     * A class that shows the xy coordinates near the mouse cursor.
     */
    public class AlsXYMouseLabelComponent extends JComponent {

        private static final long serialVersionUID = 1L;

        public int x;
        public int y;

        /**
         * Uses the xy coordinates to update the mouse cursor label.
         */
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            String coordinates = x + ", " + y; // Get the cordinates of the mouse
            g.setColor(Color.red);
            g.drawString(coordinates, x, y); // Display the coordinates of the mouse
        }

    }

}
Gilbert Le Blanc
  • 50,182
  • 6
  • 67
  • 111