Trivia game with JFrame - java

I'm trying to make a trivia game. My problem is that, the questions does not show up in the frame when I try to run the program. what should I do? Here's what I have done so far. any help would really be great. thanks in advance.
package trivia;
import java.util.Arrays;
import java.util.List;
public class ChemistryJFrame extends javax.swing.JFrame {
String question, answer;
ChemistryJFrame[] questionbank = new ChemistryJFrame[3];
List<ChemistryJFrame> questionlist = Arrays.asList(questionbank);
int quest;
public ChemistryJFrame() {
initComponents();
}
#SuppressWarnings("unchecked")
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
dispose();
MainJFrame Main = new MainJFrame();
Main.setVisible(true);
}
public static void main(String args[]) {
ChemistryJFrame bank = new ChemistryJFrame();
bank.banklist();
bank.startquiz();
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new ChemistryJFrame().setVisible(true);
}
});
}
public void banklist()
{
questionbank[0] = new ChemistryJFrame();
questionbank[0].question = "Which of the following scientists was awarded the Nobel Prize in 1911 for the discovery of the radioactive elements, radium and polonium?\n A) Charles Darwin\n B) Dmitri Mendeleev\n C) Marie Curie";
questionbank[0].answer = "C";
questionbank[1] = new ChemistryJFrame();
questionbank[1].question = "How many electrons can occupy an s orbital?\n A) one\n B) two\n C) three";
questionbank[1].answer = "B";
questionbank[2] = new ChemistryJFrame();
questionbank[2].question = "Which noble gas has the highest melting point ?\n A) argon\n B) xenon\n C) radon";
questionbank[2].answer = "C";
}
public void startquiz()
{
for(quest=1; quest<10; quest++)
{
questionlabel.setText(questionbank[quest].question);
}
}
// Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JButton jButton2;
private javax.swing.JSeparator jSeparator1;
private javax.swing.JTextField jTextField1;
private javax.swing.JLabel questionlabel;
// End of variables declaration
}

Your start quiz function seems totally wrong to me.
At the moment you are seeing nothing because the quiz start function is very rapidly setting the text to every question - finally ending at question 9 which is blank as you never set it in the banklist function.
I would imagine that you intend to set the text to the qustion[0] text and then wait for some kind of user response?

public void startquiz()
{
for(quest=1; quest<10; quest++)
{
questionlabel.setText(questionbank[quest].question);
}
}
Lots of issues:
You are iterating from 1 to 10, but you only define questionbank as an array of 3 items. ArrayIndexOutOfBounds is being thrown.
Even if the above is solved, you just iterate all questions before the data is even displayed. You would only get to see the last one. Learn to program with listeners, this is how GUIs work (not sequentially as command line programs).
You also have what seems to be an actionListener method for a button that does not exist, clean your code.

