0

I'm working on this code in which I need to draw a house. The house has a door(rectangle) that randomly changes color with a mouse click. Everything else besides the door doesn't change color at all.

How to make the color of the door change on mouse click?

package finalExam;  

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


public class Final  extends JFrame{         

    public Final(){

        setTitle("An Interactive House");
        setSize(500, 500);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setVisible(true);
    }


    public void paint(Graphics g){


        int [] xCoords = { 40, 250, 460 };
        int [] yCoords = { 200, 50, 200 };

        super.paint(g);         

        g.drawRect(80, 200, 330, 260);

        g.drawPolygon(xCoords , yCoords , 3);

        g.setColor(Color.black);
        g.fillRect(190, 330, 100, 130);
        addMouseListener(new MouseEventListener());

        g.setColor(Color.white);
        g.fillOval(280, 400, 5, 5);


    }

    private class MouseEventListener implements MouseListener{

        public void mouseClicked(MouseEvent arg0){

            repaint();

        }
        public void mouseEntered(MouseEvent arg0){

        }
        public void mouseExited(MouseEvent arg0){

        }           
        public void mousePressed(MouseEvent arg0){

        }
        public void mouseReleased(MouseEvent arg0){

        }
    }

        public static void main(String[] args){
            new Final();
        }

    }
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Seung
  • 11
  • 1
  • 2
    Don't override `paint`, especially of a top level container like `JFrame`, this is going to cause no end of issues. Start with a `JPanel` and override its `paintComponent` method instead, make you preserve the paint chain by calling it's super method – MadProgrammer May 17 '17 at 03:48
  • Add a series of colors to an array, use `Math.random` to generate a random value between `0` and the arrays `length`, use that as the next color to paint the door – MadProgrammer May 17 '17 at 03:48
  • `The house has a door(rectangle) that randomly changes color with a mouse click` is that a good or a bad thing? I'm guessing it's a bad thing for you, so you need to set the color with `g.setColor(...)` **before** you do any drawing, otherwise it could have the color that was used in a previous component / drawing operation. – Erwin Bolwidt May 17 '17 at 03:51
  • Don't add a listener to a component in a painting method. The painting method is executed every time the component is repainted to you don't want to keep adding listeners. – camickr May 17 '17 at 03:51
  • stupid solution: replace `g.setColor(Color.black);` with `Random rnd = new Random();g.setColor(new Color(rnd.nextFloat(),rnd.nextFloat(),rnd.nextFloat()));` – Iłya Bursov May 17 '17 at 03:59

2 Answers2

3

Okay, there's a couple of problems that need to be addressed; but hey, what else is StackOverflow for?

  1. Every time paint(Graphics g) is called, you're creating and assigning a new MouseEventListener. Really, this is something you'd only want to do once upon initialization, unless you can forsee multiple MouseEventListeners needing to receive updates in future; but even then, you wouldn't want to do it repeatedly in the rendering process anyway; you'd rather do it asynchronously elsewhere. Whatever logic you ever place in any kind of rendering operation, it should only be to do with rendering, or executing tasks that need to be synchronized on each render pass. When you register a MouseEventListener on this class, I'm sure you'd want it to receive events for the lifetime of your application; not get constantly overwritten!
  2. You're using setColor(Color.BLACK) and setColor(Color.WHITE); these are constants! If you want to change the colour, they'll need to become variables. Try placing them as member variables in your class, i.e.

    public final class Final extends JFrame{   
        /* Member Variables. */
        Color mDoorColor  = Color.BLACK;
        Color mHouseColor = Color.WHITE;
    

    Then use these colours in your rendering; i.e. setColor(this.mDoorColor);. When they're member variables, you can start reading and writing to them; which means that you can persist certain colours for your graphical routines, but also change them as you go! i.e. this.mHouseColor = Color.CYAN;

  3. When you do create your MouseListener, (I suggest making your class Final implement the MouseListener interface), you can update your values for mDoorColor and mHouseColor in there. Then you can assign a random color to your random variables.

  4. Try better naming conventions. Calling your class Final is too similar to a reserved keyword, final. It's not a very helpful name to call your class, should anybody else takeover. How about something different, like MouseHousePainter? MouseDrivenHouseDecorator?

  5. Finally, like MadProgrammer mentioned, the JFrame is a very powerful graphics class in Java; you don't want to override its paint method. Here's a nice example of his suggested design approach. (Not so mad after all, huh.)

Community
  • 1
  • 1
Mapsy
  • 4,192
  • 1
  • 37
  • 43
1

I have created your program that changes door's color on mouse click.

I added JPanel to draw house and used Random.nextFloat to create random color in paintComponent method. Like this

package com.stackoverflow.main;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Final extends JFrame {
    Random rnd = new Random();
    JPanel panel;

    public Final() {

        setTitle("An Interactive House");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        super.setSize(500, 500);

        addMouseListener(new MouseEventListener());

        panel = new JPanel() {
            @Override
            public void paintComponent(Graphics g) {
                super.paintComponent(g);

                paintHouse(g);
            }
        };
        getContentPane().add(panel);

        setVisible(true);
    }

    public void paintHouse(Graphics g) {

        int[] xCoords = { 40, 250, 460 };
        int[] yCoords = { 200, 50, 200 };

        // super.paint(g);

        g.drawRect(80, 200, 330, 260);

        g.drawPolygon(xCoords, yCoords, 3);

        g.setColor(new Color(rnd.nextFloat(), rnd.nextFloat(), rnd.nextFloat()));
        g.fillRect(190, 330, 100, 130);

        g.setColor(Color.white);
        g.fillOval(280, 400, 5, 5);

    }

    private class MouseEventListener extends MouseAdapter {

        public void mouseClicked(MouseEvent arg0) {

            panel.repaint();

        }
    }

    public static void main(String[] args) {
        new Final();
    }

}

I changed MouseListener to MouseAdapter as you need only mouseClicked.

Jay Smith
  • 2,331
  • 3
  • 16
  • 27
  • Thanks so much!!! Though when the user open the window, the initial color of the door should be black before the user clicks on the door to change color. How should I approach to fix the code? – Seung May 18 '17 at 02:54
  • Create class level variable `Color doorColor = Color.BLACK;`. In `paintHouse` method use `g.setColor(doorColor)`. In `MouseEventListener.mouseClicked` write `doorColor = new Color(rnd.nextFloat(), rnd.nextFloat(), rnd.nextFloat())` – Jay Smith May 19 '17 at 18:12