I'm wondering why my applet isn't running. I'm using netbeans, and the program works fine with no errors, but I can't seem to get the applet screen to appear to test all the functions of my program.I was wondering if someone can point out what I am doing wrong in starting my applet up. I haven't done to many things with applets, so I'm quite curious why it isn't upping and running for me. I really didn't want to post the full code of my program, but I've no idea if there's an error in my code, or I'm just not doing the right thing to actually start the applet or something.
I do not get any errors while running my program, that applet simply does not appear and run in itself. Otherwise I get no errors from neatbeans while running my program.
import java.awt.event.*;
import javax.swing.*;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.FlowLayout;
public class Program7 extends JApplet implements ActionListener, ItemListener
{
//static varaibles
private static int GuiHeight = 90;
private static int Square = 50;
//gui varaibles
private JRadioButton drawSquare;
private JRadioButton mess;
private JTextField messageFeild;
private JCheckBox color;
private JButton button;
private JComboBox location;
//modable global varaibles
private int width, height, drawX, drawY;
private Color drawColor;
private String draw;
#Override
public void init()
{
//creating the panels
JPanel drawChoice;
JPanel drawSet;
//setting group onject to link certain buttons together
ButtonGroup ObjGroup;
//setting layout to make things look nice
setLayout(new FlowLayout());
//ibtializing other varaibles
width = 0;
height = 0;
drawX = 0;
drawY= 0;
drawColor = Color.BLACK;
draw = "";
//intialzing the gui interface
drawSquare = new JRadioButton("Draw a Square!");
mess = new JRadioButton("Write a Message!");
location = new JComboBox(new String[]{"", "Random Pick", "Top Left"});
color = new JCheckBox("Draw in Color!");
button = new JButton("Draw it!");
//linking the buttons together
ObjGroup = new ButtonGroup();
ObjGroup.add(drawSquare);
ObjGroup.add(mess);
//adding event handlers to the buttons
location.addItem(this);
button.addActionListener(this);
color.addItemListener(this);
drawSquare.addActionListener(this);
mess.addActionListener(this);
messageFeild = new JTextField(20);
//adding to the first paels
drawChoice = new JPanel();
drawChoice.add(drawSquare);
drawChoice.add(mess);
drawChoice.add(messageFeild);
//adding to the applet
add(drawChoice);
//adding to the second panel
drawSet = new JPanel();
drawSet.add(new JLabel("Select where to draw!"));
drawSet.add(location);
drawSet.add(color);
drawSet.add(button);
//adding to the applet
add(drawSet);
}
#Override
public void paint(Graphics g)
{
//calling super constructor
super.paint(g);
//getting width
width = getWidth();
height = getHeight();
//setting graphics color
g.setColor(drawColor);
if (location.getSelectedItem() != "")
{
//ifstatement checking for inputs
if(draw == "Square"||draw == "square"||draw == "SQUARE")
{
//creating rectange
g.fillRect(drawX, drawY, width, height);
}
if(draw == "Message"|| draw == "MESSAGE"||draw == "message")
{
//writing message
g.drawString(messageFeild.getText(), drawX, drawY);
}
}
}
#Override
public void actionPerformed(ActionEvent e)
{
//repainting
repaint();
}
#Override
public void itemStateChanged(ItemEvent e)
{
//if statement checking for the various changes being made by the user in the pograms interface
//if statement check checking to see if there's a square or to write a message
if (e.getSource() == drawSquare && e.getStateChange() == ItemEvent.SELECTED)
{
draw = "Square";
messageFeild.setEnabled(false);
}
if (e.getSource() == mess && e.getStateChange() == ItemEvent.SELECTED)
{
draw = "Message";
messageFeild.setEnabled(true);
}
//if statement set checking for locational input
if (e.getSource() == location)
{
if(location.getSelectedItem() == "Random Pick")
{
drawX=(int)(Math.random()*(width+1));
drawY=(int)(GuiHeight+ Math.random()*(height-GuiHeight+1));
}
if(location.getSelectedItem() == "Top Left")
{
drawX=0;
drawY=GuiHeight;
}
}
//if statement to check for color change
if(e.getSource()==color && e.getStateChange()==ItemEvent.SELECTED)
{
drawColor = Color.GREEN;
}
if(e.getSource()==color && e.getStateChange()==ItemEvent.DESELECTED)
{
drawColor = Color.BLACK;
}
}
public static void main(String[] args) {
}
}
Related
I am trying to make a JComponent application which uses two JFrames, one frame with alterable sliders and textfields for the graphical display of a firework on the second. When the "fire" button is pressed, a rendering of the firework should appear. However, I have found through placing strategic print statements, that my paintComponent() method does not run even though the conditional statement wrapping the code is satisfied. I have also double checked all of my other methods to ensure that correct values are generated at the correct times. After looking through all of the JComponent literature and questions I could find, I'm afraid I cannot get it to work - this problem is most likely derived from my lack of familiarity with the library. That being said, any advice no matter how rudimentary, will be much appreciated. Abridged code is below:
*The swing timer may also be the issue for I am not sure if I have used it correctly
[fireworksCanvas.java]
public class fireworkCanvas extends JComponent implements ActionListener{
private static final long serialVersionUID = 1L;
private ArrayList<Ellipse2D> nodes = new ArrayList<Ellipse2D>();
private ArrayList<Line2D> cNodes = new ArrayList<Line2D>();
private ArrayList<QuadCurve2D> bCurves = new ArrayList<QuadCurve2D>();
private int[] arcX;
private int[] arcY;
private Color userColor;
private Random rand = new Random();
private int shellX, shellY, fType, theta, velocity;
private Timer timer;
private int time;
private double g = -9.8; //gravity in m/s
public boolean explosivesSet;
public fireworkCanvas() {
time = rand.nextInt(3000) + 2000;
timer = new Timer(time, this); // 5 seconds
timer.start();
fType = 0;
}
#Override
public void paintComponent(Graphics g){
if (explosivesSet) {
System.out.println("fType" + fType);
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
g.setColor(Color.BLACK);
g.drawPolyline(arcX, arcY, arcX.length);
for (Ellipse2D e : nodes) {
System.out.println("painting nodes"); // NEVER PRINTS
g.setColor(userColor);
g.fillOval(shellX + (int) e.getX(), shellY + (int) e.getY(), (int) e.getWidth(), (int) e.getHeight());
}
for (Line2D l: cNodes) {
System.out.println("painting cNodes"); // NEVER PRINTS
g.setColor(determineColor("l"));
g.drawLine(shellX + (int) l.getX1(), shellY + (int) l.getY1(), shellX + (int) l.getX2(), shellY + (int) l.getY2());
}
for (QuadCurve2D c: bCurves) {
System.out.println("painting curves"); // NEVER PRINTS
g.setColor(determineColor("c"));
g2D.draw(c);
}
}
}
public Color determineColor(String type) {
// returns color
}
public void setExplosives() {
if (fType != 5 && fType != 0) {
nodes.clear(); // clears three array lists with FW components
cNodes.clear(); // these are the components to paint for the
bCurves.clear(); // firework explosion graphic
setArc(); // stores path of shell for a polyLine to be drawn
// builds and generates components for FW based on type chosen (fType)
setExplosivesSet(true);
repaint();
}
}
public void setArc() {
// builds int[] for shellX, shellY
}
#Override
public void actionPerformed(ActionEvent e) {
// nothing is here??
// should I use the action performed in some way?
}
[GUI.java]
public class GUI extends JFrame implements ActionListener, ChangeListener, ItemListener, MouseListener{
private static JFrame canvasFrame = new JFrame("Canvas");
private fireworkCanvas canvas = new fireworkCanvas();
private Choice fireworkChooser = new Choice();
private JSlider launchAngle = new JSlider();
private JSlider velocity = new JSlider();
private JSlider r = new JSlider();
private JSlider g = new JSlider();
private JSlider b = new JSlider();
private JPanel panel = new JPanel();
private JButton button = new JButton("Fire!");
private JLabel launchLabel = new JLabel("Launch Angle ");
private JLabel velocityLabel = new JLabel("Velocity ");
private JLabel rLabel = new JLabel("Red ");
private JLabel gLabel = new JLabel("Green ");
private JLabel bLabel = new JLabel("Blue ");
public static int fHeight = 500;
public static int fWidth = 500;
public GUI() {
this.add(panel);
panel.add(button);
panel.add(fireworkChooser);
panel.add(launchAngle);
panel.add(launchLabel);
panel.add(velocity);
panel.add(velocityLabel);
panel.add(r);
panel.add(rLabel);
panel.add(g);
panel.add(gLabel);
panel.add(b);
panel.add(bLabel);
addActionListener(this);
BoxLayout bl = new BoxLayout(getContentPane(), BoxLayout.Y_AXIS);
setLayout(bl);
fireworkChooser.addItemListener(this);
launchAngle.addChangeListener(this);
velocity.addChangeListener(this);
r.addChangeListener(this);
g.addChangeListener(this);
b.addChangeListener(this);
button.addActionListener(this);
fireworkChooser.add("Firework 1");
fireworkChooser.add("Firework 2");
fireworkChooser.add("Firework 3");
fireworkChooser.add("Firework 4");
fireworkChooser.add("Super Firework");
launchAngle.setMinimum(1);
launchAngle.setMaximum(90);
velocity.setMinimum(1);
velocity.setMaximum(50);
r.setMinimum(0);
r.setMaximum(255);
g.setMinimum(0);
g.setMaximum(255);
b.setMinimum(0);
b.setMaximum(255);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 200);
}
#Override
public void stateChanged(ChangeEvent e) {
// sets FW variables
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == button) {
canvas.setfType(fireworkChooser.getSelectedIndex()+1);
canvas.setExplosives();
canvas.repaint();
canvas.setExplosivesSet(false);
System.out.println("button fired");
}
}
public static void createAndShowGUI() {
GUI gui = new GUI();
gui.pack();
gui.setLocationRelativeTo(null);
gui.setVisible(true);
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
fireworkCanvas canvas = new fireworkCanvas();
canvasFrame.pack();
canvasFrame.add(canvas);
canvasFrame.setLocationRelativeTo(null);
canvasFrame.setVisible(true);
canvasFrame.setSize(fWidth, fHeight);
canvasFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
First of all:
public fireworkCanvas()
Class names should start with an upper case character. All the other classes in your code follow this rule. Learn by example.
private Choice fireworkChooser = new Choice();
Choice is an AWT component don't mix AWT components in a Swing application. Use a JComboBox.
that my paintComponent() method does not run
fireworkCanvas canvas = new fireworkCanvas();
canvasFrame.pack();
canvasFrame.add(canvas);
You add the canvas to the frame AFTER you pack() the frame, so the size of the canvas is (0, 0) and there is nothing to paint.
The canvas should be added to the frame BEFORE the pack() and you should implement getPreferredSize() in your FireworkCanvas class so the pack() method can work properly.
Read the section from the Swing tutorial on Custom Painting for the basics and working examples to get you started.
I am completing a past paper exam question and it asks to create an applet that displays a green square in the center, with three buttons + , - and reset, however, I am trying to make it that when any button is clicked the program should essentially figure out which button was pressed. I know you would use e.getSource() but I am not sure how to go about this.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Square extends JApplet {
int size = 100;
public void init() {
JButton increase = new JButton("+");
JButton reduce = new JButton("-");
JButton reset = new JButton("reset");
SquarePanel panel = new SquarePanel(this);
JPanel butPanel = new JPanel();
butPanel.add(increase);
butPanel.add(reduce);
butPanel.add(reset);
add(butPanel, BorderLayout.NORTH);
add(panel, BorderLayout.CENTER);
ButtonHandler bh1 = new ButtonHandler(this, 0);
ButtonHandler bh2 = new ButtonHandler(this, 1);
ButtonHandler bh3 = new ButtonHandler(this, 2);
increase.addActionListener(bh1);
reduce.addActionListener(bh2);
reset.addActionListener(bh3);
}
}
class SquarePanel extends JPanel {
Square theApplet;
SquarePanel(Square app) {
theApplet = app;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.green);
g.fillRect(10, 10, theApplet.size, theApplet.size);
}
}
class ButtonHandler implements ActionListener {
Square theApplet;
int number;
ButtonHandler(Square app, int num) {
theApplet = app;
number = num;
}
public void actionPerformed(ActionEvent e) {
switch (number) {
case 0:
theApplet.size = theApplet.size + 10;
theApplet.repaint();
break;
case 1:
if (theApplet.size > 10) {
theApplet.size = theApplet.size - 10;
theApplet.repaint();
}
break;
case 2:
theApplet.size = 100;
theApplet.repaint();
break;
}
}
Not the best way to do it, but based on your current code, you could simply compare the object references. You'd need to pass in references to the buttons or access them some other way. e.g.
if(e.getSource() == increase) { \\do something on increase}
Another alternative would be to check the string of the button, e.g.
if(((JButton)e.getSource()).getText().equals("+")){ \\do something on increase}
You can use strings in a switch statement in Java 8, but if you're using Java 7 or lower, it has to be an if statement.
You can use if then else statement as in the sample below
if(e.getSource()==bh1){
//your codes for what should happen
}else if(e.getSource()==bh2){
}else if(e.getSource()==bh3){
}else if(e.getSource()==bh4){
}
OR even in a switch case statement
I was given this code by my professor and it should run as is.
I compile it and get the following error.
java.lang.NullPointerException
at WholePanel.<init>(WholePanel.java:59)
at Assignment7.init(Assignment7.java:19)
at sun.applet.AppletPanel.run(AppletPanel.java:435)
at java.lang.Thread.run(Thread.java:744)
I have no idea why this is happening. Here are my classes.
I compiled and ran the code, got the error, tried commenting some things out and still nothing. I have programmed some previous applets and they run fine.
Assignment7
import javax.swing.*;
public class Assignment7 extends JApplet
{
public void init()
{
// create a WholePanel object and add it to the applet
WholePanel wholePanel = new WholePanel();
getContentPane().add(wholePanel);
//set applet size to 400 X 400
setSize (400, 400);
}
}
Whole Panel
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.ArrayList;
public class WholePanel extends JPanel
{
private Color currentColor;
private CanvasPanel canvas;
private JPanel primary, buttonPanel, leftPanel;
private JButton erase, undo;
private ArrayList rectList, tempList;
private JRadioButton[] colorRButtons;
private Color[] colors;
private int x1, y1, x2, y2, x3, y3;
private boolean mouseDragged = false;
//Constructor to instantiate components
public WholePanel()
{
//default color to draw rectangles is black
currentColor = Color.black;
rectList = new ArrayList();
//create buttons
//create radio buttons for 5 colors
//black will be chosen by default
colorRButtons = new JRadioButton[5];
colorRButtons[0] = new JRadioButton("black", true);
//store 5 colors in an array
//group radio buttons so that when one is selected,
//others will be unselected.
ButtonGroup group = new ButtonGroup();
for (int i=0; i<colorRButtons.length; i++)
group.add(colorRButtons[i]);
//add ColorListener to radio buttons
ColorListener listener = new ColorListener();
for (int i=0; i<colorRButtons.length; i++)
colorRButtons[i].addActionListener(listener);
//primary panel contains all radiobuttons
primary = new JPanel(new GridLayout(5,1));
for (int i=0; i<colorRButtons.length; i++)
primary.add(colorRButtons[i]);
//canvas panel is where rectangles will be drawn, thus
//it will be listening to a mouse.
canvas = new CanvasPanel();
canvas.setBackground(Color.white);
canvas.addMouseListener(new PointListener());
canvas.addMouseMotionListener(new PointListener());
JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, canvas);
setLayout(new BorderLayout());
add(sp);
}
//ButtonListener defined actions to take in case "Create",
//"Undo", or "Erase" is chosed.
private class ButtonListener implements ActionListener
{
public void actionPerformed (ActionEvent event)
{
}
} // end of ButtonListener
// listener class to set the color chosen by a user using
// the radio buttons.
private class ColorListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
if (event.getSource() == colorRButtons[0])
currentColor = colors[0];
else if (event.getSource() == colorRButtons[1])
currentColor = colors[1];
else if (event.getSource() == colorRButtons[2])
currentColor = colors[2];
else if (event.getSource() == colorRButtons[3])
currentColor = colors[3];
else if (event.getSource() == colorRButtons[4])
currentColor = colors[4];
}
}
//CanvasPanel is the panel where rectangles will be drawn
private class CanvasPanel extends JPanel
{
//this method draws all rectangles specified by a user
public void paintComponent(Graphics page)
{
super.paintComponent(page);
//draw all rectangles
for (int i=0; i < rectList.size(); i++)
{
// ((Rect) rectList.get(i)).draw(page);
}
//draw an outline of the rectangle that is currently being drawn.
if (mouseDragged == true)
{
page.setColor(currentColor);
//Assume that a user will move a mouse only to left and down from
//the first point that was pushed.
page.drawRect(x1, y1, x3-x1, y3-y1);
}
}
} //end of CanvasPanel class
// listener class that listens to the mouse
public class PointListener implements MouseListener, MouseMotionListener
{
//in case that a user presses using a mouse,
//record the point where it was pressed.
public void mousePressed (MouseEvent event)
{
//after "create" button is pushed.
}
//mouseReleased method takes the point where a mouse is released,
//using the point and the pressed point to create a rectangle,
//add it to the ArrayList "rectList", and call paintComponent method.
public void mouseReleased (MouseEvent event)
{
}
//mouseDragged method takes the point where a mouse is dragged
//and call paintComponent nethod
public void mouseDragged(MouseEvent event)
{
canvas.repaint();
}
public void mouseClicked (MouseEvent event) {}
public void mouseEntered (MouseEvent event) {}
public void mouseExited (MouseEvent event) {}
public void mouseMoved(MouseEvent event) {}
} // end of PointListener
} // end of Whole Panel Class
It seems you create only one colorRButtons, but trying to use all five.
So in colorRButtons[0] is not null, but all others are null and using of addActionListener for them is impossible.
In this loop
for (int i=0; i<colorRButtons.length; i++)
colorRButtons[i].addActionListener(listener);
you are accessing an array of colorRButtons, but only the first one
colorRButtons[0] = new JRadioButton("black", true);
has been created.
I'm new to java, and have been working on creating a code to get a small picture of a car to move using the keys. My problem is when I add more than 1 buttons to the panel. The function of the button in the code I post is nothing, just prints "button [i] clicked" message. The purpose is for them to read a file and update the locations of the car from the data in the file. This is supposed to be a piece on my Reinforcement Learning project. I thought it would be a good opportunity to learn java since this "graphics package" is not necessary for the project, just a "nice" addition. The code is here:
package graphics;
public class Board extends JPanel implements ActionListener {
private Timer timer;
private Agent agent;
private String button = "button.png";
private Image image;
protected JButton b1;
protected JButton b2;
protected JButton b3;
public Board() {
//Keylistener added for the agent to respond to arrow keys
addKeyListener(new TAdapter());
agent = new Agent();
timer = new Timer(10, this); //10ms timer calls action performed
timer.start();
//This part for the button.
ImageIcon i = new ImageIcon(this.getClass().getResource(button));
image = i.getImage();
b1 = new JButton("1", i);
b1.setVerticalTextPosition(AbstractButton.CENTER);
b1.setHorizontalTextPosition(AbstractButton.LEADING);
b1.setActionCommand("Active1");
b2 = new JButton("2", i);
b2.setVerticalTextPosition(AbstractButton.CENTER);
b2.setHorizontalTextPosition(AbstractButton.LEADING);
b2.setActionCommand("Active2");
b3 = new JButton("3", i);
b3.setVerticalTextPosition(AbstractButton.CENTER);
b3.setHorizontalTextPosition(AbstractButton.LEADING);
b3.setActionCommand("Active3");
b1.addActionListener(this);
b2.addActionListener(this);
b3.addActionListener(this);
add(b1); add(b2); add(b3);
setFocusable(true);
setBackground(Color.BLACK);
setDoubleBuffered(true);
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
//Transformations for the agent to be painted based upon its position and orientation
AffineTransform trans = new AffineTransform();
trans.rotate(Math.toRadians(agent.getTh()), agent.getX()+64, agent.getY()+64);
trans.translate(agent.getX(), agent.getY());
g2d.drawImage(agent.getImage(), trans, this); // Draws agent with said transformations
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
public void actionPerformed(ActionEvent ae) {
b1.setEnabled(true);
b2.setEnabled(true);
b3.setEnabled(true);
if (ae.getActionCommand()=="Active1") {
b1.setEnabled(false);
b2.setEnabled(true);
b3.setEnabled(true);
System.out.println("Clicked 1");
agent.reset();
}
if(ae.getActionCommand()=="Active2") {
b1.setEnabled(true);
b2.setEnabled(false);
b3.setEnabled(true);
System.out.println("Clicked 2");
agent.reset();
}
if (ae.getActionCommand()=="Active3") {
b1.setEnabled(true);
b2.setEnabled(true);
b3.setEnabled(false);
System.out.println("Clicked 3");
agent.reset();
}
agent.move();
repaint();
}
private class TAdapter extends KeyAdapter {
public void keyReleased(KeyEvent e) {
agent.keyReleased(e);
}
public void keyPressed(KeyEvent e) {
agent.keyPressed(e);
}
}
}
Now, the problem is this. If I click button 1, or button 2, the other buttons are disabled and it says "Clicked 1 (or 2)" which is fine. But the agent.move() and repaint() aren't invoked. The car doesn't move when I press the keys. If I then click button 3, the other two buttons are disabled and the car moves with the keys.
If I add buttons in a different order add(b3); add(b2); add(b1); then the same happens but this time its button 1 that works fine.
Problems:
Your main problem is one of focus -- When a JButton gets focus and the JPanel loses focus, the JPanel's KeyListener won't work, since the KeyListener requires that the listened to component have the focus, no exception.
A bad solution is to force the JPanel to retain the focus at all times. This will be bad if your window has JButtons and will be disaster if you need to display JTextFields, JTextAreas, or other text components.
A better solution is not to use a KeyListener as it has lots of problems with Swing applications and in particular it has focus issues as noted above. Use Key Bindings instead. Google the tutorial for the gory details on this.
Don't use == to compare Strings, use equals(...) or equalsIgnoreCase(...) instead. The problem is that == checks for object equality, is String A the same object as String B, and you don't care about this. You want to know if the two Strings hold the same chars in the same order which is where the two methods come in.
Don't dispose() of a Graphics object given you by the JVM as this may mess up the painting of a component's borders, children, and have even other side effects.
don't draw in the JPanel's paint(...) method but rather in its paintComponent(...) method just as the tutorials tell you to do. Drawing in paint(...) can have side effects on a component's borders and children if you're not careful, and also does not have the benefit of default double buffering which is important for smooth animation. paintComponent(...) fixes all these problems.
Speaking of which, you should Google and read the Swing graphics tutorials. You can't make stuff up and hope that it will work, and graphics programming will require a whole different approach from what you're used to.
Ignore Andromeda's threading suggestion. While he means well, I suggest that you don't do painting in a background thread. Just move the car with your Swing Timer as you're doing. Background threading has its uses, but not here, as a Timer will work just fine. You will need to use a background thread when you have a long-running process that blocks the calling thread, something that you don't have in your current code, and so a thread "fix" is not needed and in fact is a potential source of problems if you don't take extreme care to make your Swing calls on the Swing event thread. The unknown for us though is what your "agent" is doing. If it is calling long-running code or code with Thread.sleep(...) or wait()/notify() in it, then yes, you will need to use background threading.
But again, we know that's not your primary problem, since your problems began only after adding focus grabbers -- the JButtons. Again this is strong indication that your primary problem is not threading but is use of KeyListeners and their focus requirement.
For example:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.*;
import java.util.EnumMap;
import javax.swing.*;
#SuppressWarnings("serial")
public class KeyBindingPanel extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = PREF_W;
private static final Stroke THICK_STROKE = new BasicStroke(5f,
BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
private static final int OVAL_WIDTH = 30;
private static final int OVAL_HEIGHT = 30;
private static final Color OVAL_COLOR = Color.red;
private static final Color BKGRD_COLOR = Color.black;
private static final int TIMER_DELAY = 20;
public static final int STEP = 2;
private int myX = 0;
private int myY = 0;
private JButton[] buttons = new JButton[3];
private int condition = WHEN_IN_FOCUSED_WINDOW;
private InputMap inputMap = getInputMap(condition);
private ActionMap actionMap = getActionMap();
private EnumMap<Direction, Boolean> directionMap = new EnumMap<Direction, Boolean>(
Direction.class);
public KeyBindingPanel() {
for (int i = 0; i < buttons.length; i++) {
buttons[i] = new JButton(new ButtonAction());
add(buttons[i]);
}
setBackground(BKGRD_COLOR);
for (final Direction direction : Direction.values()) {
directionMap.put(direction, Boolean.FALSE);
Boolean[] onKeyReleases = { Boolean.TRUE, Boolean.FALSE };
for (Boolean onKeyRelease : onKeyReleases) {
KeyStroke keyStroke = KeyStroke.getKeyStroke(
direction.getKeyCode(), 0, onKeyRelease);
inputMap.put(keyStroke, keyStroke.toString());
actionMap.put(keyStroke.toString(), new DirAction(direction,
onKeyRelease));
}
}
new Timer(TIMER_DELAY, new GameTimerListener()).start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2b = (Graphics2D) g.create();
g2b.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2b.setStroke(THICK_STROKE);
g2b.setColor(OVAL_COLOR);
g2b.drawOval(myX, myY, OVAL_WIDTH, OVAL_HEIGHT);
g2b.dispose(); // since I created this guy
}
private class GameTimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
for (Direction direction : Direction.values()) {
if (directionMap.get(direction)) {
myX += STEP * direction.getRight();
myY += STEP * direction.getDown();
}
}
repaint();
}
}
private class DirAction extends AbstractAction {
private Direction direction;
private boolean onRelease;
public DirAction(Direction direction, boolean onRelease) {
this.direction = direction;
this.onRelease = onRelease;
}
#Override
public void actionPerformed(ActionEvent evt) {
directionMap.put(direction, !onRelease); // it's the opposite!
}
}
private class ButtonAction extends AbstractAction {
public ButtonAction() {
super("Press Me!");
}
#Override
public void actionPerformed(ActionEvent e) {
JButton thisBtn = (JButton) e.getSource();
for (JButton btn : buttons) {
if (btn == thisBtn) {
btn.setEnabled(false);
} else {
btn.setEnabled(true);
}
}
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("KeyBindingPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new KeyBindingPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
enum Direction {
UP(KeyEvent.VK_UP, -1, 0), DOWN(KeyEvent.VK_DOWN, 1, 0), LEFT(
KeyEvent.VK_LEFT, 0, -1), RIGHT(KeyEvent.VK_RIGHT, 0, 1);
private int keyCode;
private int down;
private int right;
private Direction(int keyCode, int down, int right) {
this.keyCode = keyCode;
this.down = down;
this.right = right;
}
public int getKeyCode() {
return keyCode;
}
public int getDown() {
return down;
}
public int getRight() {
return right;
}
}
It seems you need to use Threading. You can make your class to implements Runnable and then override the public void run(){} method and do the painting there.
I have a problem with the code I am currently trying to run - I am trying to make 3 buttons, put them on a GUI, and then have the first buttons colour be changed to orange, and the buttons next to that colour change to white and green. Every click thereafter will result in the colours moving one button to the right. My code thus far is as follows, it is skipping colours in places and is not behaving at all as I expected. Can anyone offer some help/guidance please ?
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class ButtonJava extends JButton implements ActionListener {
private int currentColor=-1;
private int clicks=0;
private static final Color[] COLORS = {
Color.ORANGE,
Color.WHITE,
Color.GREEN };
private static ButtonJava[] buttons;
public ButtonJava( ){
setBackground( Color.YELLOW );
setText( "Pick ME" );
this.addActionListener( this );
}
public static void main(String[] args) {
JFrame frame = new JFrame ("JFrame");
JPanel panel = new JPanel( );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE);
buttons = new ButtonJava[3];
for(int i = 0;i<buttons.length ; i++){
buttons[i] = new ButtonJava();
panel.add(buttons[i]);
}
frame.getContentPane( ).add( panel );
frame.setSize( 500, 500);
frame.setVisible( true );
}
private void updateButton() {
clicks++;
changeColors();
// setText( );
}
private void changeColors( ) {
for (int i=buttons.length-1;i>=0;i--){
buttons[i].currentColor = nextColor(currentColor);
buttons[i].setBackground(COLORS[buttons[i].currentColor]);
buttons[i].setText(("# of clicks = " + buttons[i].getClicks() ) );
}
}
private Integer getClicks() {
return clicks;
}
private int nextColor( int curCol ) {
final int colLen = COLORS.length;
curCol--;
curCol = (colLen + curCol % colLen) % colLen;
return curCol;
}
private void firstClick( ActionEvent event ) {
int curCol = 0;
for (int i=buttons.length-1;i>=0;i--){
if ( buttons[i] == event.getSource() ) {
buttons[i].currentColor = curCol;
curCol++;
currentColor++;
}
}}
#Override
public void actionPerformed( ActionEvent event ) {
if ( -1 == currentColor ) {
firstClick( event );
}
updateButton( );
}
}
Thank you very much for the help :)
You have a couple issues with the code you posted, but they generally boil down to being clear about what is a member of the class(static) and what is a member of the instance.
For starters, you buttons array only exists inside your main method and can't be accessed by changeColors(). Along those same lines, since changeColors() is an instance method, setBackground() needs to be called directly on the button in your array. as written you are setting the color for one button 3 times.
Additionally, the logic in changeColors() is not properly rotating the currentColor index. You need to both increase the counter and ensure is wraps for the length of the color array. If the arrays are the same size, you need to make sure there is an extra addition to make the colors cycle.
private static void changeColors( ) {
for (int i=0;i<buttons.length;i++){
buttons[i].setBackground(COLORS[currentColor]);
currentColor = nextColor(currentColor);
}
if (buttons.length == COLORS.length) {
currentColor = nextColor(currentColor);
}
}
private static int nextColor(int currentColor) {
return (currentColor+1)% COLORS.length;
}
Edit for new code:
I'm not sure why you re-wrote nextColor(), as what I posted worked. But in general, I feel like you are running into issues because your code is not well partitioned for the tasks you are trying to achieve. You have code related to the specific button instance and code related to controlling all the buttons mixing together.
With the following implementation, the issue of how many times a button was clicked is clearly self-contained in the button class. Then every button press also calls the one method in the owning panel. This method knows how many buttons there are and the color of the first button. And each subsequent button will contain the next color in the list, wrapping when necessary.
public class RotateButtons extends JPanel {
private static final Color[] COLORS = { Color.ORANGE, Color.WHITE, Color.GREEN };
private static final int BUTTON_COUNT = 3;
private JButton[] _buttons;
private int _currentColor = 0;
public static void main(String[] args)
{
JFrame frame = new JFrame("JFrame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new RotateButtons());
frame.setSize(500, 500);
frame.setVisible(true);
}
public RotateButtons()
{
_buttons = new JButton[BUTTON_COUNT];
for (int i = 0; i < _buttons.length; i++) {
_buttons[i] = new CountButton();
add(_buttons[i]);
}
}
private void rotateButtons()
{
for (JButton button : _buttons) {
button.setBackground(COLORS[_currentColor]);
_currentColor = nextColor(_currentColor);
}
if (_buttons.length == COLORS.length) {
_currentColor = nextColor(_currentColor);
}
}
private int nextColor(int currentColor)
{
return (currentColor + 1) % COLORS.length;
}
private class CountButton extends JButton {
private int _count = 0;
public CountButton()
{
setBackground(Color.YELLOW);
setText("Pick ME");
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0)
{
_count++;
setText("# of clicks = " + _count);
rotateButtons();
}
});
}
}
}
2nd Edit:
Shows just the changes to shift _currentColor by the necessary amount on the first click.
public class RotateButtons extends JPanel {
...
private boolean _firstClick = true;
...
private void rotateButtons(CountButton source)
{
if (_firstClick) {
_firstClick = false;
boolean foundSource = false;
for (int i = 0; i < _buttons.length; i++) {
if (foundSource) {
_currentColor = nextColor(_currentColor);
} else {
foundSource = _buttons[i] == source;
}
}
}
...
}
private class CountButton extends JButton {
...
public CountButton()
{
...
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0)
{
...
rotateButtons(CountButton.this);
}
});
}
}
One thing that I noticed is you are using currentColor to assign the color, but the currentColor is initialized to 0 and the only manipulation is currentColor %= 2 which does not change it.
If I'm understanding what you are wanting to achieve, I'm thinking to change currentColor %= 2 to ++currentColor, and setBackground(COLORS[currentColor]); to buttons[i].setBackground(COLORS[(i + currentColor) % 3]);. That way, your colours should cycle around your buttons each time one is clicked.
EDIT: it's probably also worth calling changeColors from within main to initialise your button colours. And, as #unholysampler notes, your array buttons is local to main and should (for example) be refactored as a static member variable, and have changeColors become a static method.