You never actually create questionlabel. You need to create it first and then add it to the frame.
Also in this piece of code:
for(quest=1; quest<10; quest++)
{
questionlabel.setText(questionbank[quest].question);
}
You'll be overwriting label text 10 times and only the last question will be shown. What you probably need is ten different labels.
Another thing is that you create only 3 questions, but iterate over 10. Arrays in Java start with zero so you need to change for(quest=1 to for (quest=0
Those are not all of the problems with your code, but keep trying, you'll get there eventually :)

Related

Java proper use of ArrayList

I am currently working on a small project, where a Jframe has a Jlist, which displays an arraylist of files, which have been gathered by scanning through a directory.
The whole process works like this, a seperate class, calls a method in the Jframe class called "main". This "main" method scans through a directory(folderAndFiles) and lists all the file names into a regular text file(file.txt). Aftwerwards the seperate class then displays the Jframe, which then has another scanner, which reads the new text file(file.txt) and turns all the names within that file into an arraylist(filList). Within the initialization function of the Jframe, I am then setting a DefaultListModel to add the arraylist items to the Jlist.
Everything sort of works, but there are some slight hiccups. The first thing is the fact that the Jlist displays the things from the arraylist horizontaly meaning it will be like this [File1.txt, File2.txt, File3.txt, etc...] and not vertically, where the filenames are displayed underneath each other. Then the second issue, which probably would be fixed if the first issue is fixed, the array list is too long and on the Jlist after listing some of the files it ends up saying "line is to long, please switch to wrapped mode to see whole line..."
I am not completely sure whether I am using the arraylist right and why it won't list the items within the Jlist vertically and properly.
The following is the whole Jframe, where the Jlist is placed and the function is happening.
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Scanner;
import javax.swing.DefaultListModel;
public class DisplayTest extends javax.swing.JFrame {
static String username = System.getProperty("user.name");
static File file = new File("file.txt");
static ArrayList<String> filList = new ArrayList<String>();
public DisplayTest(){
initComponents();
DefaultListModel DLM = new DefaultListModel();
DLM.addElement(filList);
jList1.setModel(DLM);
System.out.println(filList);
}
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new DisplayTest().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JLabel jLabel1;
private javax.swing.JList<String> jList1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JTextArea jTextArea1;
// End of variables declaration
public static void main() throws IOException {
try {
listFilesForFolderMac(folderAndFiles);
} finally {
Scanner scanner = new Scanner(file);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
filList.add(line);
}
}
public static void listFilesForFolderMac(final File folder) throws IOException {
PrintWriter writToDoc = new PrintWriter(new FileWriter("file.txt",true));
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
listFilesForFolderMac(fileEntry);
} else {
writToDoc.println(fileEntry.getName());
}
}
writToDoc.close();
}
final static File folderAndFiles = new File("/Users/" + username + "/Documents");
}
The following is how I call the Jframe and function, from the seperate class
public static void main(String[] args) throws IOException {
try {
DisplayTest.main();
} finally {
DisplayTest dTest = new DisplayTest();
dTest.setVisible(true);
}
}
I am not completely sure whether I am using the arraylist right
A JList doesn't know how to display the items in an ArrayList, so you can't just add the ArrayList to the ListModel.
So you need to iterate through the ArrayList and add each item to the ListModel.
Or even easier, just get rid of the ArrayList and read the data from the file directly into the ListModel.
Your code is poorly structured. Any time you see an overuse of static variables and methods you know you have a design problem.
I would start by reading the section from the Swing tutorial on How to Use Lists. There are working examples there that will show you a better program structure. You can start with working code and modify it for your requirements.

Object has null values when subclass attempts to use it. Why?

