Hello I am having trouble with my code and I have been trying to figure out what is wrong for a few days and looked at somewhat relevant programs for help and can not figure it out. The program is supposed to change the the image of a traffic light based on what button you press: red, yellow, or green. There are 3 classes. I am running the program in eclipse.
CLass 1 trafficLight that contains the main method:
import javax.swing.*;
import java.awt.*;
public class trafficLight
{
//-----------------------------------------------------------------
// Creates and displays the main program frame.
//-----------------------------------------------------------------
public static void main(String[] args)
{
JFrame frame = new JFrame("CHANGE TRAFFIC LIGHT");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
trafficLightPanel lights = new trafficLightPanel();
trafficLightControls controls = new trafficLightControls(lights);
JPanel panel = new JPanel();
panel.setBackground(Color.blue);
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.add(Box.createRigidArea (new Dimension (0, 20)));
panel.add(lights);
panel.add(Box.createRigidArea (new Dimension (0, 10)));
panel.add(controls);
panel.add(Box.createRigidArea (new Dimension (0, 10)));
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
The second class trafficLightPanel that contain the imageicons part:
import java.awt.*;
import javax.swing.*;
public class trafficLightPanel extends JPanel
{
public int count, redCount, yellowCount, greenCount;
private ImageIcon none, red, yellow, green;
private JLabel imageLabel;
//-----------------------------------------------------------------
// Constructor: Sets up the images and the initial state.
//-----------------------------------------------------------------
public trafficLightPanel()
{
none = new ImageIcon("nonePic.png");
red = new ImageIcon("redPic.png");
yellow = new ImageIcon("yellowPic.png");
green = new ImageIcon("greenPic.png");
setBackground(Color.black);
redCount = 1; yellowCount = 2; greenCount = 3;
imageLabel = new JLabel(none);
add(imageLabel);
}
//-----------------------------------------------------------------
// Paints the panel using the appropriate image.
//-----------------------------------------------------------------
public void paintComponent(Graphics page)
{
super.paintComponent(page);
if (count == redCount)
{
imageLabel.setIcon(red);
}
if (count == yellowCount)
{
imageLabel.setIcon(yellow);
}
if (count == greenCount)
{
imageLabel.setIcon(green);
}
}
//-----------------------------------------------------------------
// Sets the status of the traffic light.
//-----------------------------------------------------------------
public void setCount(int newCount)
{
count = newCount;
}
}
The third class trafficLightControls containing the jbuttons:
//********************************************************************
// Represents the control panel for the traffic light program.
//********************************************************************
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class trafficLightControls extends JPanel
{
private trafficLightPanel lights;
private JButton red, yellow, green;
//-----------------------------------------------------------------
// Sets up the traffic light control panel.
//-----------------------------------------------------------------
public trafficLightControls(trafficLightPanel lightPanel)
{
lights = lightPanel;
red = new JButton("RED");
red.addActionListener(new redListener());
yellow = new JButton("YELLOW");
yellow.addActionListener(new yellowListener());
green = new JButton("GREEN");
green.addActionListener(new greenListener());
setBackground(Color.black);
add(red);
add(yellow);
add(green);
}
//*****************************************************************
// Represents the listener for the red button.
//*****************************************************************
private class redListener implements ActionListener
{
//--------------------------------------------------------------
// sets count to redCount and repaints the lights panel.
//--------------------------------------------------------------
public void actionPerformed(ActionEvent event)
{
lights.setCount(lights.redCount);
lights.repaint();
}
}
//*****************************************************************
//Represents the listener for the yellow button.
//*****************************************************************
private class yellowListener implements ActionListener
{
//--------------------------------------------------------------
//sets count to yellowCount and repaints the lights panel.
//--------------------------------------------------------------
public void actionPerformed(ActionEvent event)
{
lights.setCount(lights.yellowCount);
lights.repaint();
}
}
//*****************************************************************
//Represents the listener for the green button.
//*****************************************************************
private class greenListener implements ActionListener
{
//--------------------------------------------------------------
//sets count to green count and repaints the lights panel.
//--------------------------------------------------------------
public void actionPerformed(ActionEvent event)
{
lights.setCount(lights.greenCount);
lights.repaint();
}
}
}
Each time I click a button it is supposed to set the count in the trafficLightPanel object, lights, to the count that corresponds to the color, then based on the count the image is supposed to be replaced by the corresponding image. The components are all put together with a box layout.
For some reason only red will work... It starts out displaying the nonePic, the one without any light, and when I click red it displays redPic. If I click on any before or after clicking RED button, the others do not display. If I click one of the others first then RED button, red can still display for some reason. All images are in the root folder(is this the correct name?), the one containing the src and bin folders.
I thought maybe something was wrong with the count, and I tried doing something like adding a jLabel that would display the count each time into the program with the box layout but it does not display anything(this attempt is not in the code). I also tried putting the jLabel into the trafficLightControls class and adding it along with the add(red) add(yellow).... but it would not display anything. Another thing I tried was to change the text of the buttons each time to displaying the color with the count as an alternative to the jLabel attempt. I tried using .setText("") method like red.setText("") in the listener class for red. I would appreciate it if anyone could explain how to add a jLabel and change the text of the button as I have described in this particular little paragraph, as it is something I would like to know how to do to for future reference, though it is not necessary to solving my problem so its ok to not help out with this little paragraph.
Thank you very much for any help anyone offers!
edit: (I am sorry I left in remnants of my attempts at making jLabels to test the code but I removed them, though they did not affect the code I believe, I attempted to use them because of my problem. I am very sorry if this confused anyone)
There's no need to call repaint() and you shouldn't override paintComponent if all you're doing is swapping ImageIcons. Simply call setIcon(...) on your JLabel is all that is needed. The model will trigger a repainting of the view itself.
Getting rid of your paintComponent override and changing setCount to something as simple as this could work:
public void setCount(int newCount) {
count = newCount;
Icon icon = null;
switch (count) {
case 1:
icon = red;
break;
case 2:
icon = yellow;
break;
case 3:
icon = green;
break;
default:
icon = null;
break;
}
imageLabel.setIcon(icon);
}
For example, my MCVE, one that uses an enum and a Map to simplify the code a bit.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;
#SuppressWarnings("serial")
public class Traff2 extends JPanel {
public Traff2() {
Traff2LightPanel lightPanel = new Traff2LightPanel();
Traff2LightControlsPanel controlsPanel = new Traff2LightControlsPanel(lightPanel);
setLayout(new BorderLayout());
add(lightPanel, BorderLayout.CENTER);
add(controlsPanel, BorderLayout.PAGE_END);
}
private static void createAndShowGui() {
Traff2 mainPanel = new Traff2();
JFrame frame = new JFrame("Traffic");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
enum Light {
NONE(""), RED("Red"), YELLOW("Yellow"), GREEN("Green");
private String text;
private Light(String text) {
this.text = text;
}
public String getText() {
return text;
}
}
#SuppressWarnings("serial")
class Traff2LightPanel extends JPanel {
private Map<Light, Icon> lightColorMap = new EnumMap<>(Light.class);
private JLabel imageLabel = new JLabel();
private Light light = Light.NONE;
public Traff2LightPanel() {
// fill the map
lightColorMap.put(Light.NONE, new ImageIcon("nonePic.png"));
lightColorMap.put(Light.RED, new ImageIcon("redPic.png"));
lightColorMap.put(Light.YELLOW, new ImageIcon("yellowPic.png"));
lightColorMap.put(Light.GREEN, new ImageIcon("greenPic.png"));
imageLabel.setIcon(lightColorMap.get(Light.NONE));
add(imageLabel);
}
// when changing the light field,
// also set the ImageIcon
public void setLight(Light light) {
this.light = light;
imageLabel.setIcon(lightColorMap.get(light));
}
public Light getLight() {
return light;
}
}
#SuppressWarnings("serial")
class Traff2LightControlsPanel extends JPanel {
private Traff2LightPanel lightPanel;
public Traff2LightControlsPanel(Traff2LightPanel lightPanel) {
this.lightPanel = lightPanel;
for (Light light : Light.values()) {
if (light == Light.NONE) {
continue;
}
add(new JButton(new LightAction(light)));
}
}
// use an AbstractAction...
// like an ActionListener on "steroids"
private class LightAction extends AbstractAction {
private Light light;
public LightAction(Light light) {
super(light.getText());
this.light = light;
}
#Override
public void actionPerformed(ActionEvent e) {
lightPanel.setLight(light);
}
}
}
Related
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());
}
}
}
I have written this code however I am having trouble with one aspect I wish to code into it. I want to make the green square change size when I press one of the three buttons I have so when I press the button 'small' the square changes size to small e.g. 100 and when I press the button 'medium' it changes size to medium e.g. 400. This is my code so far:
package Lab2;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Main {
public static void main(String[] args) {
FilledFrame frame = new FilledFrame();
frame.setVisible( true );
}
}
class FilledFrame extends JFrame {
int size = 400;
public FilledFrame()
{
JButton butSmall = new JButton("Small");
JButton butMedium = new JButton("Medium");
JButton butLarge = new JButton("Large");
JButton butMessage = new JButton("Say Hi");
SquarePanel panel = new SquarePanel(this);
JPanel butPanel = new JPanel();
butPanel.add(butSmall);
butPanel.add(butMedium);
butPanel.add(butLarge);
butPanel.add(butMessage);
add(butPanel, BorderLayout.NORTH);
add(panel, BorderLayout.CENTER);
setSize( size+100, size+100 ); } }
class SquarePanel extends JPanel {
FilledFrame theApp;
SquarePanel(FilledFrame app)
{
theApp = app;
}
public void paintComponent ( Graphics g)
{
super.paintComponent(g);
g.setColor(Color.green);
g.fillRect(20, 20, theApp.size, theApp.size);
}
}
class buttonHandler implements ActionListener {
FilledFrame theApp;
int size;
public buttonHandler(FilledFrame app, int size) {
theApp = app;
this.size = size;
}
#Override
public void actionPerformed (ActionEvent e){
theApp.setSize(this.size, this.size);
}
}
As I don't see any event listeners for your buttons, I assume this is all the code you have. Your buttons will not do anything unless you tell them to do it. You need to add event listeners, and through that change the size and update the panel.
Example:
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
theApp.size = 200;
frame.getContentPane().repaint();
//OR frame.repaint();
}
});
EDIT:
The problem with using the button handler class is you would need to find which buttton was pressed, instead its easier to use the way I showed above. I edited the code above, try copy pasting to one of the buttons.
Current code
ThreeColorButton class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ThreeColorButton {
private static CompositeIcon icons = new CompositeIcon();
private static JPanel panel = new JPanel();
private static JFrame frame = new JFrame();
private static JLabel label = new JLabel();
public static void main(String[] args) {
//create rgb buttons
JButton redButton = new JButton("Red");
JButton greenButton = new JButton("Green");
JButton blueButton = new JButton("Blue");
//add rgb buttons to panel
panel.add(redButton);
panel.add(greenButton);
panel.add(blueButton);
//add action listeners to buttons
redButton.addActionListener(buttonListener(40, Color.red));
greenButton.addActionListener(buttonListener(40, Color.green));
blueButton.addActionListener(buttonListener(40, Color.blue));
frame.setLayout(new BorderLayout());
frame.add(panel, BorderLayout.NORTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private static ActionListener buttonListener(final int size,final Color color) {
return new ActionListener() {
public void actionPerformed(ActionEvent event) {
SquareIcon icon = new SquareIcon(size, color);
icons.addIcon(icon);
label.setIcon(icons);
frame.add(label, BorderLayout.SOUTH);
frame.repaint();
frame.pack();
}
};
}
}
CompositeIcon code
import javax.swing.*;
import java.awt.*;
import java.util.*;
public class CompositeIcon implements Icon{
private ArrayList<Icon> icons;
private int size;
public CompositeIcon() {
icons = new ArrayList<Icon>();
}
public void paintIcon(Component c, Graphics g, int x, int y) {
int position = x;
for(Icon z : icons) {
z.paintIcon(c,g,position,y);
position = position + z.getIconWidth();
}
}
public int getIconHeight() {
return size;
}
public int getIconWidth() {
int total = 0;
for(Icon z : icons) {
total = total + z.getIconWidth();
}
return total;
}
public void addIcon(Icon z) {
icons.add(z);
}
}
SquareIcon class is only a simple little class that creates a square of a single color with a given size.
My question is, in my ThreeColorButton class, when I run it, it doesn't show any icons when I press either of the RGB buttons. However, in the buttonListener method, if I set label.setIcons(icons) to label.setIcons(icon), it shows a single square and it doesnt place it side by side.
I can't seem to figure out whats causing this behavior. Is there a problem with displaying an array of icons using JLabel?
There is nothing to paint in the label since the height of your Icon is 0, since you never set the size.
I would suggest code something like:
#Override
public int getIconHeight()
{
int size = 0;
for(Icon z : icons)
{
size = Math.max(size, z.getIconHeight());
}
return size;
}
You may want to check out Compound Icon. Similar to your class but it has more features. It supports horizontal/vertical/stacked icon and icon alignment options.
It doesn't support dynamically adding Icons so you would need to change that. I might looking adding that feature myself (when I get time) :)
I can't seem to figure out whats causing this behavior. Is there a problem with displaying an array of icons using JLabel?
Yes, as #mKorbel mentioned, there is a problem. A JLabel can only display a single icon. If you want to display n icons, you will need n JLabel instances.
I need to make a java applet that allows the user to paint with the mouse. When the applet is launched, a second window opens that allows the user to select one of 6 different colors to paint with.
First, I wrote code to construct a toolbar window which contains a getcurrentcolor method. I can't seem to link the button press with the color change.
If I launch the applet, the toolbarwindow opens successfully and I'm able to paint in black, so my only problem is selecting a color on the toolbar window and painting in that color.
toolbar code:https://gist.github.com/anonymous/3c053c69112f46d17440
painting applet code: https://gist.github.com/anonymous/aca7929dbcfc08008f30
I gave an approach here for 3 buttons, you can add the rest. The idea is that you keep a currently selected color field and update it each time a button is selected via the ActionListener. A map from the button to the color it represents is not necessary, but makes the code more manageable.
public class ToolBarWindow extends JFrame {
private static Map<JRadioButton, Color> colors = new HashMap<>();
private static Color currentColor = Color.BLACK;
public static void main(String[] args) {
ToolBarWindow frame = new ToolBarWindow();
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Colors");
frame.setVisible(true);
}
public ToolBarWindow() {
JPanel jpRadioButtons = new JPanel();
jpRadioButtons.setLayout(new GridLayout(3, 1));
// put the other colors
JRadioButton red = new JRadioButton("red");
JRadioButton black = new JRadioButton("black");
JRadioButton magenta = new JRadioButton("magenta");
red.addActionListener(new MyActionListener());
black.addActionListener(new MyActionListener());
magenta.addActionListener(new MyActionListener());
jpRadioButtons.add(red);
jpRadioButtons.add(black);
jpRadioButtons.add(magenta);
colors.put(red, Color.RED);
colors.put(black, Color.BLACK);
colors.put(magenta, Color.MAGENTA);
add(jpRadioButtons, BorderLayout.WEST);
ButtonGroup bg = new ButtonGroup();
bg.add(red);
bg.add(black);
bg.add(magenta);
}
Color getCurrentColor() {
return currentColor;
}
private class MyActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
currentColor = colors.get(e.getSource());
}
}
}
I get the feeling your professor wants you to make your own. Here is an example I threw together in 10 minutes or so. its very rough and lacking good coding style but if you need to know what is involved, it should be useful. The example code prints out the color whenever you have selected it.
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
public class MyColorChooser extends Component
{
private Color[] colors;
private Color selectedColor;
public MyColorChooser(Color ... colors)
{
this.colors = colors;
this.selectedColor = colors[0];
this.addMouseListener
(
new MouseAdapter()
{
#Override public void mouseClicked(MouseEvent e)
{
int tileWidth = MyColorChooser.this.getWidth();
tileWidth /= MyColorChooser.this.colors.length;
int index = e.getX()/(tileWidth);
MyColorChooser.this.selectedColor = MyColorChooser.this.colors[index];
}
}
);
}
#Override public void paint(Graphics renderer)
{
int width = this.getWidth()/this.colors.length;
int height = this.getHeight();
for(int i = 0; i < this.colors.length; i++)
{
renderer.setColor(this.colors[i]);
renderer.fillRect(width*i,0,width,height);
}
}
public Color getSelectedColor()
{
return this.selectedColor;
}
public static void main(String ... args) throws Throwable
{
JFrame f = new JFrame();
f.setSize(200,100);
f.getContentPane().setLayout(null);
MyColorChooser chooser = new MyColorChooser
(
Color.RED,
Color.GREEN,
Color.BLUE,
Color.YELLOW,
Color.WHITE,
Color.BLACK
);
f.getContentPane().add(chooser);
chooser.setBounds(0,0,200,50);
f.setVisible(true);
Color lastColor = chooser.getSelectedColor();
for(;;)
{
if(!chooser.getSelectedColor().equals(lastColor))
{
lastColor = chooser.getSelectedColor();
System.out.printf("Selected Color:%s\n",lastColor.toString());
}
Thread.sleep(100);
}
}
}
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
}
}