I have a JFrame, comprised of three JPanel containers, each panel has a filled-in circle (for example, red, white blue).
What I'd like to be able to do is update the color of the filled-in circle of that panel (make it darker with Color.RED.darker, for example) when that particular panel is clicked
I can't use an ActionListener, since panels aren't components but containers. I started out using MouseListener, but have now updated this to MouseAdapter. I am able to determine which JPanel was clicked - for testing purposes I'm printing out which panel was clicked to the console (for simplicity purposes I added a name to each panel).
EDIT: I got this mostly working - I can now repaint() the Jpanel that was clicked, making that cricle color darker, using the suggestion below of creating a setCircleColor (color) method, which calls repaint().This redraws the circle in that panel, using a darker color.
However, what I really also need to do is make the other two (non-clicked) cirlces on the other panels to repaint() with lighter colors.
But I can't see an easy way to handle this - how can I manipulate the other Jpanels that I didn't click on?
Here's my code:
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class TrafficLight {
// sets up the frame, calls the circle panels and adds them to the frame
public static void setUpGui() {
JFrame frame = new JFrame("Traffic Lights");
frame.setSize(300, 900);
frame.setLayout(new GridLayout(3, 0));
DrawCirclePanel redCircle = new DrawCirclePanel(Color.RED);
DrawCirclePanel yellowCircle = new DrawCirclePanel(Color.YELLOW);
DrawCirclePanel greenCircle = new DrawCirclePanel(Color.GREEN);
redCircle.setName("redCircle");
yellowCircle.setName("yellowCircle");
greenCircle.setName("greenCircle");
CircleListener cl = new CircleListener();
redCircle.addMouseListener(cl);
yellowCircle.addMouseListener(cl);
greenCircle.addMouseListener(cl);
frame.add(redCircle);
frame.add(yellowCircle);
frame.add(greenCircle);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setVisible(true);
}
public static void main(String[] args) {
setUpGui();
}
}
// the DrawCirclePanel class creates a panel and
// draws a filled-in circle on the panel
class DrawCirclePanel extends JPanel {
Color c;
Border blackline = BorderFactory.createLineBorder(Color.black);
// constructor for panel, takes Color as argument
// so we know what color circle to make
public DrawCirclePanel(Color color) {
this.c = color;
this.setLayout(new GridLayout(1, 0));
this.setBorder(blackline);
}
// draws the circle in the panel
public void paintComponent(Graphics g) {
super.paintComponent(g);
int xWidth = this.getParent().getWidth();
g.setColor(c);
g.fillOval(1, 1, xWidth-1, xWidth-1);
}
public void setCircleColor(Color color) {
this.c = color;
this.getGraphics().setColor(c);
this.repaint();
}
}
class CircleListener extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
DrawCirclePanel cPanel = (DrawCirclePanel) e.getSource();
System.out.println(cPanel);
String name = cPanel.getName();
if (name == "redCircle") {
cPanel.setCircleColor(Color.red.darker());
}
else if (name == "yellowCircle") {
cPanel.setCircleColor(Color.yellow.darker());
}
else {
cPanel.setCircleColor(Color.green.darker());
}
}
}
So the answer turned out to be fairly simple.
Declare the panels with the circles as static variables so that the MouseListener class can access all three of the panels.
As Andrew Thompson noted, set up a setCircleColor method in DrawCirclePanel that repaints the circle with a different color as needed.
In the MouseListener class, determine with panel was called, then repaint all three of the circles, passing in the correct color - darker() or brighter() - as needed.
Here's the final code
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.Color;
import java.awt.event.*;
import java.awt.event.MouseEvent;
public class TrafficLight {
static DrawCirclePanel redCircle;
static DrawCirclePanel yellowCircle;
static DrawCirclePanel greenCircle;
// sets up the frame, calls the circle panels and adds them to the frame
public static void setUpGui() {
JFrame frame = new JFrame("Traffic Lights");
frame.setSize(300, 900);
frame.setLayout(new GridLayout(3, 0));
redCircle = new DrawCirclePanel(Color.RED.brighter().brighter());
yellowCircle = new DrawCirclePanel(Color.YELLOW.darker().darker());
greenCircle = new DrawCirclePanel(Color.GREEN.darker().darker());
redCircle.setName("redCircle");
yellowCircle.setName("yellowCircle");
greenCircle.setName("greenCircle");
CircleListener cl = new CircleListener();
redCircle.addMouseListener(cl);
yellowCircle.addMouseListener(cl);
greenCircle.addMouseListener(cl);
frame.add(redCircle);
frame.add(yellowCircle);
frame.add(greenCircle);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setVisible(true);
}
public static void main(String[] args) {
setUpGui();
}
}
// the DrawCirclePanel class creates a panel and
// draws a filled-in circle on the panel
class DrawCirclePanel extends JPanel {
Color c;
Border blackLine = BorderFactory.createLineBorder(Color.BLACK);
// constructor for panel, takes Color as argument
// so we know what color circle to make
public DrawCirclePanel(Color color) {
this.c = color;
this.setLayout(new GridLayout(1, 0));
this.setBorder(blackLine);
}
// draws the circle in the panel
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int xWidth = this.getParent().getWidth();
g.setColor(c);
g.fillOval(0, 0, xWidth, xWidth);
}
// changes the color and calls repaint after a mouseClicked event
public void setCircleColor(Color color) {
this.c = color;
this.getGraphics().setColor(c);
this.repaint();
}
}
//abstract adapter class for receiving mouse events
class CircleListener extends MouseAdapter {
// determine which panel was clicked; redraws as brighter circle
// redraws other circles with dimmer (darker) color
public void mouseClicked(MouseEvent e) {
DrawCirclePanel cPanel = (DrawCirclePanel) e.getSource();
String name = cPanel.getName();
if (name.equals("redCircle")) {
TrafficLight.redCircle.setCircleColor(Color.RED.brighter().brighter());
TrafficLight.yellowCircle.setCircleColor(Color.YELLOW.darker().darker());
TrafficLight.greenCircle.setCircleColor(Color.GREEN.darker().darker());
} else if (name.equals("yellowCircle")) {
TrafficLight.redCircle.setCircleColor(Color.RED.darker().darker());
TrafficLight.yellowCircle.setCircleColor(Color.YELLOW.brighter().brighter());
TrafficLight.greenCircle.setCircleColor(Color.GREEN.darker().darker());
} else {
TrafficLight.redCircle.setCircleColor(Color.RED.darker().darker());
TrafficLight.yellowCircle.setCircleColor(Color.YELLOW.darker().darker());
TrafficLight.greenCircle.setCircleColor(Color.GREEN.brighter().brighter());
}
}
}
Related
I am trying to build a bounce game in Java. My project has three classes ie the Main class which creates a new window(frame) where the game buttons and bounce objects are drawn.
The GameInterface class which represents the properties of the frame being drawn and the RightPanel class which I created so that I could override the paint(Graphics) method to draw my bounce object. So far this is what I have managed to draw with the code.
You can see that I have two JPanels, one that holds my buttons and the other one that accepts the drawing of a round ball on it ie RightPanel
I need help with the Button Event listeners to move the ball up and down and when user holds the button down, it needs to keep moving down until reaches the down order, sam for the up button.
The code am using is provided below.
GameInterface class
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
public class GameInterface extends JFrame {
//we need this panel declaration in the class level for reference from other methods
RightPanel rightpanel;
//define the physical properties of the window
public GameInterface(){
setSize(new Dimension(600, 600));
setResizable(false);
setTitle("Bounce Game");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBackground(Color.black);
//define a new JSplitPane and use it to add two JPanels
JPanel leftpanel= new JPanel();
//add buttons to the left panel programatically
JButton up= new JButton("Move up");
//set the event listeners for the buttons
up.addActionListener(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
//move my ball up
//clear and redraw the ball while in a new position, use a timer or
something
}
});
JButton down = new JButton("Move down");
down.addActionListener(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
//move my ball down
// rightpanel.getGraphics.fillColor(Color.RED);
}
});
leftpanel.add(up);
leftpanel.add(down);
//add a new RightPanel with a drawn red object
rightpanel= new RightPanel();
JSplitPane splitpane= new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,leftpanel,rightpanel);
this.add(splitpane);
setVisible(true);
}
}
RightPanel class
import javax.swing.*;
import java.awt.*;
public class RightPanel extends JPanel {
//define the position where the circle will be drawn
private int positionX=150;
private int positionY=150;
//I had an idea where we need a timer and then on delay we
//decrement positionX by 3 for move down but can't figure out how to clear RightPanel
private int radius=100;//as the shape is a circle
//override the paint method to draw the bounce ball on the second panel
#Override
public void paint(Graphics g) {
g.setColor(Color.RED);
g.fillOval(positionX,positionY,radius,radius);
}
}
Main class
public class Main
{
public static void main(String args[]){
new GameInterface();
}
}
How do I add logic to my code to make it move the circle up an down, Thank You.
I tried using a timer object to clear the panel and then redraw the ball in the new position of the ball but it draws a vertical bar, not clearing the original ball drawn.
Never call getGraphics() on a component.
Override paintComponent not paint
Call the super.paintComponent(g) in your override.
Give the RightPanel class setter methods that allow you to change the positionX and positionY locations for drawing,
In the button listener, call an appropriate setter method, and then call repaint() on on the RightPanel instance after changing the positions.
For example:
The key code below is here in the ActionListener where you update the position values and call repaint:
moveRightBtn.addActionListener(e -> {
// get and update the x position
int x = drawOval.getPositionX();
x += DELTA;
// call the setter method
drawOval.setPositionX(x);
// request that Java repaint the JPanel
drawOval.repaint();
});
and in the drawing JPanel's paintComponent method where you call the super's method and draw the oval:
#Override
protected void paintComponent(Graphics g) {
// this is needed to do house-keeping painting, to clear "dirty" pixels
super.paintComponent(g);
// this is needed to draw smooth graphics
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(OVAL_COLOR);
g2.fillOval(positionX, positionY, RADIUS, RADIUS);
}
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.*;
#SuppressWarnings("serial")
public class MoveCircle extends JPanel {
private static final int DELTA = 5;
private DrawOval drawOval = new DrawOval();
public MoveCircle() {
JButton moveRightBtn = new JButton("Move Right");
moveRightBtn.addActionListener(e -> {
// get and update the x position
int x = drawOval.getPositionX();
x += DELTA;
// call the setter method
drawOval.setPositionX(x);
// request that Java repaint the JPanel
drawOval.repaint();
});
JPanel buttonPanel = new JPanel();
buttonPanel.add(moveRightBtn);
setLayout(new BorderLayout());
add(drawOval);
add(buttonPanel, BorderLayout.LINE_START);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
MoveCircle mainPanel = new MoveCircle();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
#SuppressWarnings("serial")
class DrawOval extends JPanel {
private static final int RADIUS = 100;
private static final int PANEL_WIDTH = 600;
private static final int PANEL_HEIGHT = 450;
private static final Color OVAL_COLOR = Color.RED;
private int positionX = 0;
private int positionY = 0;
public DrawOval() {
setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
}
public int getPositionX() {
return positionX;
}
public void setPositionX(int positionX) {
this.positionX = positionX;
}
public int getPositionY() {
return positionY;
}
public void setPositionY(int positionY) {
this.positionY = positionY;
}
#Override
protected void paintComponent(Graphics g) {
// this is needed to do house-keeping painting, to clear "dirty" pixels
super.paintComponent(g);
// this is needed to draw smooth graphics
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(OVAL_COLOR);
g2.fillOval(positionX, positionY, RADIUS, RADIUS);
}
}
i am making a simple GUI in which small boxes should appear on the Jpanel according to their x,y coordinates. So i in my structure i have got three classes:
1: MyFrame which contains the main JFrame
2: MyPanel extends JPanel
3: Icon extends JComponent
In my MyFrame i want to have a MenuBar through which i can open a file of X,Y coordinates and below the menu bar i want to have the MyPanel which will have all the Icons for each X,Y coordinates. The first problem i have is that the Icon do not appear on MyPanel when i add the Icons.
My code can be seen below:
public class MyFrame {
private JFrame frame;
private MyPanel panel;
public MyFrame(){
panel = new MyPanel();
}
/*
*HERE GOES THE `FILE OPEN` LISTENER
* it creates `Coordinate` for each line
* passes the coordinate to panel.makeIcons()
*/
public void createGui(){
frame = new JFrame("Graph Editor");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(true);
//create, get and set the Jframe menu bar
//createMenuBar() returns a JMenuBar
frame.setJMenuBar(createMenuBar());
Container frame_pane = frame.getContentPane();
panel.setBounds(0, 0, frame.getWidth(), frame.getHeight());
frame_pane.add(panel);
frame.pack();
frame.setVisible(true);
}
public static void main(String args[]){
MyFrame window = new MyFrame();
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
window.createGui();
}
});
}
}
Code For the panel for holding icons:
public class MyPanel extends JPanel{
private Set<Icon> points;
public MyPanel(){
setLayout(null);
setPreferredSize(new Dimension(600, 600));
setBackground(Color.YELLOW);
}
//gets called by `FILE OPEN` listener for each coordinate
public void makeIcons(Coordinate obj){
Icon temp = new Icon(obj);
points.add(temp);
//add the temp JComponent to this JPanel
this.add(temp);
}
}
Code for Icon which needs to be shown on the above panel:
public Icon extends JComponent{
private Coordinate location;
public Icon(Coordinate obj){
location = obj;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(location.getX(), location.getY(), 20, 20);
g.setColor(Color.BLACK);
g.drawRect(location.getX(), location.getY(), 20, 20);
}
}
First Problem: The Icons do not show up in the panel with the above code.
Second Problem: When i change the makeIcon method in MyPanel.class to below. It shows the Icons By the MenuBar erases them when the MenuBar appears on any of the icons:
public void makeIcons(Coordinate obj){
Icon temp = new Icon(obj);
points.add(temp);
//add the temp JComponent to this JPanel
this.add(temp);
temp.paintComponent(this.getGraphics());
revalidate();
}
Any help is appreciated. Thanks
Don't call paintComponent (or any paint) method yourself, ever. This is not how painting works.
The core reasons why a component won't be painted are because:
it's size is 0x0
it's invisible
it's not added to a container that is (indirectly) added to a native peer.
Based on my brief observation, I would say you're suffering from point number 1, in part due to the use of a null layout
Also, remember, when painting a component, the component's Graphics context has already been translated so that 0x0 is the top/left corner of the component. This means, based on your code, you'd most likely be painting beyond the visible bounds of the component any way.
So, you basically have two choices. Implement your own layout manager, which uses the Coordinate information to place the Icons with in the container (which would then need to override getPreferredSize in order to provide sizing hints) or, paint it yourself
Which might look something like this...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Graph Editor");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.add(new MyPanel());
frame.pack();
frame.setVisible(true);
}
});
}
public class Coordinate {
private int x;
private int y;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
public class Icon {
private Coordinate coordinate;
public Icon(Coordinate coordinate) {
this.coordinate = coordinate;
}
public Coordinate getCoordinate() {
return coordinate;
}
public void paint(Graphics2D g2d) {
g2d.setColor(Color.RED);
g2d.fillRect(0, 0, 20, 20);
g2d.setColor(Color.BLACK);
g2d.drawRect(0, 0, 20, 20);
}
}
public class MyPanel extends JPanel {
private Set<Icon> points;
public MyPanel() {
points = new HashSet<>();
setLayout(null);
setPreferredSize(new Dimension(600, 600));
setBackground(Color.YELLOW);
}
//gets called by `FILE OPEN` listener for each coordinate
public void makeIcons(Coordinate obj) {
points.add(new Icon(obj));
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Icon icon : points) {
Graphics2D g2d = (Graphics2D) g.create();
Coordinate coordinate = icon.getCoordinate();
// I'd have a size component associated with the Icon
// which I'd then use to offset the context by half its
// value, so the icon is paint around the center of the point
g2d.translate(coordinate.getX() - 10, coordinate.getY() - 10);
icon.paint(g2d);
g2d.dispose();
}
}
}
}
I've not seeded any values, I'm lazy, but that's the basic idea
I have a very simple program that ask user to click one of four panels that match its background color to that of the bigger panel(aka displaypanel), which randomly set its background color as one of the four.If the wrong panel is clicked Joptionpane comes out; displaypanels background is temporarily set to black. If clicked yes, displaypanel should re set its background color. The problem is I dont alway see the background being updated.Instead sometimes the background stays black. ...and what is more confusing is while it stays black if you drag another window over the window of this program if you see color partially being updated as moves over the display panel or just switching to a different window and refoucs then you see the complete updated background color.
so why is the setMethod called but only occasionally executed by whatever the paint method is behind the scenes? and why casting other windows or frames make it visible? does it have anything to do with the mouse click event being processed?
I appreciate any explanation for all of this,thanks guys
public class MainPanel extends JPanel{
Subpanel panel1;
Subpanel panel2;
Subpanel panel3;
Subpanel panel4;
Subpanel displaypanel;
Color[] color; //stores all the colors that display on the subpanels
public static void main(String[] args) {
JFrame window=new JFrame("This is a test");
window.setContentPane(new MainPanel());
window.setLocation(100,30);
window.setSize(600,500);
window.setVisible(true);
}
public MainPanel(){
setLayout(new FlowLayout(FlowLayout.CENTER,80,30));
panel1= new Subpanel();
panel2= new Subpanel();
panel3= new Subpanel();
panel4= new Subpanel();
//the big sub panel
displaypanel= new Subpanel();
color=new Color[4];
color[0]=Color.BLUE;
color[1]=Color.RED;
color[2]=Color.YELLOW;
color[3]=Color.GREEN;
setBackground(Color.GRAY);
displaypanel.setBackground(displayRandomColor());
panel1.setBackground(color[0]);
panel2.setBackground(color[1]);
panel3.setBackground(color[2]);
panel4.setBackground(color[3]);
displaypanel.setPreferredSize(new Dimension(400,250));
panel1.setPreferredSize(new Dimension(70,70));
panel2.setPreferredSize(new Dimension(70,70));
panel3.setPreferredSize(new Dimension(70,70));
panel4.setPreferredSize(new Dimension(70,70));
add(displaypanel);
add(panel1);
add(panel2);
add(panel3);
add(panel4);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
}
public Color displayRandomColor(){
Color i=Color.WHITE;
switch ((int)(Math.random()*4)+1){
case 1:
i= Color.YELLOW;
break;
case 2:
i= Color.BLUE;
break;
case 3:
i= Color.GREEN;
break;
case 4:
i= Color.RED;
}
return i;
}
public class Subpanel extends JPanel{
public Subpanel(){
this.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent evt){
Component source=(Component)evt.getSource();
if((source.getBackground()).equals(displaypanel.getBackground())){
//do nothing for this test..
}
else{
displaypanel.setBackground(Color.BLACK);
//ask user to reset the background color
//**the following 2 lines introduces the problem
if(JOptionPane.showOptionDialog(null,"click Yes to see a new Color","Incorrect",JOptionPane.YES_NO_OPTION,JOptionPane.PLAIN_MESSAGE,null,null,null)==JOptionPane.YES_OPTION){
displaypanel.setBackground(displayRandomColor());
}
}
}
});
} //end of constructor
public void paintComponent(Graphics g){
super.paintComponent(g);
}
}
}
Your program works reasonably well when synchronized correctly. A few notes:
Initialize objects once, as early in program execution as practical.
Use an instance of Random to get random integers; note the much simpler implementation of displayRandomColor().
private Color displayRandomColor() {
return color[r.nextInt(color.length)];
}
Swing GUI objects should be constructed and manipulated only on the event dispatch thread.
Don't use setPreferredSize() when you really mean to override getPreferredSize()], as suggested here.
Use layouts and pack() the enclosing window.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class MainPanel extends JPanel {
private static final Random r = new Random();
private final JPanel displayPanel;
private Color[] color = {Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW};
private Subpanel panel1 = new Subpanel(color[0]);
private Subpanel panel2 = new Subpanel(color[1]);
private Subpanel panel3 = new Subpanel(color[2]);
private Subpanel panel4 = new Subpanel(color[3]);
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame window = new JFrame("This is a test");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.add(new MainPanel());
window.pack();
window.setLocationRelativeTo(null);
window.setVisible(true);
}
});
}
public MainPanel() {
setLayout(new BorderLayout());
setBackground(Color.GRAY);
//the big sub panel
displayPanel = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
};
displayPanel.setBackground(displayRandomColor());
//the control panel
JPanel p = new JPanel();
p.add(panel1);
p.add(panel2);
p.add(panel3);
p.add(panel4);
add(displayPanel, BorderLayout.CENTER);
add(p, BorderLayout.SOUTH);
}
private Color displayRandomColor() {
return color[r.nextInt(color.length)];
}
public class Subpanel extends JPanel {
public Subpanel(Color color) {
this.setBackground(color);
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent evt) {
Component source = (Component) evt.getSource();
if ((source.getBackground()).equals(displayPanel.getBackground())) {
System.out.println(source.getBackground());
} else {
displayPanel.setBackground(Color.BLACK);
if (JOptionPane.showOptionDialog(null,
"Click Yes to see a new Color", "Incorrect",
JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE,
null, null, null) == JOptionPane.YES_OPTION) {
displayPanel.setBackground(displayRandomColor());
}
}
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(70, 70);
}
}
}
Ok so I have my main class which got some buttons one for a triangle and the other for an
oval and boxes.
And i got a button for ColorChooser I want to click on it and ColorChooser show up. I have
the class for the oval and triangles and ColorChooser and i set each one of them to a mode
in my main program.
So this is my main program with only the boxes and ColorChooser:
As you can see im using modes for each button and i set mode 4 for ColorChooser
If you want me to add the box class or the ColorChooser class i will if it is not making
sense. I just dont want it to be any longer.
This is my main program:
import java.awt.*;
import java.util.ArrayList;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
public class Kaleidescope extends JFrame implements MouseListener, ActionListener,
MouseMotionListener
{
Box b;
ArrayList<Box> boxes; // list of boxes
ColorChooser oo;
ColorChooser[] colors;
int colorCount;
// Buttons
JButton boxButton;
JButton ColorButton;
int x1, y1; // mousePressed
int w1, z1; // mouseEntered
int mode =1; // 1 = line, 2= boxes, 3 = oval, 4= text, 5 = SG, twoLines = 7.
public static void main( String[] args )
{
System.out.println("hi there.");
new Kaleidescope();
}
public Kaleidescope()
{
setDefaultCloseOperation( EXIT_ON_CLOSE );
addMouseListener(this);
addMouseMotionListener(this);
boxes = new ArrayList<Box>();
colors = new ColorChooser[20];
colorCount = 0;
setLayout( new FlowLayout() );
boxButton = new JButton("Boxes");
add(boxButton);
boxButton.addActionListener( this );
ColorButton = new JButton("Color Chooser");
add(ColorButton);
ColorButton.addActionListener( this);
setSize( new Dimension(500,500) );
setVisible(true);
}
// returns a random color
public Color randomColor()
{
int red = (int)(Math.random()*255);
int green = (int)(Math.random()*255);
int blue = (int)(Math.random()*255);
return new Color(red,green,blue);
}
public void mouseClicked( MouseEvent e )
{
// box
if ( mode == 2)
{
boxes.add(new Box(e.getX(), e.getY(), randomColor()));
}
repaint();
}
//action performed
public void actionPerformed( ActionEvent e )
{
if ( e.getSource()==TriangleButton ) { mode = 1;}
else if ( e.getSource()==boxButton ) { mode = 2;}
else if ( e.getSource()==ovalButton) { mode = 3;}
else if ( e.getSource()==ColorButton) { mode = 4;}
//clear all
else if (e.getSource() == clearButton)
{
boxes.clear();
triangles.clear();
ovals.clear();
}
repaint();
}
public void mouseEntered( MouseEvent e ) { }
public void mousePressed( MouseEvent e ) { }
public void mouseExited( MouseEvent e ) { }
public void mouseReleased( MouseEvent e ) {}
public void mouseMoved( MouseEvent e ) {}
public void mouseDragged( MouseEvent e ){ }
}
public void paint( Graphics g )
{
//draw/paint box triangle and oval
super.paint(g);
for (Box box : boxes)
{
box.drawMe(g);
}
}
}
here is my colorChooser class:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.colorchooser.*;
public class ColorChooser extends JPanel implements ChangeListener
{
public static final long serialVersionUID = 1L;
public JColorChooser tcc;
public JLabel banner;
public ColorChooser()
{
super(new BorderLayout());
banner = new JLabel("",JLabel.CENTER);
banner.setOpaque(true);
banner.setPreferredSize(new Dimension(100, 65));
JPanel bannerPanel = new JPanel(new BorderLayout());
bannerPanel.add(banner, BorderLayout.CENTER);
bannerPanel.setBorder(BorderFactory.createTitledBorder("Banner"));
//Set up color chooser for setting text color
tcc = new JColorChooser(banner.getForeground());
tcc.getSelectionModel().addChangeListener(this);
tcc.setBorder(BorderFactory.createTitledBorder("Choose Text Color"));
add(bannerPanel, BorderLayout.CENTER);
add(tcc, BorderLayout.PAGE_END);
}
public void stateChanged(ChangeEvent e)
{
Color newColor = tcc.getColor();
banner.setForeground(newColor);
}
private static void createAndShowGUI()
{
//Create and set up the window.
JFrame frame = new JFrame("ColorChooserDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
JComponent newContentPane = new ColorChooser();
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args)
{
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
Start by taking a look at How to Write an Action Listener and How to Use Color Choosers
Basically, attach a ActionListener to the JButton you want to activate the JColorChooser and when the actionPerformed method is called, use inbuilt functionality to show the default chooser window, for example (from the linked tutorial)...
Color newColor = JColorChooser.showDialog(
ColorChooserDemo2.this,
"Choose Background Color",
banner.getBackground());
Updated
Start by adding a Color instance variable to Kaleidescope, this will allow you to maintain a reference to the last chossen color
private Color currentPaintColor = Color.BLACK;
Next, when the ColorButton is pressed, you will want to create some kind of dialog to show the chooser in, this will allow you to wait until the user chooses a color and get the resulting color...
} else if (e.getSource() == ColorButton) {
ColorChooser chooser = new ColorChooser();
int result = JOptionPane.showConfirmDialog(this, chooser, "Color Chooser", JOptionPane.OK_CANCEL_OPTION);
if (result == JOptionPane.OK_OPTION) {
currentPaintColor = chooser.getChoosenColor();
}
} //clear all
You'll also want to change the stateChanged method in ColorChooser to make it more meaningful...
public void stateChanged(ChangeEvent e) {
Color newColor = tcc.getColor();
banner.setBackground(newColor);
}
Now, the question is, what do you want to do with this new color? Do you want to apply it to all the current shapes you are painting? If so you need to set the color before painting the shapes...
public void paint(Graphics g) {
//draw/paint box triangle and oval
super.paint(g);
g.setColor(currentPaintColor);
for (Box box : boxes)
{
box.drawMe(g);
}
}
Or do you only want to apply the color to new objects added after the change?
You should avoid overriding paint of top level containers, lots of reason, they aren't double buffered, which will cause flickering when they are updated and you will be painting over the top of everything else on the frame and you can potentially paint under the frame borders...
Instead you should use something JPanel and override it's paintComponent method, take a look at Performing Custom Painting for more details
You need to clarify just what you expect a mode = 4 will do with your program. I can understand using JButton presses to set shape modes (object state) that will alter the behavior of your MouseListener, but I don't see how a color chooser will fit into this model, and in fact believe that it likely won't. I don't have the rest of your code, nor do I have the specifics of your assignment, but I'm going to make some recommendations based on guesses, and thus these will necessarily be weak recommendations.
I'm guessing that you want to have a JColorChooser dialog displayed when the color button is pressed.
And that the user then can select a Color that will be the color of the drawn shapes.
If so, then likely you shouldn't have the color chooser button (which should be named colorChooserButton) set a numeric node. Rather, it should open your color choosing dialog, and after the user has selected a color, then you should set a Color field in your drawing class, not the mode value.
Rather the modes should only be used to select an appropriate shape that the MouseListener will use to determine what shape to draw.
Myself, I wouldn't use numeric modes but rather an enum to define this state, but that is probably something you'll learn later in your programming education.
If my assumptions are incorrect, then please clarify them.
As an aside, note that you should not draw in a paint(Graphics g) method, and should not draw directly in the JFrame. Rather you should draw in the paintComponent(Graphics g) method override of a JPanel or JComponent.
Here's a runnable example of how JColorChooser can be used to set the color for different tasks. Feel free to ask questions if you are unclear about anything.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ColorChooserPaintExample {
private Color color = Color.BLUE;
private ColorPanel colorPanel = new ColorPanel();
public ColorChooserPaintExample() {
final JFrame frame = new JFrame("My Color Chooser Demo");
JButton chooseColor = new JButton("Change Color of Panel");
chooseColor.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
color = JColorChooser.showDialog(frame, "Choose a Color for Panel", color);
colorPanel.repaint();
}
});
frame.add(colorPanel);
frame.add(chooseColor, BorderLayout.SOUTH);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private class ColorPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(color);
g.fillRect(0, 0, getWidth(), getHeight());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new ColorChooserPaintExample();
}
});
}
}
I'm trying to do a simple piece of homework, where I display a line of text displaying whether a door object is open or not. Underneath that, I visually represent it (using the drawRect) method. And at the bottom I have two buttons, which can open or close the door, thus changing the text and rectangle.
Edit: List of code that can be compiled given now:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class Test {
public static void main(String[] args) {
// Creates new JFrame called frame, with title "Door"
// (displayed at top of screen).
JFrame frame = new JFrame ("Door");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TempDoorPanel panel = new TempDoorPanel();
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
}
class Door {
private String state;
private String message;
Door (String state) {
this.state = state;
message = "The door is currently closed.";
}
public boolean isOpen() {
return state.equals ("open");
}
public boolean isClosed() {
return state.equals ("closed");
}
public void setState(String state) {
this.state = state;
}
public String getMessage() {
return message;
}
public void open() {
if (state.equals("open")) {
message = "The door is already open.";
}
else {
state = "open";
message = "The door has been opened.";
}
}
public void drawOpenDoor (Graphics page) {
page.drawRect(100, 100, 100, 100);
}
}
class TempDoorPanel extends JPanel {
private Door door;
private JTextField currentStateOfDoor;
private JButton openDoor;
public TempDoorPanel() {
super.setLayout(new BorderLayout());
door = new Door("closed");
super.setBackground(Color.blue);
super.setPreferredSize(new Dimension (360, 400));
currentStateOfDoor = new JTextField(14);
currentStateOfDoor.setText(door.getMessage());
super.add(currentStateOfDoor, BorderLayout.NORTH);
openDoor = new JButton("Open Door");
class openDoorListener implements ActionListener {
public void actionPerformed (ActionEvent event) {
door.open();
repaintText();
}
}
openDoorListener openlistener = new openDoorListener();
openDoor.addActionListener(openlistener);
JPanel holder = new JPanel();
holder.add(openDoor);
super.add(holder, BorderLayout.SOUTH);
}
private void repaintText() {
currentStateOfDoor.setText(door.getMessage());
// These methods are from Door class.
}
public void paintComponent (Graphics page) {
super.paintComponent(page);
if (door.isOpen())
door.drawOpenDoor(page);
// isOpen is a boolean method from Door class.
}
}
What works:
Buttons appear at right place on screen, at BorderLayout.SOUTH, one after the other.
The JTextField appears at right place, at BorderLayout.NORTH
Finally, the blue area appears in the right place in the centre of the screen.
What I'm trying to fix:
I have no idea how to display the rectangle properly in the middle of that blue area. I've tried changing the coordinates and size of the rectangle, which doesn't change the size of it at all. I can make it drawRect(100, 100, 100, 100) and it changes nothing.
I'm also aware that the rectangle is currently hidden behind the top left corner of the JTextField, but I can't figure out how to move it into the BorderLayout.
Questions:
How do you place a rectangle in a BorderLayout?
How do you adjust the size of a rectangle, drawn via drawrect(), in such a layout?
Because you add components to the JPanel you draw on the JTextField is covering your drawing.
Solution:
1) Either compensate for this by checking the JTextField height in your drawRect(..) method
or better
2) Dont add components to the same JPanel which you are drawing on unless it cant be helped.
So basically I made your TempDoorPanel add a new JPanel to BorderLayout.CENTER which is the drawing panel we can now use drawRect(0,0,10,10) and it will show in the top left hand corner of JPanel drawingPanel.
Also dont call setPreferredSize on JPanel rather override getPreferredSize() and return Dimensions which fit your drawings.
To invoke paintComponent outside of the class simply call repaint() its instance
See this example which uses point no.2:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Door");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
TempDoorPanel panel = new TempDoorPanel();
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
});
}
}
class Door {
private String state;
private String message;
public Door(String state) {
this.state = state;
message = "The door is currently closed.";
}
public void drawOpenDoor(Graphics page) {
page.setColor(Color.GREEN);
page.drawRect(0, 0, 10, 10);
}
}
class TempDoorPanel extends JPanel {
private Door door;
private JTextField currentStateOfDoor;
private JButton openDoor;
public TempDoorPanel() {
super.setLayout(new BorderLayout());
door = new Door("closed");
currentStateOfDoor = new JTextField(14);
//AcurrentStateOfDoor.setText(door.getMessage());
super.add(currentStateOfDoor, BorderLayout.NORTH);
openDoor = new JButton("Open Door");
final JPanel drawingPanel = new JPanel() {
#Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
// if (door.isOpen()) {
door.drawOpenDoor(grphcs);
// }
// isOpen is a boolean method from Door class.
}
};
drawingPanel.setBackground(Color.blue);
add(drawingPanel);
class openDoorListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
//door.open();
repaintText();
drawingPanel.repaint();//so paint component of drawing panel is called
}
}
openDoorListener openlistener = new openDoorListener();
openDoor.addActionListener(openlistener);
JPanel holder = new JPanel();
holder.add(openDoor);
super.add(holder, BorderLayout.SOUTH);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
private void repaintText() {
// currentStateOfDoor.setText(door.getMessage());
// These methods are from Door class.
}
}
When you handler the door opening event with your listener;
class openDoorListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
door.open();
repaintText();
}
}
you don't actually include a call to repaint the panel; hence the panel's paintComponent() method isn't called and door.drawOpenDoor() isn't called. You can test this by clicking the button and then resizing the frame. When you resize, the panel is automatically repainted and bingo, your door appears.
You can fix this by adding a call to repaint() in your ActionListener;
class openDoorListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
door.open();
repaintText();
repaint(); // requests that the panel be repainted
}
}