I'm a newbie Java guy so I'm probably doing this entire thing completely wrong. I have to do this giant project for software engineering class. The code is about 2,000 lines long so this is skeleton code
public class BookRental extends JFrame{
public Client currentClient = new Client(); // creating client object
//rest of declared variables.
public class Client{ //Client class containing all get/set methods for each variable
private username;
private void setUsername(String u){
username = u;
}
public String getUsername(){
return username;
}
public class LoginPanel extends JPanel{} //Panel to show and receive login info.
public class RegisterPanel extends JPanel{} //Panel to register.
public class MenuPanel extends JPanel{ //Panel showing main menu.
//At this point currentClient will contain values
public ClientInfoPanel(){
initComponents();
}
private void initComponents(){
infoPanelUserName = new JLabel();
infoPanelFullName.setText("Currently logged in as: " + currentClient.getUsername());
}
private JLabel infoPanelUserName;
}
public class ClientInfoPanel extends JPanel{} //Panel to print currentClient info to screen using JLabel objects
private void ViewClientInfoButtonActionPerformed(event){ // Using button in Menu Panel to setVisibility of clientInfoPanel to (true)
//At this point there will be a value for currentClient
clientInfoPanel = new ClientInfoPanel();
this.add(clientInfoPanel);
menuPanel.setVisible(false);
clientInfoPanel.setVisible(true);
}
public BookRental(){initComponents();} //Constructor
private void initComponents(){} // Creates all panels and sets visibility off, besides login
public static void main(String args[]){
new BookRental().setVisible(true);
}
}
I already am pretty sure I am doing this COMPLETELY wrong, however my question is why can't I access currentClient inside of ClientInfoPanel? Say for this JLabel:
infoPanelUserName.setText("Currently logged in as: " + currentClient.getUsername());
The ClientInfoPanel recognizes currentClient exists and that the getUsername() method exists, however it prints:
"Currently logged in as: "
The code you showed looks fine, so the problem is somewhere else, or this code is not representative of what you have. Also, you ARE accessing currentClient successfully, unless you're getting a NullPointerException or catching it somewhere, then the .getUsername() call IS resolving. So the problem is actually with .getUsername(), somehow username is uninitialized when you call .getUsername();
As a test, can you call .setUsername() on currentClient right before you call .getUsername()? That should help us narrow down the problem, isolate it to either the class access or the variable being initialized.
Also, do you know how to debug with breakpoints? You mentioned you're new, so you might not know this is possible. If you're using Eclipse (or another good IDE) you can set breakpoints and run the program in DEBUG build, then the program will freeze when it hits the line you set a breakpoint on, and you can watch as the program moves line by line, and see the variables as they are updated by the program. Google java debug tutorial. :)
I agree (not sure whether I should add since someone else already answered, what is the etiquette?). I ran this fine and it showed me a panel with the user logged in as Me as set in the BookRental constructor:
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class BookRental extends JFrame{
public Client currentClient = new Client(); // creating client object
//rest of declared variables.
public class Client{ //Client class containing all get/set methods for each variable
private String username;
private void setUsername(String u){
username = u;
}
public String getUsername(){
return username;
}
}
public class ClientInfoPanel extends JPanel{ //Panel showing main menu.
//At this point currentClient will contain values
public ClientInfoPanel(){
initComponents();
}
private void initComponents(){
infoPanelUserName = new JLabel();
infoPanelUserName.setText("Currently logged in as: " + currentClient.getUsername());
this.add(infoPanelUserName);
}
private JLabel infoPanelUserName;
}
public ClientInfoPanel clientInfoPanel;
//Constructor
public BookRental(){
currentClient.setUsername("Me");
initComponents();
}
private void initComponents(){
clientInfoPanel = new ClientInfoPanel();
this.add(clientInfoPanel);
clientInfoPanel.setVisible(true);
}
public static void main(String args[]){
new BookRental().setVisible(true);
}
}

How do I use an object reference as an argument if it is instantiated after the class taking the argument?

