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.
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.
To start with -- I'm not sure, that I have properly formulated the question (I'm new in Java and in making programs with GUI).
It is the following thing, I'm trying to do. I have a window with several similar parameters (numbers are just for distinction between lines and it ist just very simplified example, of what should my GUI be):
Initial Window
Then, by clicking on the "+"-button I would like to add an new line, like here:
Line 35 is added
It should be also possible to delete lines, like here: Line 30 was deleted, by pressing "-"-Button.
As I wrote at the beginning, it is possible, that there was such a question, but I couldn't find anything (probably, because I do not now the keywords or I was looking with a wrong ones).
How such window can be done? The only idea I have is to draw a new window after every +/-.
Addition: Code (not working in the part of changing the number of rows).
import javax.swing.*;
import java.awt.event.*;
public class Test extends JFrame {
public Test() {
setSize(200, 600);
JButton plusButton[] = new JButton[100];
JButton minusButton[] = new JButton[100];
JTextField fields[] = new JTextField[100];
JPanel panel1 = new JPanel();
for (int i=0; i<plusButton.length; i++) {
plusButton[i]=new JButton("+");
minusButton[i]=new JButton("-");
fields[i] = new JTextField("Text "+ i);
}
for (int i=1; i<4; i++) {
panel1.add(plusButton[i*10]);
plusButton[i*10].setActionCommand("add after " +String.valueOf(i));
panel1.add(minusButton[i*10]);
minusButton[i*10].setActionCommand("remove " +String.valueOf(i));
panel1.add(fields[i*10]);
}
panel1.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
this.getContentPane().add(panel1);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e) {
for (int i=0; i<100; i++) {
String stand1 = "add after "+String.valueOf(i);
String stand2 = "remove "+String.valueOf(i);
if (stand1.equals(e.getActionCommand())) {
//add "row" of elements
panel1.add(plusButton[i]);
plusButton[i+1].setActionCommand("add");
panel1.add(minusButton[i+1]);
minusButton[i+1].setActionCommand("remove");
panel1.add(fields[i+1]);
} else if (stand2.equals(e.getActionCommand())) {
//delete "row" of elements
}
}
}
public static void main(String[] args) {
Test a = new Test();
}
}
The Problem, that is obvious -- when I want to add 2 rows (i think it is proper definition) of buttons after button 20, there will be an doubling of numbers. As a solution I see here a creation of a new panel for each new row. But it is sounds wrong for me.
P.S. Unfortunately I do not have time to end this topic or to post a working example. I actually found some kind of solution, beginning from the Question here, on Stack Overflow:
Adding JButton to JTable as cell.
So, in case somebody will be looking for such topic, it should sounds like "jButton in jTable".
There are multiple GUI frameworks for Java. First decide which one you wanna use.
As for your particular query
Add functionality to the + and - such that it will create an instance of a field object (that line with parameters as you call them) or destroy that particular instance of the object.
+ is clicked -> Create new object on consecutive line and increase the pointer-count(?) of the following fields.
- is clicked -> Call destructor for the particular object and decrease the pointer-count of the following fields.
I am trying to learn some basic java by following a book, one of the exercises requires that I display a set of bar graphics based on user input.
I have to query the user to input the no. of bars to be shown and the length of each.
I use the following:
1`st is the Bar class I defined to draw rectangles corresponding to the numbers inputed
import java.awt.Graphics;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class Bar extends JPanel
{
private int noOfBars; // number of bars to display
int i = 0;
// constructor with choice input
public Bar (int noOfBars)
{
this.noOfBars = noOfBars;
}
// draw desired shapes starting from default position (0, 5) and incrementing for each new bar
public void paintComponent(Graphics g)
{
super.paintComponent(g);
do
{
String input = JOptionPane.showInputDialog("Enter number: ");
int length = Integer.parseInt(input);
for (int j = 1; j <= length; j++)
g.drawRect(0, 5 + i * 20 ,j * 15 , 15);
i++;
} while (i < noOfBars);
}
}
2`nd is the main class:
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class ShapesExercise
{
public static void main(String[] args)
{
int noOfBars = 0;
// obtain user choice
String input = JOptionPane.showInputDialog("Enter total bars to display:");
noOfBars = Integer.parseInt(input);
if (noOfBars == 0)
{
JOptionPane.showMessageDialog(null,"Invalid number.");
input = JOptionPane.showInputDialog("Enter total bars to display::");
noOfBars = Integer.parseInt(input);
}
JFrame application = new JFrame();
application.setSize(300, 40 + 25 * noOfBars);
Bar panel = new Bar(noOfBars);
application.add(panel);
application.setVisible(true);
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
My issue is as follows:
The first message_dialog (the one created in the main class) works correctly, popping up only once and querying for input.
But the message_dialogs generated by the Bar class keep popping up even after reaching the end of the "do while" loop (this was initially a "for" loop but I changed it to "do while" in an attempt to troubleshoot the code).
I have no idea why this happens. While researching online I could not find something related.
Thank you in advance.
paintComponent is called by Swing’s painting architecture, which in turn is largely dependent on the native system. paintComponent can be called several times per second, depending on the circumstances; it may be called once, or several times, when a window is moved or brought to the front. It may be called for each movement of the mouse over it.
You have no control over when paintComponent is called. You must only draw in that method. You MUST NOT call JOptionPane in it. You must not change any state, and you must not change the component or any other components in that method.
If you want to call JOptionPane, do it elsewhere, and then call repaint() to request that the Swing system eventually call your paintComponent method.
You can learn more at https://docs.oracle.com/javase/tutorial/uiswing/painting/.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I am quite new to Java. I decided to code tic-tac-toe as practice (from scratch).
Anyway, I am trying to have the 'JLabel label' change when I click; going from 1, then 2, etc. Eventually, it will change to something other than numbers. But, for now, it works for a test.
The 'System.out.println("Number of clicks: " + mouseIn);' works fine, and produces the output I want. A picture of the console and JFrame/JPanel/JLabel can be seen here:
(The little 1 in the JFrame is the JLabel. I want to match what is output in the console.
I have googled, and searched, and tried everything I know (which ain't much!) and I can't get the dang thing to work...I'm just asking for some guidance. Main method just includes building of JFrame/Panel.
Code below:
From the main class, called (namone.java [named it this for my own reasons]):
public void run(JPanel p) //Takes panel from main method {
for(int i = 0; i < ticList.length; i++){
ticList[i] = new JButton(buttonText); //For every position in
//ticList[], create a JButton object
p.add(ticList[i]);
ticList[i].setPreferredSize(new Dimension(140,140));
ticList[i].addMouseListener(mouse); //Load mouseListner
}
//Set mouseIn to click value in MouseEvents Class
int mouseIn = mouse.getClicks();
//Set text value to text value in MouseEvents class
text = mouse.getText();
//Output...
System.out.println("Number of clicks: " + mouseIn); //For testing
String mouse = Integer.toString(mouseIn); //Convert mouseIn value (from MouseEvents.java) to mouse
JLabel label = new JLabel(); //New JLabel
p.add(label); //Add label to screen
label.setText(mouse); //Set the text of the label to value of mouse
System.out.println(mouse); //For testing
//So I can see if it's working (clicks wise)
}
And then the code from my MouseEvents.java class:
public class MouseEvents extends namone implements MouseListener {
int clicks = 1;
String text = "first"; //For testing purposes
public namone game = new namone();
public int getClicks(){
return clicks;
}
public String getText(){
return text;
}
public int intToString(){
Integer.toString(clicks);
return clicks;
}
#Override
public void mouseClicked(MouseEvent e) {
clicks++;
intToString();
JPanel p = new JPanel();
text = "" + clicks;
game.run(p);
}
As I said. I am very new to Java and I'm trying to learn how to develop applications with it. I'm sure it's caused by my own ignorance.
Thanks.
Assuming that mouse is of type MouseEvents that you write, one possibility is that you need to pass mouse.getText() to your call to label.setText(.).
Regardless, the way you set up your game is a bit strange to me. What is the reason to create a brand new JPanel every time someone clicks? Why not maintain the original JPanel and update it instead. I personally would attach a custom ActionListener to each JButton that runs some code everytime the button is clicked. If this ActionListener is an inner class, it can also view variables in the scope that the JButton is defined.
For this program, the JButton doesn't seem to show up unless you click the area where the JButton should be; the JFrame starts up blank. The moment you click the button, the respective code runs and the button finally shows up.
How do I get the buttons to show up upon starting the program?
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
/*
The Amazing BlackJack Advisory Tool by JoshK,HieuV, and AlvinC.
Prepare to be amazed :O
*/
public class BlckJackUI {
//main class, will contain the JFrame of the program, as well as all the buttons.
public static void main(String args[])
{
//Creating the JFrame
JFrame GUI = new JFrame("Blackjack Advisor");
GUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GUI.setSize(1300, 900);
GUI.setContentPane(new JLabel(new ImageIcon("C:\\Users\\Hieu Vo\\Desktop\\Green Background.png")));
GUI.setVisible(true);
// Because each button needs to run through the Math class.
final Math math = new Math();
// The Ace Button:
ImageIcon Ace = new ImageIcon("/Users/computerscience2/Downloads/Ace.jpg");
JButton ace = new JButton(Ace);
ace.setSize(300, 100);
ace.setLocation(100, 100);
ace.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//Automatically default the the Ace to 11, and if Bust, Ace becomes 1.
if (math.array.playerhandtotal <= 21)
{
math.cardvalue = math.cardvalue + 11;
}
else
{
math.cardvalue = math.cardvalue + 1;
}
math.array.clicktracker++;
math.calcResult();
JOptionPane.showMessageDialog(null,math.array.result);
}
});
GUI.add(ace);
ImageIcon Two = new ImageIcon("/Users/computerscience2/Downloads/2.jpg");
JButton two = new JButton(Two);
two.setSize(300, 100);
two.setLocation(100, 200);
two.addActionListener(new ActionListener ()
{
public void actionPerformed(ActionEvent e)
{
/*
This generally repeats throughout the whole class, and the only
thing different is the changing cardvalue. When a button is pressed,
respective cardvalues are added into the playerhand ArrayList, and
totaled up to form playerhandtotal, which is a major factor in
bringing up the advice.
*/
math.cardvalue = math.cardvalue + 2;
math.array.clicktracker++;
math.calcResult();
JOptionPane.showMessageDialog(null,math.array.result);
}
});
GUI.add(two);
Et cetera, Et cetera... Just a bunch of the same stuff, more buttons coded the same exact way as JButton two, but with different value associated to them.
JButton start = new JButton("Start/Reset");
start.setSize(300, 100);
start.setLocation(500,500);
start.addActionListener(new ActionListener ()
{
public void actionPerformed(ActionEvent e)
{
/*
The start button also acts like a reset button, and the concept is fairly
simple. If we reset all the important values to 0 or "null," then the
program acts as if it was just opened.
*/
Arrays array = new Arrays();
array.playerhand.clear();
array.dealer = 0;
math.array.starttracker++;
math.array.clicktracker = 0;
array.playerhandtotal = 0;
math.cardvalue = 0;
array.result = null;
JOptionPane.showMessageDialog(null,"Please select the card \nthat the dealer is showing :)");
}
});
GUI.add(start);
GUI.setLayout(null);
This is all in the same class, and I understand a layout would be nicer, but perhaps there's a way to fix this issue using what I have now?
The program starts blank because you are calling setVisible before you add components. Call setVisible after you add components (in the end of contructor) and it should work fine.
Also, avoid absolute positioning and call of set|Preferred|Minimum|MaximumSize methods for your components. Learn how to use layout managers.
Write GUI.validate(); after you add all the components to your frame. Any time you add something to a frame you have to validate it like this. Otherwise, you will get the behavior that you have described.
No. The problem is caused by the layout. Before adding anything to a JFrame or a JPanel which you want it to have an absolute position, you have to setLayout(null). Otherwise, you'll have unexpected behaviours all the time. I just figured it out by myself after three hours of experimenting; suddenly, I connected your post with other different subject, and it worked, but this isn't well explained on the Internet yet.