Geroy290
Geroy290

Reputation: 478

How to add a mouse hover listener to a rectangle in Java

I am trying to make a button using the Rectangle object and am also trying to make the color change on hover, and it will not change. I have made my code have more generic names for variables that way it would not confuse, here it is:

public class MouseHandler extends MouseAdapter {
    @Override
    public void mouseMoved(MouseEvent e) {
        int mx = e.getX();
        int my = e.getY();
        if(mx > button.x && mx < button.x+button.width &&
                my > button.y && my < button.y+button.height) {
                buttonHover = true;
        } else {
                buttonHover = false;

        }
    }
}

And I tried calling these lines of code also, but it wouldn't work:

if(buttonHover)
g.setColor(hoverColor);
g.drawRect(button.x, button.y, button.width, button.height);

I will put my full code at the bottom, with the actual variable names. Thanks for the help!

package trivia;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;

@SuppressWarnings("serial")
public class Main extends JFrame{

boolean mainMenu = true;
boolean startHover;
static Color tan = Color.decode("#F4EBC3");
static Color darkGreen = Color.decode("#668284");
static Color buttonColor = Color.decode("#A2896B");
static Color borderColor = Color.decode("#333333");
static Color buttonHover = Color.decode("#F5B66E");
Rectangle header = new Rectangle(0, 0, 500, 100);
Rectangle body = new Rectangle(0, 100, 500, 400);
Rectangle start = new Rectangle(150, 150, 200, 40);
Rectangle howToPlay = new Rectangle(150, 225, 200, 40);
Rectangle quit = new Rectangle(150, 300, 200, 40);

public Main() {
    setTitle("Trivia Game!");
    setSize(500, 500);
    setVisible(true);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLocationRelativeTo(null);

}
@Override
public void paint(Graphics g) {
    Dimension d = this.getSize();
    if(mainMenu = true){
        g.setColor(darkGreen);
        g.fillRect(header.x, header.y, header.width, header.height);
        g.setFont(new Font("Courier", Font.BOLD, 24));
        g.setColor(Color.BLACK);
        drawCenteredString("Trivia Game!", d.width, 125, g);
        g.setColor(tan);
        g.fillRect(body.x, body.y, body.width, body.height);
        g.setColor(buttonColor);
        g.fillRect(start.x, start.y, start.width, start.height);
        g.setColor(borderColor);
        g.drawRect(start.x, start.y, start.width, start.height);
        g.setFont(new Font("Courier", Font.BOLD, 20));
        g.setColor(Color.black);
        drawCenteredString("Start", d.width, 340, g);
        g.setColor(buttonColor);
        g.fillRect(howToPlay.x, howToPlay.y, howToPlay.width, howToPlay.height);
        g.setColor(borderColor);
        g.drawRect(howToPlay.x, howToPlay.y, howToPlay.width, howToPlay.height);
        g.setFont(new Font("Courier", Font.BOLD, 20));
        g.setColor(Color.black);
        drawCenteredString("How To Play", d.width, 490, g);
        g.setColor(buttonColor);
        g.fillRect(quit.x, quit.y, quit.width, quit.height);
        g.setColor(borderColor);
        g.drawRect(quit.x, quit.y, quit.width, quit.height);
        g.setFont(new Font("Courier", Font.BOLD, 20));
        g.setColor(Color.black);
        drawCenteredString("Quit?", d.width, 640, g);
        g.setColor(buttonColor);
        g.fillRect(start.x, start.y, start.width, start.height);
        g.setColor(borderColor);
        g.drawRect(start.x, start.y, start.width, start.height);
        g.setFont(new Font("Courier", Font.BOLD, 20));
        g.setColor(Color.black);
        drawCenteredString("Start", d.width, 340, g);
        if(startHover)
            g.setColor(buttonHover);
            g.drawRect(start.x, start.y, start.width, start.height);
    }
}
public void drawCenteredString(String s, int w, int h, Graphics g) {
    FontMetrics fm = g.getFontMetrics();
    int x = (w - fm.stringWidth(s)) / 2;
    int y = (fm.getAscent() + (h- (fm.getAscent() + fm.getDescent())) / 2);
    g.drawString(s, x, y);
}

public static void main(String[] args) {
    @SuppressWarnings("unused")
    Main m = new Main();
}
public class MouseHandler extends MouseAdapter {
    @Override
    public void mouseMoved(MouseEvent e) {
        int mx = e.getX();
        int my = e.getY();
        if(mx > start.x && mx < start.x+start.width &&
                my > start.y && my < start.y+start.height) {
                startHover = true;
                System.out.println("yes");
        } else {
                startHover = false;
                System.out.println("no");
        }
    }
}
}