So I have this code:
package com.erikbalen.game.rpg;
import com.erikbalen.platform.*;
import javax.swing.JFrame;
public class World extends Engine {
public static void main(String[] args) {
Gui display = new Gui(/*takes a Player argument so i can get certain variables*/);
display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
display.setSize(300,220);
display.setVisible(true);
Player player1 = new Dps("ebalen", display);
Player player2 = new Healer("frankypanky", display);
}
}
package com.erikbalen.game.rpg;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Gui extends JFrame implements ActionListener {
/**
*
*/
private static final long serialVersionUID = -384241835772507459L;
private JLabel playerInfo;
private JTextField textField;
private final static String newline = "\n";
private JTextArea feed;
private JScrollPane scrollPane;
private Player player;
public Gui(Player currentPlayer) {
super("Erik's RPG");
this.player = currentPlayer;
setLayout(new FlowLayout());
playerInfo = new JLabel("<html>Health = " + currentPlayer.getHealth() + " | " + "Mana = " + currentPlayer.getMana() + "</html>");
playerInfo.setBorder(BorderFactory.createTitledBorder(currentPlayer.getName()));
textField = new JTextField(20);
textField.addActionListener(this);
feed = new JTextArea(5, 20);
scrollPane = new JScrollPane(feed);
feed.setEditable(false);
add(playerInfo);
add(feed);
add(textField);
add(scrollPane);
}
public void actionPerformed(ActionEvent textBox) {
String text = textField.getText();
this.player.chat(text);
}
public void printText(String text) {
feed.append(text + "\n");
feed.setCaretPosition(feed.getDocument().getLength());
}
}
My problem is that class Gui takes a Player as an argument and Player takes Gui as an argument. How do I let both objects take each other as arguments? Feel free to tell me if my code is inefficient.
Well, ideally you should try to break the circular dependency, but otherwise, you could:
Create the GUI, create the players by passing in the GUI, then add the players to the GUI
Create the players, create the GUI by passing in the players, then set the GUI for the players
Create the GUI within the player constructor:
Player(String name)
{
GUI gui = new GUi(this);
...
}
All of these are non-ideal:
You may well want your classes to be immutable, which makes the first two options nasty
Publishing the this reference before your constructor has finished executing has various issues, both in terms of thread safety and the memory model, as well as potentially allowing the GUI constructor to call back to the Player object before it's fully initialized.
This goes back to "try to break the dependency" - but if that's really impossible, I would probably favour the first option, without knowing anything else. It makes sense to be able to add players to a game - it makes less sense to set the GUI for a player after the fact, IMO.
Your stuck in what we call a circular dependency. This is almost everytime the result of a bad design.
There are still solutions, but there are not really pretty. For an elegant way, you should rethink your design.
Does the GUI really need the player ? Maybe you could create a method to set the player later on. If it's not possible, you could also create a setter in the player. You won't be able to set both at construction time.
Try giving the Gui class methods for updating what is displayed to the user/users. Make the directing code (main() for example) responsible for updating the Gui with the right information as events happen.
Neither Gui nor Player should have to take each other as constructor arguments - Gui should only be responsible for displaying information it is told to, and Player should only be a logical representation of a game piece. Event-driven functionality should be reserved for the directing code.

Updating text in a JTextField

K, so unlike with my last question, I've been proactive about trying to deal with this problem a number of times, and it's still not working.
Basically I'm trying implement a JTextField. I've added the action listener to it and the getters and setters for the text are working, but text that I'm enter isn't showing up in the textfield. I tried setting the text color to black and that didn't help. Honestly, I'm not sure what the issue is.
K here's the code.
import acm.program.*;
import java.awt.event.*;
import javax.swing.*;
public class NameSurfer extends Program implements NameSurferConstants {
//Change back to program after this
/* Method: init() */
/**
* This method has the responsibility for reading in the data base
* and initializing the interactors at the bottom of the window.
*/
public void init() {
// You fill this in, along with any helper methods //
createUI();
addActionListeners();
}
/* Method: actionPerformed(e) */
/**
* This class is responsible for detecting when the buttons are
* clicked, so you will have to define a method to respond to
* button actions.
*/
public void actionPerformed(ActionEvent e) {
// You fill this in //
if(e.getSource() == nameField || e.getSource() == graphName) {
drawNameGraph(nameField.getText());
} else if(e.getSource() == clearGraph) {
clearNameGraph();
}
}
/* Method: createUI() */
/**
* This method sets up and adds the interactors at the bottom of the window*/
private void createUI() {
nameField = new JTextField(25);
nameField.setColumns(25);
nameField.addActionListener(this);
graphName = new JButton("Graph");
clearGraph = new JButton("Clear");
graph=new NameSurferGraph();
add(new JLabel("Name"), SOUTH);
add(nameField, SOUTH);
add(graphName, SOUTH);
add(clearGraph, SOUTH);
add(graph);
//println(db.fileEntries.size());
}
/* Method: drawNameGraph(str) */
/** Draws the graph of the name entered in nameField
* */
private void drawNameGraph(String str) {
//println(str);
NameSurferEntry entered = db.findEntry(str);
if(entered != null) {
//println("Graph: " + entered.toString());
graph.addEntry(entered);
nameField.setText("str");
} else {
graph.badEntry(str);
}
//nameField.setText("");
}
/* Method: clearNameGraph() */
private void clearNameGraph() {
graph.clear();
}
private NameSurferDataBase db = new NameSurferDataBase(NAMES_DATA_FILE);
/**TextField where the names get entered*/
private JTextField nameField;
/**button to graph name popularity*/
private JButton graphName;
/**Clears graph*/
private JButton clearGraph;
private NameSurferGraph graph;
}
Also I'm going to try to explain my question better using images. Sorry if this don't work on your OS. Their .tiffs but I'll try to run them through image conversion later on. For some reason, stackoverflow isn't letting me post the images in question, so I'm going to try to do some links to them instead through some other site. Sorry for the inconvenience.
When I run the code, this is displayed.
See the image for that here.
Basically so far it works as expected.
The problem arises
here.
The getters and setters are working, but I'ld like to have the JTextField updated when the user enters the text, as opposed to not displaying anything that I've got entered in it.
Are you trying to do this?!?
JTextField text = new JTextField();
text.setText("ttttttttttttexxxt");
Quoting from the the Java 6 API on JTextField:
public JTextField()
Constructs a new TextField. A default model is created, the initial string is null, and the number of columns is set to 0.
(Emphasis added.)
If you are using a default constructor, then if you have not called setColumns(int), your JTextField has a column limit of 0 (regardless of the text field's width) and therefore will refuse all input from the user. I am inferring you are having trouble entering text as a user when the program is running, rather than trouble setting the text within the program and causing it to display?
Either use a form of the constructor that has a column limit, or use setColumns to specify a nonzero maximum after construction.
If this doesn't solve the issue, please provide a code sample, especially where you are constructing and initializing your JTextField.
The text is always defaulted to black so there no need to play with anything except setText.
There are a number of things you could be asking here so.
To set the text on load simply use setText at the top of your code.
public TestFrame() {
initComponents();
jTextField1.setText("Hello I am text in a box");
}
You can also have it respond to an event in the following way. Example is a button click.
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
//Text Box changes from default
jTextField1.setText("The button was pushed!!");
}
Notice that it is all the same, I feel like you are making it a little more complicated than it actually is.
Use a normal TextField instead of a JTextfield. According to this post that was the issue. I'm not a specialist, but I have encountered the exact same problem, and it seems to be linked to the usage of the ACM library.

