I'm in a rut trying to program a traffic lights simulation for my Intro to Programming in Java course. When I run the applet, all three lights are still lit up even though I haven't clicked any of the JButtons yet. When I do, the applet does turn blank momentarily like it's doing something, and if I press GO, the car does move. I'm wondering if I need to reset the colors in the graphics class, or use switch statements (which I'm not really certain how to do) and begin with a color as I've seen in other examples. Is there anything incorrect in my code that's hindering me from getting the results I want? Any help would be greatly appreciated. Thank you.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
/**
* Class TrafficLights - At the click of a button, change the traffic lights
*
* #author Mickey Mouse
* #version JDK 8
* #course CSCI 1130-01
* #date 10-2-15
*/
public class TrafficLights extends JApplet implements ActionListener {
private JButton WAIT, STOP, GO;
private boolean clickWAIT = false;
private boolean clickSTOP = false;
private boolean clickGO = false;
private int carX = 200;
/**
* Called by the browser or applet viewer to inform this JApplet that it
* has been loaded into the system. It is always called before the first
* time that the start method is called.
*/
public void init()
{
setLayout( new FlowLayout()); // changes the layout from BorderLayout to FlowLayout
WAIT = new JButton ("WAIT"); //adds WAIT label to button
WAIT.setForeground(Color.yellow); //changes the label to yellow
//adds the WAIT JButton to the screen
add (WAIT);
WAIT.addActionListener(this);
GO = new JButton ("GO"); //adds GO label to button
GO.setForeground(Color.green); //changes the label to green
//adds the button to the screen
add (GO);
GO.addActionListener(this);
STOP = new JButton ("STOP"); //adds STOP label to button
STOP.setForeground(Color.red); //changes the label to red
//adds STOP JButton to screen
add (STOP);
STOP.addActionListener(this);
}
/**
* Called by the browser or applet viewer to inform this JApplet that it
* should start its execution. It is called after the init method and
* each time the JApplet is revisited in a Web page.
*/
public void start()
{
// provide any code requred to run each time
// web page is visited
}
/**
* Called by the browser or applet viewer to inform this JApplet that
* it should stop its execution. It is called when the Web page that
* contains this JApplet has been replaced by another page, and also
* just before the JApplet is to be destroyed.
*/
public void stop()
{
// provide any code that needs to be run when page
// is replaced by another page or before JApplet is destroyed
}
/**
* Paint method for applet.
*
* #param g the Graphics object for this applet
*/
public void paint(Graphics g)
{
super.paint(g);
//declares and retrieves the images from their file locations
Image img = getImage(getDocumentBase(), "stoplights.png");
Image img2 = getImage(getDocumentBase(), "car.jpg");
g.drawImage( img, 50, 100, 300, 350, 0, 0, 5000, 5000, this ); //draws and resizes the stoplights image
g.drawImage( img2, carX, 400, 1000, 1000, 0, 0, 5000, 5000, this); //draws and resizes the car image
//draw and fill an oval red for the STOP stoplight when STOP is pressed
if (clickSTOP == true);
{
g.drawOval(63, 112, 30, 30);
g.setColor(Color.red);
g.fillOval(63, 112, 30, 30);
clickSTOP = false;
}
//draw and fill an oval yellow for the WAIT stoplight when WAIT is pressed
if (clickWAIT == true);
{
g.setColor(Color.black);
g.drawOval(63, 148, 30, 30);
g.setColor(Color.orange);
g.fillOval(63, 148, 30, 30);
clickWAIT = false;
}
//draw and fill an oval green for the GO stoplight when GO is pressed
if (clickGO == true);
{
g.setColor(Color.black);
g.drawOval(63, 184, 30, 30);
g.setColor(Color.green);
g.fillOval(63, 184, 30, 30);
clickGO = false;
}
}
public void actionPerformed(ActionEvent event)
{
/*
* Links the JButtons and the graphic sequences to display the lights
*
*/
if(event.getSource() == GO) //display green if GO is clicked
{
clickGO = true;
carX -=15;
repaint();
}
if (event.getSource() == WAIT) //display yellow if WAIT is clicked
{
clickWAIT = true;
repaint();
}
if (event.getSource() == STOP) //display red if STOP is clicked
{
clickSTOP = true;
repaint();
}
}
/**
When I run the applet, all three lights are still lit up even though I haven't clicked any of the JButtons yet
This is because you have a ; after each of your if statements, which is basically short circuiting your logic, so the code following it, is always executed, regardless of the state of the variable...
if (clickSTOP == true);
So, instead, you should be using something more like
if (clickSTOP == true)
{
g.setColor(Color.red);
g.fillOval(63, 112, 30, 30);
clickSTOP = false;
}
You are also modifying the state of the program from within you paint method, this is generally discouraged, as paint should just do that, paint the current state.
The better place to change the state is in the ActionListener.
Rather then having three state variables, which are generally describing the same thing, you should have a single state variable, so the state can only ever be go or wait or stop, never a combination of all three.
Equally, you could use a ButtonGroup and JToggleButtons or JRadioButtons, this would allow the buttons to carry a certain amount of the information about the state, as only only button could be selected at a time.
Have a look at How to Use the ButtonGroup Component and How to Use Buttons, Check Boxes, and Radio Buttons for more details
When I do, the applet does turn blank momentarily like it's doing something
This could be caused by the fact that you are loading images from within the paint method, but as a general rule, you should avoid overriding paint of top level containers like this.
Related
I am trying to make a chess engine as a fun project, but for that I really want to make a GUI. The problem is that I have no experience with this, so I am a little stuck. I managed to create the board, but there are two things I have no idea how to do and looking online just confuses me further.
How do I add the pieces to the board, based on what the board looks like in the computers memory. (so for example if the engine makes a move, I want that move to also happen on the gui, how would I link the two?)
How do I figure out what square the user is clicking on in the gui?
This is the code I have so far for the gui, it's not much, but it's honest work
private final JFrame gameFrame;
private Board board;
public Table() {
this.board = new Board();
this.gameFrame = new JFrame("Chess");
this.gameFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.gameFrame.setSize(527, 550);
JPanel panel = new JPanel() {
#Override
public void paint(Graphics g) {
boolean white = true;
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
if (white) {
g.setColor(new Color(240, 217, 181));
}
else {
g.setColor(new Color(181, 136, 99));
}
g.fillRect(j * 64, i * 64, 64, 64);
white = !white;
}
white = !white;
}
}
};
this.gameFrame.add(panel);
this.gameFrame.setVisible(true);
}
I know I am probably asking questions with complicated answers, but I am just looking for something I can look up or some general directions
One way and perhaps the the most useful is to implement a mouseListenerand then get the x y position from one of the methods.
Write a class to extend MouseAdapter.
override the desired empty methods.
then add an instance of that class to the frame via addMouseListener (and perhaps addMouseMotionListener).
Then when you do some action with the mouse, you can get the coordinnates from the MouseEvent. It helps to put some print statements in each method to observe what is going on (what method is processing what mouse movement).
The above will serve to demonstrate the process. But later on you should actually add the listener on a JPanel and add the JPanel to the frame.
I am coding a game in Java. The first screen is the begin screen. On a mouse click, the screen is supposed to switch to a screen that lets you choose a character. Then, the next screen is the first game question. The character choosing screen isn't coming. It is just going to the first question. drawq is the boolean that determines if the question has been drawn. I had initialized it to false in the beginning of my code. Here is my mouselistener method, please help me find a way to get the screen that displays "Choose your character" and the image of the girl.
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
//background image
g.drawImage(theme.getImage(),0,0,WIDTH,HEIGHT,null);
//Choosing character screen
g.drawString("Choose your character", WIDTH-1550, HEIGHT/6);
g.drawImage(girl.getImage(),WIDTH-1550,HEIGHT/2,237,338,null);
//switching drawq to false
drawq=true;
//draw next question on mouse click
if(drawq==true) {
questions[whichquestion].draw(g);
drawq=false;
repaint();
}
It seems like you have got the order of your code mixed up, you set drawq to true and then immediately afterwards check if it's true, which will obviously always result in the if clause beeing run.
There are tons of tutorials for developing games on Java. Also here on SO there are many questions and answers. Just take a look at one or the other and let yourself be inspired.
An example of mouse input and screen output:
public class Main extends JPanel{
private int clicks = 0;
private Random rnd = new Random();
public static void main(String[] args){
var frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.setContentPane(new Main());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
}
public Main(){
addMouseListener(new MouseInputAdapter(){
#Override
public void mouseClicked(MouseEvent e){
clicks = e.getClickCount();
repaint();
}
});
setPreferredSize(new Dimension(640, 480));
repaint();
}
#Override
public void paintComponent(Graphics g){
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.WHITE);
g.drawString("Click your Mousebutton! One, two, three times or more ;-)", 20, 20);
if(clicks > 0) {
g.drawString("Clicks counted: " + clicks, 20, 40);
for(int i = 0; i < clicks; i++){
g.setColor(new Color(rnd.nextInt(256),rnd.nextInt(256),rnd.nextInt(256),255));
g.drawLine(20, 60 + i * 10, 100 + i * 20, 60 + i * 10);
}
}
}
}
I suggest that you go back to the drawing board. You should create a JFrame subclass that has a JLabel and a JImage on it. Then when the user clicks the button, just show that JFrame.
In gneeral, don't use a Graphics object outside of paintComponent(). And don't use drawImage() or drawText() unless you have a good reason. In this case, a JLabel and a JImage are much more appropriate for implementing the elements in the screen.
I am trying to draw a car as a polygon in swing and move it left and right when clicking button
The problem is that I can't display the buttons on the screen when running the program and can't make them works
And I Don't know how implement the buttons inside of the user interface when using polygon
Here is my code:-
package java2d;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Java2D extends JFrame{
int xValues[];
int yValues[];
private JButton Right, Left;
public Java2D() {
super( "Drawing lines, rectangles and ovals" );
setSize( 500, 300 );
setVisible( true );
}
public void paint( Graphics g ) {
int xValues[] = { 40, 100, 130, 230, 260, 320, 320, 40 };
int yValues[] = { 120, 120, 40, 40, 120, 120, 170, 170 };
Polygon polygon1 = new Polygon( xValues, yValues, 8 );
g.setColor(Color.blue);
g.drawPolygon( polygon1 );
Right = new JButton("Right");
Left = new JButton("Left");
Right.setSize(50, 50);
Left.setSize(50, 50);
Right.setLocation(100, 200);
Left.setLocation(200, 200);
g.add(Right);
g.add(Left);
}
public void actionPerformed(ActionEvent event) {
if(event.getActionCommand().equals("Right")){
for (int i=0; i<xValues.length;i++) {
xValues[i] = xValues[i] + 10;
yValues[i] = yValues[i] + 10;
}
}
if(event.getActionCommand().equals("Left")){
for (int i=0; i<xValues.length;i++) {
xValues[i] = xValues[i] + 10;
yValues[i] = yValues[i] + 10;
}
}
repaint();
}
public static void main(String[] args) {
Java2D application = new Java2D();
application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}
}
THANKS
Many issues:
Variable names should NOT start with an upper case character.
Custom painting is done by overriding the paintComponent() method of a JPanel and then you add the panel to the frame. Read the section from the Swing tutorial on Custom Painting for more information and working examples to get you started. Start with the working code and modify it for your requirement.
Never create Swing components in a painting method. The painting method is continually invoked when Swing determines the component needs to be repainted, so you don't want to keep creating new buttons.
Typically to add buttons to the frame you would create a JPanel and add the buttons to the panel. Then you add the panel to the frame using frame.add(buttonsPanel, BorderLayout.PAGE_START). Then you would add your painting panel to the frame using frame.add(paintingPanel, BorderLayout.CENTER). Read the section from the Swing tutorial on Layout Managers for more information and examples.
Instead of attempting to update the values of the Arrays used to create the Polygon you should be using the translate() method of the Polygon.
Keep a reference to the Swing tutorial handy as it contains examples for most Swing basics.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I'm having a couple of different problems with my code, most of them are GUI based problems but i do have one actionevent problem. I will post my code in sections first then I will point out what the issue is specifically with each section. *note all of my code will be in order of how is actually in my IDE.
If you wish to copy my code without all of the other stuff here it is on pastebin: http://pastebin.com/HHjRRtGZ
My imports:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*; //Makes it a Japplet
import java.util.Random;
My Program Starts here:
public class Hangman extends JApplet implements ActionListener {
// How many times you can guess the wrong letter till you lose
static final int DEAD = 7;
private int errors; // amount of errors
private String message; // Message displaying either Error or Victory
private String information; // Secondary Message
private String RealWord; // The Real word
private StringBuffer GuessWord;// The Guessed word
private Button StartBtn; // The Restart Button
private Button GoBtn; // The Go Button
private TextField LetterBox; // The LetterBox
My ActionEvent:
public void actionPerformed(ActionEvent e){
if (e.getSource() == StartBtn){
initGame();
}
if (e.getSource() == GoBtn){
processTurn();
LetterBox.setText("");
repaint();
}
}
Problem One:
The problem that I am having with my Action event is that when I hit the StartBtn it does not reinitialize everything. Nothing is cleared. Nothing is done. It doesn't do anything. So that's the issue there.
My init() function (This is where one of my problems lie.
public void init() {
// Create a "Textbox" for the letter guessing
LetterBox = new TextField();
//Create my buttons and labels
StartBtn = new Button("Restart");
GoBtn = new Button("Go");
//Add the elements to the applet
JPanel p = new JPanel();
p.setLayout(new FlowLayout());
p.add(StartBtn);
p.add(new Label("Guess a letter"));
p.add(LetterBox);
p.add(GoBtn);
add(p, BorderLayout.SOUTH);
//Make buttons event listeners
StartBtn.addActionListener(this);
GoBtn.addActionListener(this);
//Startup the Game
initGame();
}
Problem 2 (MAIN PROBLEM):
The problems I have with my Init code that affect my GUI is that the actual word guess area and the hangman area are kind of messed up. It's hard to explain, so i'll show you an image. The Backdrop for almost all of the form is completely transparent. So it just uses a still image of whatever it was on top of as it's back ground.
Problem 3:
There are some other issues with the image as you can see. The code is further down for those parts however. But as you can tell, the messages do not clear and just write over each other, even though I specify them to (which you will see further down).
Problem 4:
Now before you guess any letters, the word is hidden with a "" but when you guess a correct letter for the word it's supposed to replace the "" with the correct letter guessed. However it just put's it on top of it (you will see the code for this below as well).
This is the Game initializer
public void initGame() {
//Set the errors to 0
errors = 0;
//Enter the wordslist, separated by a | here
String str = "write|program|receive|positive|variables|temporary|good|bad|test";
String[] temp;
//delimiter
String delimiter = "\\|";
// given string will be split by the argument delimiter provided.
temp = str.split(delimiter);
//Create the Random Seed Generator
Random RandGenerator = new Random();
//Generate my Random Number
int randomInt = RandGenerator.nextInt(temp.length);
RealWord = new String(temp[randomInt]);
char positions[] = new char[RealWord.length()];
Right here is where it replaces the unguessed characters on screen with a "*".
for (int i = 0; i < RealWord.length(); i++) {
positions[i] = '*';
}
String s = new String(positions);
GuessWord = new StringBuffer(s);
LetterBox.setText("");
//Delete Messages
message = "";
information = "";
repaint();
}
My Painting function
#Override
public void paint(Graphics g) {
int BaseY = 250;
//THE HANGING STAND
if (errors > 0) { //1 Error
g.drawLine(90, BaseY, 200, BaseY); //The ground
g.drawLine(125, BaseY, 125, BaseY-100); //The bar going up
g.drawLine(125, BaseY-100, 175, BaseY-100); //The sidebar
g.drawLine(175, BaseY-100, 175, BaseY-75); //The Rope
}
//THE PERSON
if (errors > 1) {
g.drawOval(170, BaseY-75, 10, 12); // The Head
}
if (errors > 2) {
g.drawLine(175, BaseY-62, 175, BaseY-45); // The Body
}
if (errors > 3) {
g.drawLine(165, BaseY-65, 175, BaseY-55); // Left Arm
}
if (errors > 4) {
g.drawLine(185, BaseY-65, 175, BaseY-55); // Right Arm
}
if (errors > 5) {
g.drawLine(170, BaseY-30, 175, BaseY-45); //Left Leg
}
if (errors > 6) { //7 Errors
g.drawLine(175, BaseY-45, 180, BaseY-30); // Right Left
}
//Show Messages/Errors
g.drawString(message, 40, BaseY+25);
g.drawString(information, 25, BaseY+45);
g.drawString(new String (GuessWord), 140, BaseY-120);
g.drawString(new String("WELCOME TO HANGMAN!"), 75, 40);
}
This is where alot of the magic happens. This is the processTurn Function
private void processTurn() {
String s, t;
char a;
s = LetterBox.getText();
a = s.charAt(0);
if (!Character.isLetter(a)) {
message = "Only enter letters please.";
return;
}
if (s.length() > 1) {
message = "One letter at a time please.";
return;
}
//Check if letter has been used already
t = new String(GuessWord);
if (t.indexOf(s) != -1) {
message = "You have already guessed with that letter!";
return;
}
//If the letter you guessed does not occur in the Real Word
if (RealWord.indexOf(s) == -1) {
message = "";
errors++;
if (errors==DEAD) {
message = "Sorry, you lose";
information = "Click restart to try again!";
//INSERT MOVING HANGMAN HERE.
}
return;
}
This is where the "*" is supposed to be replaced with the correctl guessed letter but it doesn't work correctly!
//Replace stars in the Guessed Word with the found letter
for (int i = 0; i < RealWord.length(); i++) {
if (RealWord.charAt(i) == a) {
GuessWord.setCharAt(i, a);
}
}
t = new String(GuessWord);
//If all of the stars have been filled, then you win!
if (t.indexOf('*') == -1) {
message = "You have won!";
return;
}
//Delete the Message
message = "";
repaint();
}
Main Function
public static void main(String[] args) {
JFrame frame = new JFrame();
JApplet applet = new Hangman();
applet.init();
applet.start();
frame.add(applet);
frame.setSize(300, 400);
frame.setLocationRelativeTo(null); // Center the frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Any and all assistance will be greatly appreciated :) Thanks in advance!
This is caused by the basic fact that you have broken the paint chain.
Painting in AWT/Swing is made of a chain of method calls. If you neglect to maintain this chain, you start ending up with paint artifacts, in the form you are seeing.
The Graphics context is a shared resource, that is, every component painted during any given paint cycle will be given the same Graphics resource. Each component is expected to prepare the Graphics context before painting to it...
To fix the problem, in all your paint methods, you should be calling super.paint(g) to ensure that the paint chain is maintained and that the Graphics context is preapred for the individual components painting needs.
Having said that. It is not recommended to override paint of top level containers. Instead, it is recommended that you perform your custom painting using something like a JPanel and override it's paintComponent method instead (ensuring that you call super.paintComponent as well!)
This has a least two basic benefits. The first is, you can know decide where the panel should be displayed, for example, you could add it to an JApplet or JFrame or other container as you see fit. It is double buffered by default. This means you won't see any flicker when the painting is updated.
You should consider breaking your application down into small panels, focusing on each of the components needs separately. This will help reduce the complexity of your application and make it easier to manage the individual needs of each section of your application.
Take a look at Performing Custom Painting and Painting in AWT and Swing for more details
The problem is that you're painting directly on JApplet. You should not paint directly on top level container such as JFrame or JApplet. Instead, use JComponent or JPanel. Override paintComponent() for painting rather than paint() and don't forget to call super.paintComponent(g).
Take a look at Performing Custom Painting tutorial for more information.
Consider refactoring your code by moving all the current logic and painting into a new JPanel which will be used as applet content. Then, add this panel to the applet.
EDIT:
The source of the problem is not calling super.paint() in you painting implementation. Overriding paint() is not necessary and usually not recommended in many Swing applications. JComponent.paint() (a superclass for all Swing components) handles painting the content, borders, and children of a Swing component. And by neglecting a call to super.paint() you are disrupting the painting of all these details.
Take a looks at A Closer Look at the Paint Mechanism for more details about painting cycle.
I'm attempting to create my own custom ToolTip for a program I've ported to Java, I'm trying to match the original programs ToolTips (it was written in Delphi). I've got some code that allows me to draw "inside" a ToolTip but for some reason, if I Override paint(Graphics g, JComponent c) and leave it blank it still draws a ToolTip, and anything I attempt to draw will be drawn "inside" this little boxed ToolTip and I can't draw "outside" of it.
import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.basic.BasicToolTipUI;
class MultiLineToolTipUI extends BasicToolTipUI {
#Override
public void paint(Graphics g, JComponent c) {
//int mY = 0;
//int mX = 0;
//int xPoints[] = {mX, mX, mX + 15};
//int yPoints[] = {mY, mY + 25, mY + 25};
//Polygon p = new Polygon(xPoints, yPoints, 3);
//g.setColor(Color.BLACK);
//g.fillPolygon(p);
//g.fillRoundRect(mX, mY, 100, 50, 30, 30);
}
public static void main (String args[])
{
JButton button = new JButton ("Mouse Over ME!") {
public JToolTip createToolTip() {
MultiLineToolTip tip = new MultiLineToolTip();
tip.setComponent(this);
return tip;
}
};
//JButton button = new JButton("Mouse Over ME!");
button.setToolTipText("Hello, World");
JFrame frame = new JFrame("Basic SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( button );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
static class MultiLineToolTip extends JToolTip
{
public MultiLineToolTip()
{
setUI(new MultiLineToolTipUI());
}
}
}
This is what I have, and like I said, even without the lines in paint it's drawing on it's own.
Any advice to get around this? Or a better way to go about what I'm trying to do?
CLARIFICATION: The first answer by Camickr was very helpful, however I should clarify my goal is to get the box that is automatically drawn from somewhere outside of paint to go away, or be invisible.
The size of the tool tip is determined by the text. Add:
System.out.println( c.getSize() );
to the paint(...) method to see the size of the tool tip. You are trying to paint outside its bounds. If you want to override the default size then you need to set the preferred size yourself. I think you want:
public Dimension getPreferredSize(JComponent c)
{
return new Dimension(100, 50);
}
Edit: A tooltip is a component with a border and a background. If you want to remove them you can use:
tip.setOpaque(false);
tip.setBorder(new javax.swing.border.EmptyBorder(0, 0, 0, 0));
This will only work when to tooltip is fully contained withing the frame. When the tooltip is displayed outside the bounds of the frame, then the tooltip is added to a JWindow, in which case you will see the background of the window. I don't know how to disable this behaviour because all Swing components must be painted within the bounds of a top level container.