Upvotes: 0

Views: 6180

Answers (2)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285403

You've several issues going on here:

  • You're doing drawing directly within a JFrame, a dangerous thing to do, since JFrames hold many components, several I'm sure that you're not familiar with, including borders, rootpane, glasspane, and contentpane, and if you mess up painting, it can mess up the drawing of these critical components.
  • Also by painting inside of a paint method, you loose all the advantages of Swing graphics.
  • Also you appear to have most of your program design and logic within a painting method, something that you should never do since you don't have full control over when or even if that method gets called.
  • Instead, you should create your button component in its own class, separate from the JFrame
  • Give your class ability to be placed in a JPanel
  • And give it a rollover capability.
  • For my money though, I'd just extend a JButton or better, just use a JButton, and make it look the way I want rather than trying to re-invent the wheel.

e.g.,

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.GridLayout;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

@SuppressWarnings("serial")
public class Main2 extends JPanel {
   private static final Color TAN = Color.decode("#F4EBC3");
   private static final Color DARK_GREEN = Color.decode("#668284");
   private static final Color BUTTON_COLOR = Color.decode("#A2896B");
   private static final Color BORDER_COLOR = Color.decode("#333333");
   private static final Color BUTTON_ROLLOVER_COLOR = Color.decode("#F5B66E");
   private static final String TITLE = "Trivia Game!";
   private static final Font TITLE_FONT = new Font("Courier", Font.BOLD, 24);
   private static final int PREF_W = 500;
   private static final int PREF_H = PREF_W - 30;
   private JButton startButton;
   private JButton howToPlayButton;
   private JButton quitButton;


   public Main2() {
      JLabel titleLabel = new JLabel(TITLE, SwingConstants.CENTER);
      titleLabel.setFont(TITLE_FONT);
      int blGap = 15;
      titleLabel.setBorder(BorderFactory.createEmptyBorder(blGap, blGap, blGap, blGap));
      JPanel titlePanel = new JPanel(new GridBagLayout());
      titlePanel.setBackground(DARK_GREEN);
      titlePanel.add(titleLabel);

      JPanel centerInnerPanel = new JPanel(new GridLayout(0, 1, blGap, 2 * blGap));
      centerInnerPanel.setOpaque(false);
      centerInnerPanel.setBorder(BorderFactory.createEmptyBorder(blGap, blGap, blGap, blGap));
      centerInnerPanel.add(startButton = createButton("Start"));
      centerInnerPanel.add(howToPlayButton = createButton("How To Play"));
      centerInnerPanel.add(quitButton = createButton("Quit?"));

      JPanel centerOuterPanel = new JPanel(new GridBagLayout());
      centerOuterPanel.setBackground(TAN);
      centerOuterPanel.add(centerInnerPanel);


      setLayout(new BorderLayout());
      add(titlePanel, BorderLayout.PAGE_START);
      add(centerOuterPanel, BorderLayout.CENTER);
   }

   private JButton createButton(String name) {
      final JButton button = new JButton(name);
      button.setFont(TITLE_FONT.deriveFont(20F));
      button.setBackground(BUTTON_COLOR);
      Border emptyBorder = BorderFactory.createEmptyBorder(5, 25, 5, 25);
      Border lineBorder = BorderFactory.createLineBorder(BORDER_COLOR);
      Border nestedBorder = BorderFactory.createCompoundBorder(lineBorder, emptyBorder);
      button.setBorder(nestedBorder);


      button.getModel().addChangeListener(new ChangeListener() {

         @Override
         public void stateChanged(ChangeEvent e) {
            ButtonModel model = (ButtonModel)e.getSource();
            if (model.isRollover()) {
               button.setBackground(BUTTON_ROLLOVER_COLOR);
            } else {
               button.setBackground(BUTTON_COLOR);
            }
         }
      });

      return button;
   }

   @Override
   public Dimension getPreferredSize() {
      if (isPreferredSizeSet()) {
         return super.getPreferredSize();
      }
      int w = Math.max(super.getPreferredSize().width, PREF_W);
      int h = Math.max(super.getPreferredSize().height, PREF_H);

      return new Dimension(w, h);
   }