JPanel.addComponentListener does not work when the listener is a class variable

I have a public class which has the following method and instance variable:
public void setImagePanel(JPanel value) {
imagePanel = value;
if (imagePanel != null) {
//method 1 : works
imagePanel.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent evt) {
System.out.println("Here 1");
}
});
//method 2 : does not work
panelResizeListener = new ResizeListener();
imagePanel.addComponentListener(panelResizeListener);
//method 3 : works
//ResizeListener listener = new ResizeListener();
//imagePanel.addComponentListener(listener);
//method 4 : works
//imagePanel.addComponentListener(new ResizeListener());
//method 5 : does not work -- THIS IS THE DESIRED CODE I WANT TO USE
imagePanel.addComponentListener(panelResizeListener);
}
}
public class ResizeListener extends ComponentAdapter {
#Override
public void componentResized(ComponentEvent evt) {
System.out.println("RESIZE 3");
}
}
private ResizeListener panelResizeListener = new ResizeListener();
private static JPanel imagePanel;
Each of the methods above correspond the to code immediately below until the next //method comment. What i don't understand is why i can't use the class instance variable and add that to the JPanel as a component listener.
What happens in the cases above where i say that the method does not work is that i don't get the "RESIZE 3" log messages. In all cases where i list that it works, then i get the "RESIZE 3" messages.
The outer class is public with no other modification except that it implements an interface that i created (which has no methods or variables in common with the methods and variables listed above).
If anyone can help me i would greatly appreciate it. This problem makes no sense to me, the code should be identical.
Man camickr, you were right. Man this was a weird one to solve. There was something else wrong with my code. The order of the methods calls into my class resulted in me adding the listener then another method would end up removing the listener referenced by that variable so of course i would never get events. Thanks a lot for all the help ppl.
I think your problem is that you're declaring panelResizeListener after you're using it. That normally kills just about anything.

Categories