   private static void createAndShowGui() {
      Main2 mainPanel = new Main2();

      JFrame frame = new JFrame("Main2");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

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

Upvotes: 2

Ya Wang
Ya Wang

Reputation: 1808

I'll start with...

1) If it truly just a rectangle you want to deal with. Please use https://docs.oracle.com/javase/7/docs/api/java/awt/Rectangle.html , Java has been kind enough to make your life simple please don't throw it away. (ignore this keeping here for reference)

2) You should implement MouseMotionListener... I did it for you.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JFrame;

@SuppressWarnings("serial")
public class test extends JFrame  implements MouseMotionListener {

boolean mainMenu = true;
boolean startHover;
static Color tan = Color.decode("#F4EBC3");
static Color darkGreen = Color.decode("#668284");
static Color buttonColor = Color.decode("#A2896B");
static Color borderColor = Color.decode("#333333");
static Color buttonHover = Color.decode("#F5B66E");
Rectangle header = new Rectangle(0, 0, 500, 100);
Rectangle body = new Rectangle(0, 100, 500, 400);
Rectangle start = new Rectangle(150, 150, 200, 40);
Rectangle howToPlay = new Rectangle(150, 225, 200, 40);
Rectangle quit = new Rectangle(150, 300, 200, 40);

public test() {
    setTitle("Trivia Game!");
    setSize(500, 500);
    setVisible(true);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLocationRelativeTo(null);
    this.addMouseMotionListener(this);
}

@Override
public void paint(Graphics g) {
    Dimension d = this.getSize();
    if (mainMenu = true) {
        g.setColor(darkGreen);
        g.fillRect(header.x, header.y, header.width, header.height);
        g.setFont(new Font("Courier", Font.BOLD, 24));
        g.setColor(Color.BLACK);
        drawCenteredString("Trivia Game!", d.width, 125, g);
        g.setColor(tan);
        g.fillRect(body.x, body.y, body.width, body.height);
        g.setColor(buttonColor);
        g.fillRect(start.x, start.y, start.width, start.height);
        g.setColor(borderColor);
        g.drawRect(start.x, start.y, start.width, start.height);
        g.setFont(new Font("Courier", Font.BOLD, 20));
        g.setColor(Color.black);
        drawCenteredString("Start", d.width, 340, g);
        g.setColor(buttonColor);
        g.fillRect(howToPlay.x, howToPlay.y, howToPlay.width,
                howToPlay.height);
        g.setColor(borderColor);
        g.drawRect(howToPlay.x, howToPlay.y, howToPlay.width,
                howToPlay.height);
        g.setFont(new Font("Courier", Font.BOLD, 20));
        g.setColor(Color.black);
        drawCenteredString("How To Play", d.width, 490, g);
        g.setColor(buttonColor);
        g.fillRect(quit.x, quit.y, quit.width, quit.height);
        g.setColor(borderColor);
        g.drawRect(quit.x, quit.y, quit.width, quit.height);
        g.setFont(new Font("Courier", Font.BOLD, 20));
        g.setColor(Color.black);
        drawCenteredString("Quit?", d.width, 640, g);
        g.setColor(buttonColor);
        g.fillRect(start.x, start.y, start.width, start.height);
        g.setColor(borderColor);
        g.drawRect(start.x, start.y, start.width, start.height);
        g.setFont(new Font("Courier", Font.BOLD, 20));
        g.setColor(Color.black);
        drawCenteredString("Start", d.width, 340, g);
        if (startHover)
            g.setColor(buttonHover);
        g.drawRect(start.x, start.y, start.width, start.height);
    }
}

public void drawCenteredString(String s, int w, int h, Graphics g) {
    FontMetrics fm = g.getFontMetrics();
    int x = (w - fm.stringWidth(s)) / 2;
    int y = (fm.getAscent() + (h - (fm.getAscent() + fm.getDescent())) / 2);
    g.drawString(s, x, y);
}

public static void main(String[] args) {
    @SuppressWarnings("unused")
    test m = new test();
}

@Override
public void mouseDragged(MouseEvent arg0) {
    // TODO Auto-generated method stub

}

@Override
public void mouseMoved(MouseEvent e) {
    System.out.println("lol");
    int mx = e.getX();
    int my = e.getY();
    if (mx > start.x && mx < start.x + start.width && my > start.y
            && my < start.y + start.height) {
        startHover = true;
        System.out.println("yes");
    } else {
        startHover = false;
        System.out.println("no");
    }
}
}

If you read below you can see there are a lot of things wrong with your code. Don't let that scare you from learning. Do it step by step and you will be fine.

Upvotes: 3

Related Questions