I am writing this gui in java and it works great, except I recently discovered a bug. Currently I access each of my screens through file menus and use the below method to switch back and forth between the panels I am looking at. I have also included the method which one of the file menu actionlisteners executes. For the sake of brevity I have not included the others, just know that they use the same types of commands in a very similar order.
The problem is that sometimes when clicking between the screens, elements of the previous panel will be still visible on the new panel. This new panel will usually be missing most or all of its elements as well. Another (and probably related) issue I am experiencing is that when I run the code half or more of the time I see my initial screen but after that when I click to a new screen nothing shows up at all. It is very confusing because I don't change anything with the code or even recompile between runs and it behaves differently. This second problem has only been occurring since I moved the add methods for the panels to the setCurrentPanel for simplicity's sake.
private void setCurrentPanel(JPanel current) {
System.out.println(oldCurrent.getName() + " " + current.getName());
if (oldCurrent.getName().equals(current.getName())) {
} else {
buildingPanel.setVisible(false);
securityPanel.setVisible(false);
adminUsersPanel.setVisible(false);
adminBuildingPanel.setVisible(false);
adminServerPanel.setVisible(false);
changePasswordPanel.setVisible(false);
serverSettingsPanel.setVisible(false);
addBuildingPanel.setVisible(false);
addUser.setVisible(false);
for (BuildingItem item : buildingMenuItem) {
item.panel.setVisible(false);
}
add(current);
current.setVisible(true);
revalidate();
repaint();
oldCurrent = current;
refreshCount = refreshCount + 1;
System.out.println("Refresh " + refreshCount);
}
}
private void setupAdminServerPanel() {
getServerSettingsFromSQL();
serverSettingsPanel = new JPanel(new GridBagLayout());
serverSettingsPanel.setName("Server Settings Panel");
GridBagConstraints gbr = new GridBagConstraints();
SpinnerModel minPasswordModel = new SpinnerNumberModel(Integer.parseInt(settingMinPassword), 5, 20, 1);
SpinnerModel minUsernameModel = new SpinnerNumberModel(Integer.parseInt(settingMinUsername), 5, 20, 1);
final JSpinner minPasswordSpinner = new JSpinner(minPasswordModel);
final JSpinner minUsernameSpinner = new JSpinner(minUsernameModel);
JButton lockdownButton = new JButton("Lockdown");
lockdownButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
lockdownMode();
}
});
JButton ApplyButton = new JButton("Apply");
ApplyButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
if (minPasswordSpinner.getValue() != Integer.parseInt(settingMinPassword) ||
(minUsernameSpinner.getValue() != Integer.parseInt(settingMinUsername))) {
writeSettingsToSQL((Integer) minPasswordSpinner.getValue(),
(Integer) minUsernameSpinner.getValue());
getServerSettingsFromSQL();
}
}
});
lockdownButton.setPreferredSize(new Dimension(50, 50));
minUsernameSpinner.setPreferredSize(new Dimension(150, 30));
minPasswordSpinner.setPreferredSize(new Dimension(150, 30));
gbr.gridy = 0;
gbr.gridx = 1;
gbr.gridwidth = 1;
gbr.ipady = 0;
gbr.insets = new Insets(10, 10, 10, 10);
serverSettingsPanel.add(lockdownButton, gbr);
gbr.gridy = 1;
gbr.gridx = 0;
serverSettingsPanel.add(new JLabel("Minimum Username Length"), gbr);
gbr.gridy = 2;
gbr.gridx = 0;
serverSettingsPanel.add(new JLabel("Minimum Password Length"), gbr);
gbr.gridy = 1;
gbr.gridx = 1;
gbr.gridwidth = 2;
serverSettingsPanel.add(minUsernameSpinner, gbr);
gbr.gridy = 2;
serverSettingsPanel.add(minPasswordSpinner, gbr);
gbr.gridy = 3;
gbr.gridx = 1;
gbr.gridwidth = 1;
serverSettingsPanel.add(ApplyButton, gbr);
setCurrentPanel(serverSettingsPanel);
}
If you need to see more of the code let me know. I really would appreciate any help I can get! Thanks
I am not allowed to comment, so maybe it is not a full answer:
You revalidate and repaint the panel, do you do it to the frame or panel, in which it is displayed?
As already suggested, Card Layout is a better way.
Related
//*****
I stripped down as much as I thought possible while still being pleasing to use. this is my beginner calulator project. it shows result as I type. I'm using multiple textFields to achieve this. I'm open to smarter ways. for now though I would like to lie in my bed as I've made it to learn.
On fresh start up no issues with parsing and the getting a result but after clear lets say I used addButton last it will automatically add the first new number to itself then give me the result as the new num1. if I set num1 to 0; add works but not multiplication because of zero... is .setText(" "); really deleting the values? is there a better way? I've read all I could find on textFields.
I will happily take direction to the correct reading material in lieu of a direct answer. textField numbered slightly out of order. My apologies order is top down - 3 -2 -1 -4 -5. 4 and 5 are to help me visualize the problem 3 shows the work, 2 the result and 1 is used for parsing num1 and setting the current result to num1 so I can chain the addition.
I've tried parsing at different locations setting num1 to 0 setting result to the remainder of result and num1 to be the new num2.. and a bunch of other silly attempts at similar solulutions. I know that my if(numberButtons[i]) { statement directly above the switch for + - * / where it sets num2=Double.parseDouble(textField4.getText()); is the main cause but it is also the only way I know to give constant results as I type in my numbers.
I,ve tried more thought-out and many more arbitrary changes to my code trying to understand what's really going on and what's possible.
Afer 3 weeks I am embarrassed for myself. Thank you for your time. Again even just the right direction will help me very much. I do like and desire to solve the problem on my own. I am just truly out of my depth as I am 3 months into this a few hours a day in my time off of work. I truly enjoy it and would love to have a sense of closure and completion to this problem.
///*************
package test;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.border.SoftBevelBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Calc1 implements ActionListener {
JFrame frame;
JTextField textField3,textField2,textField1,textField4,textField5;
JButton[] numberButtons = new JButton[10];
JButton[] functionButtons = new JButton[6];
JButton addButton,subButton,multiButton,diviButton,decimalButton;
JButton equalButton,deleteButton,clearButton,negativeButton;
JPanel panel;
JLabel label;
Font myFont = new Font("Monospaced", Font.BOLD,31);
Font font1 = new Font("Monospaced", Font.BOLD, 30);
Font font2 = new Font("Monospaced", Font.BOLD, 28);
Font font3 = new Font("SansSerif", Font.BOLD, 48);
Font font4 = new Font("Monospaced", Font.BOLD, 65);
double num1=0,num2=0,result=0;
char operator;
Calc1(){
Border border1 = new LineBorder(Color.DARK_GRAY, 4, true);
frame = new JFrame("Calculator");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
frame.setOpacity(1);
frame.setVisible(true);
frame.setBounds(201, 60, 323, 700);
label = new JLabel();
label.setBounds(5, 4, 300, 52);
label.setFont(font1);
label.setVisible(true);
label.setText("Calculator");
label.setForeground(Color.blue);
label.setFont(new Font("Console", 1, 17));
label.setBorder(new SoftBevelBorder(BevelBorder.LOWERED));
Border border = new LineBorder(Color.LIGHT_GRAY, 7, true);
textField3 = new JTextField();
textField3.setBounds(5,54, 299, 38);
textField3.setFont(font2);
textField3.setBackground(Color.lightGray);
textField3.setBorder(border);
textField3.setOpaque(true);
textField3.setHorizontalAlignment(JTextField.RIGHT);
textField3.setFocusable(true);
textField2 = new JTextField();
textField2.setBounds(5, 89, 299, 44);
textField2.setFont(myFont);
textField2.setBackground(Color.lightGray);
textField2.setBorder(border);
textField2.setVisible(true);
textField2.setOpaque(true);
textField2.setHorizontalAlignment(JTextField.RIGHT);
textField2.setFocusable(false);
textField1 = new JTextField();
textField1.setBounds(5,510, 300, 35);
textField1.setFont(myFont);
textField1.setVisible(true);
textField4 = new JTextField();
textField4.setBounds(5,549, 300, 35);
textField4.setFont(myFont);
textField4.setVisible(true);
textField5 = new JTextField();
textField5.setBounds(5,580, 300, 35);
textField5.setFont(myFont);
textField5.setVisible(true);
addButton = new JButton("+");
subButton = new JButton("-");
multiButton = new JButton("x");
diviButton = new JButton("÷");
decimalButton = new JButton(".");
equalButton = new JButton("=");
deleteButton = new JButton("←");
clearButton = new JButton("AC");
functionButtons[0] = addButton;
functionButtons[1] = subButton;
functionButtons[2] = multiButton;
functionButtons[3] = diviButton;
functionButtons[4] = decimalButton;
functionButtons[5] = clearButton;
for(int i=0; i<6; i++) {
functionButtons[i].addActionListener(this);
functionButtons[i].setFont(myFont);
functionButtons[i].setFocusable(false);
functionButtons[i].setBorder(new SoftBevelBorder(BevelBorder.RAISED));
}
for(int i=0; i<10; i++) {
numberButtons[i] = new JButton(String.valueOf(i));
numberButtons[i].addActionListener(this);
numberButtons[i].setFont(font2);
numberButtons[i].setFocusable(false);
}
panel = new JPanel();
panel.setLayout(new GridLayout(4,4,4,4));
panel.add(label);
panel.setBackground(Color.DARK_GRAY);
panel.setForeground(Color.BLACK);
panel.setVisible(true);
panel.setOpaque(true);
panel.setBorder(border1);
panel.setBounds(4, 133, 300, 300);
panel.add(numberButtons[7]);
panel.add(numberButtons[8]);
panel.add(numberButtons[9]);
panel.add(addButton);
panel.add(numberButtons[4]);
panel.add(numberButtons[5]);
panel.add(numberButtons[6]);
panel.add(subButton);
panel.add(numberButtons[1]);
panel.add(numberButtons[2]);
panel.add(numberButtons[3]);
panel.add(multiButton);
panel.add(decimalButton);
panel.add(numberButtons[0]);
panel.add(clearButton);
panel.add(diviButton);
frame.add(panel);
frame.add(label);
frame.add(textField3);
frame.add(textField2);
frame.add(textField1);
frame.add(textField4);
frame.add(textField5);
frame.setOpacity(1);
frame.setForeground(Color.BLACK);
frame.setBackground(Color.BLACK);
frame.setVisible(true);
label.setForeground(Color.blue);
label.setBackground(Color.GRAY);
label.setOpaque(true);
}
public static void main(String[] args) {
Calc1 calc = new Calc1();
}
public void actionPerformed(ActionEvent e) {
for(int i=0; i<10; i++) {
if(e.getSource() == numberButtons[i]) {
textField1.setText(textField1.getText().concat(String.valueOf((i))));
textField3.setText(textField3.getText().concat(String.valueOf((i))));
textField4.setText(textField4.getText().concat(String.valueOf((i))));
textField5.setText(textField5.getText().concat(String.valueOf((i))));
}
}
if (e.getSource()==subButton) {
num1=Double.parseDouble(textField1.getText());
operator='-';
textField3.setText(textField3.getText().concat("-"));
textField4.setText("");
textField4.setText(textField4.getText().concat(""));
}
if (e.getSource()==addButton) {
num1 = Double.parseDouble(textField1.getText());
operator = '+';
textField3.setText(textField3.getText().concat("+"));
textField4.setText("");
textField4.setText(textField4.getText().concat(""));
}
if (e.getSource()==multiButton) {
num1 = Double.parseDouble(textField1.getText());
operator = '*';
textField3.setText(textField3.getText().concat("x"));
textField4.setText("");
textField4.setText(textField4.getText().concat(""));
}
if (e.getSource()==diviButton) {
num1 = Double.parseDouble(textField1.getText());
operator = '/';
textField3.setText(textField3.getText().concat("÷"));
textField4.setText("");
textField4.setText(textField4.getText().concat(""));
}
for(int i=0; i<10; i++) {
if(e.getSource()==numberButtons[i]) {
num2=Double.parseDouble(textField4.getText());
switch(operator) {
case'-':
result=num1-num2;
textField1.setText(String.valueOf(result));
textField5.setText(String.valueOf(num1));
break;
case'+':
result=num1+num2;
textField1.setText(String.valueOf(result));
textField5.setText(String.valueOf(num1));
break;
case'*':
result=num1*num2;
textField1.setText(String.valueOf(result));
textField5.setText(String.valueOf(num1));
break;
case'/':
result=num1/num2;
textField1.setText(String.valueOf(result));
textField5.setText(String.valueOf(num1));
break;
}
}
textField2.setText(String.valueOf((result)));
}
if (e.getSource()==clearButton) {
textField3.setText("");
textField2.setText("");
textField1.setText("");
textField4.setText("");
textField5.setText("");
}
}
}
Where you clear all your JTextFields, You should also reset all member variables used in previous calculations. After all, beacause of their scope (class global), they will still be holding values unless reset:
if (e.getSource() == clearButton) {
textField3.setText("");
textField2.setText("");
textField1.setText("");
textField4.setText("");
textField5.setText("");
num1 = 0;
num2 = 0;
result = 0;
operator = '\0';
}
I want to make ToDoList App. After successfully adding task to do (which contains checkbox, JLabel and date, all putted in a box) i want to remove them dynamically. With adding it's not problem but when i try to remove (ater clicking checked in checkbox) it works only once. Then it either removes not once which are intended or not removing them at all. I am not sure why it's not working so I paste all code below.
JSpinner dateSpin;
Box eventBox, boxBox;
Box[] taskBox = new Box[1000];
JTextField eventName;
Date date;
Checkbox[] doneCheck = new Checkbox[1000];
JLabel taskLabel;
JPanel panel;
JScrollPane scrollPane;
SimpleDateFormat simpleDate;
int i = 0;
public static void main(String[] args) {
new Main();
}
private Main(){
this.setSize(400, 600);
this.setTitle("To-Do List");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.setLocationRelativeTo(null);
panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
boxBox = Box.createVerticalBox();
scrollPane = new JScrollPane(panel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
eventBox = Box.createHorizontalBox();
eventBox.setBorder(BorderFactory.createEtchedBorder());
JLabel plusSign = new JLabel("+");
plusSign.setFont(new Font("Serafi", PLAIN, 20));
plusSign.setMaximumSize(new Dimension(Integer.MAX_VALUE, plusSign.getMinimumSize().height));
eventBox.add(plusSign);
eventName = new JTextField(20);
eventName.setFont(new Font("Times", Font.ITALIC, 15));
eventName.setMaximumSize(new Dimension(Integer.MAX_VALUE, eventName.getMinimumSize().height));
eventName.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == eventName){
/* to do: saving every task in some file, figure out how to remove
those tasks (checkbox + jlabel) -> whole box from screen or how to send them to "done"
also "done" to do*/
simpleDate = new SimpleDateFormat("E-dd-MM-yyyy");
taskBox[i] = Box.createHorizontalBox();
taskBox[i].setBorder(BorderFactory.createTitledBorder(simpleDate.format(date)));
doneCheck[i] = new Checkbox();
doneCheck[i].addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
int k = 0;
for (int j = 0; j < doneCheck.length; j++) {
if(doneCheck[j].getState()){
//remove(doneCheck[k]);
//System.out.println("?" + i + "?" + k + " " + e.getSource().toString());
System.out.println("xxxxx" + doneCheck[j].getState());
break;
}
System.out.println("oooooo");
k++;
}
System.out.println(doneCheck.length + taskBox[k].toString());
//System.out.println("! " + k + " " + e.getSource().toString());
boxBox.remove(taskBox[k]);
//boxBox.removeAll();
boxBox.revalidate();
boxBox.repaint();
}
});
taskBox[i].add(doneCheck[i]);
String taskName = eventName.getText();
taskLabel = new JLabel(taskName);
taskLabel.setMinimumSize(new Dimension(500,10));
taskLabel.setPreferredSize(new Dimension(300, 10));
taskBox[i].add(taskLabel);
boxBox.add(taskBox[i]);
boxBox.setMaximumSize(new Dimension(Integer.MAX_VALUE, boxBox.getMinimumSize().height + 11));
panel.add(boxBox);
panel.revalidate();
panel.repaint();
i++;
}
}
});
eventBox.add(eventName);
date = new Date();
dateSpin = new JSpinner(new SpinnerDateModel(date, null, null, Calendar.DAY_OF_MONTH));
JSpinner.DateEditor dateEditor = new JSpinner.DateEditor(dateSpin, "dd/MM/yy");
dateSpin.setEditor(dateEditor);
dateSpin.setMaximumSize(new Dimension(Integer.MAX_VALUE, dateSpin.getMinimumSize().height));
dateSpin.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
if(e.getSource() == dateSpin){
date = (Date) dateSpin.getValue();
}
}
});
eventBox.add(dateSpin);
panel.add(eventBox, new FlowLayout());
this.add(scrollPane);
this.setVisible(true);
}
You never remove elements from the taskBox and doneCheck arrays.
Now if you mark the first entry as done, your ItemListener will always find this first entry when looping over the doneCheck array.
Marking the entries as done in reverse order (always the last shown entry) will remove one entry after the other.
As to your software design: it's considered bad practice to manage your data in several parallel arrays.
Please consider creating a custom class for the todo items that manages all the elements of a single todo item.
Unless you are initializing doneCheck items somewhere, this:
Checkbox[] doneCheck = new Checkbox[1000];
And this:
int k = 0;
for (int j = 0; j < doneCheck.length; j++) {
if (doneCheck[j].getState()) {
--------^^^^^^^^^^^^
Is probably one the reason it fails: you probably got a NullPointerException somewhere, eg: when value of j > 0. The NPE will probably be catched by the EventDispatchThread which may or may not be kind enough to show it on stderr...
I fail to see why you are using this array, and you can shorten your code and avoid NPE like this:
Checkbox cb = new Checkbox();
cb.addItemListener(event -> {
if (cb.getState()) { // not null!
boxBox.remove(cb);
boxBox.revalidate();
boxBox.repaint();
}
});
doneCheck[i] = cb; // I still don't know why you need that.
My guess is that you have 2 variables global int i = 0 and local int k = 0 in here
public void itemStateChanged(ItemEvent e) {
// int k = 0;//<-------- LOCAL
for (int j = 0; j < doneCheck.length; j++) {
if(doneCheck[j].getState()){
//Either k = j;
boxBox.remove(taskBox[j]);
//remove(doneCheck[k]);
//System.out.println("?" + i + "?" + k + " " + e.getSource().toString());
System.out.println("xxxxx" + doneCheck[j].getState());
break;
}
System.out.println("oooooo");
//k++;//<-- ALWAYS == last j value before the break;
}
System.out.println(doneCheck.length + taskBox[k].toString());
//System.out.println("! " + k + " " + e.getSource().toString());
//boxBox.remove(taskBox[k]);//
//boxBox.removeAll();
boxBox.revalidate();
boxBox.repaint();
}
Every time you call for itemStateChanged int k = 0; will be initialized to 0 and you will be removing element[j] from array of taskBox. As you k++ statement will be equal to the last j value before the break; because it sits after the if(doneCheck[j].getState()){...
Try moving boxBox.remove(taskBox[j]); inside the for loop and using j instead of k.
I'm a beginner programmer, and it's my first time trying out JFrames and stuff, so feel free to criticize any violations to good programming practices. I've tried many things but none have really worked so I'm stuck.
I'm trying to make 2 pop-up windows with JFrame, one which ask for button press and then opens another one which "simulates" labels (in this case just a string of text) moving systematically. I've put it in a loop and hoped it would update the text each time, simulating it moving on the window.
But the issue is it's just showing a blank screen for the duration of the loop, and only when it's complete it shows the text on the window. How can I fix it to print the text everytime on the window, not just at the end? I've put a 200 ms delay so I could spot the text moving but it's no use if it isn't even printing the text.
Here is my code:
public class PopUpWindow {
JButton button1, button2;
JLabel text1, text2;
JFrame window1, window2;
public PopUpWindow() {
this.window1 = new JFrame("Input");
this.window1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.window1.setLayout(null);
this.window2 = new JFrame("Simulation");
this.window2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.window2.setLayout(null);
}
public void createWindow1() {
this.button1 = new JButton("Start");
this.button2 = new JButton("Quit");
this.button1.setBounds(50, 50, 100, 30);
this.button2.setBounds(180, 50, 100, 30);
this.window1.add(button1);
this.window1.add(button2);
this.window1.setSize(350, 200);
this.window1.setVisible(true);
this.window1.setResizable(true);
this.window1.setLocationRelativeTo(null);
analyzeInput();
}
public void analyzeInput() {
this.button1.addActionListener((ActionEvent e) -> {
createWindow2();
});
this.button2.addActionListener((ActionEvent e) -> {
int question = JOptionPane.showConfirmDialog(this.window1, "Exit program?");
if (question == JOptionPane.YES_OPTION) {
this.window1.dispose();
}
});
}
public void createWindow2() {
this.button1 = new JButton("Button 1");
this.button2 = new JButton("Button 2");
this.text1 = new JLabel("x");
this.text2 = new JLabel("x");
int x = 80;
int y = 0;
for (int i = 0; i < 10; i++) {
this.button1.setBounds(50, 120, 100, 30);
this.button2.setBounds(180, 120, 100, 30);
this.text1.setBounds(x, y, 100, 100);
this.text2.setBounds(x, (y + 30), 100, 100);
this.window2.add(text1);
this.window2.add(text2);
this.window2.setSize(350, 250);
this.window2.setResizable(true);
this.window2.setVisible(true);
this.window2.setLocationRelativeTo(null);
x += 5;
y += 10;
try {
Thread.sleep(200);
} catch (InterruptedException ex) {
Logger.getLogger(PopUpWindow.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
EDIT:
well, let's ignore the for-loop for now. What I mainly wanted to know was why the JFrame window will not update or change despite me changing its content. For example, here is an edited version of createWindow2() -method, which does not have a for-loop and instead reacts to another button.
public void createWindow2() {
this.window2.setSize(500, 500);
this.window2.setVisible(true);
this.window2.setResizable(true);
this.window2.setLocationRelativeTo(null);
this.text1 = new JLabel("xfdfgdf");
this.text2 = new JLabel("xdfgdfgd");
this.button3 = new JButton("dfsadfas");
this.button3.setBounds(50, 50, 100, 30);
this.window2.add(this.button3);
this.button3.addActionListener((ActionEvent e) -> {
this.text1.setBounds(200, 200, 100, 100);
this.text2.setBounds(200, 230, 100, 100);
this.window2.add(text1);
this.window2.add(text2);
});
}
When I run the program, I only see a blank window, even though I press the button. Only when I rezise the window manually will the text appear in the correct coordinates. Is it supposed to work like that? Is there a way to make it update on every button press on its own? (I haven't done anything with Layouts or stuff so I don't know how that works.)
I'm having some issues on using a conditionally assigned value in more than one class. I want to apply the use of a value in one class if and only if a condition is met, then use it in some-other class to add up to a total score. this is my code!
#SuppressWarnings("serial")
public class Beginner extends JPanel {
static JButton quest;
Random rand = new Random();
int n = 10;
static List <Point> points = new ArrayList<Point> ();
int scores;
int fails;
public Beginner() {
int radius = 200;
Point center = new Point (250, 250);
double angle = Math.toRadians(360 / n);
points.add(center);
for (int i = 0; i < n; i++) {
double theta = i * angle;
int dx = (int) (radius * Math.sin(theta));
int dy = (int) (radius * Math.cos(theta));
Point p = new Point (center.x + dx , center.y + dy);
points.add(p);
}
draw (points);
}
public void draw (List<Point> points) {
JPanel panels = new JPanel();
SpringLayout spring = new SpringLayout();
int count = 1;
for (Point point: points) {
quest = new JButton("Question " + count);
quest.setForeground(Color.BLACK);
Font fonte = new Font("Script MT Bold", Font.PLAIN, 20);
quest.setFont(fonte);
add (quest);
count++;
spring.putConstraint(SpringLayout.WEST, quest, point.x, SpringLayout.WEST, panels );
spring.putConstraint(SpringLayout.NORTH, quest, point.y, SpringLayout.NORTH, panels );
setLayout(spring);
panels.setOpaque(false);
panels.setVisible(true);
panels.setLocation(5,5);
add(panels);
quest.addActionListener(new java.awt.event.ActionListener(){
#Override
public void actionPerformed (ActionEvent p) {
if (point.equals(points.get(0))) {
new Quest1();
JButton source = (JButton) p.getSource();
source.setEnabled(false);
source.setBackground(Color.GREEN);
}
else if (point.equals(points.get(1))) {
new Quest2();
JButton source = (JButton) p.getSource();
source.setEnabled(false);
source.setBackground(Color.GREEN);
}
else if (point.equals(points.get(2))) {
new Quest3();
JButton source = (JButton) p.getSource();
source.setEnabled(false);
source.setBackground(Color.GREEN);
}
else if (point.equals(points.get(3))) {
new Quest4();
JButton source = (JButton) p.getSource();
source.setEnabled(false);
source.setBackground(Color.GREEN);
}
else if (point.equals(points.get(4))) {
new Quest5();
JButton source = (JButton) p.getSource();
source.setEnabled(false);
source.setBackground(Color.GREEN);
}
Now, this is what my first called-up class (named Quest1) looks like
public class Quest1 {
//sound files to be shuffled and played!
String [] word = { "C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/audio.wav",
"C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/bomb.wav",
"C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/baby.wav",
"C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/gym.wav",
"C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/hearing.wav",
"C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/goal.wav",
"C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/manifest.wav",
"C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/mountain.wav",
"C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/market.wav",
"C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/debate.wav",
"C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/election.wav",
"C:/Users/HP/Workspace/spellingApp/src/Level1/Question 1/number.wav",
};
//matching strings for each file
String [] words = { "Audio", "Bomb", "Baby", "Gym", "Hearing", "Goal", "Manifest","Mountain", "Market", "Debate", "Election", "Number" };
Random rand = new Random();
int random = rand.nextInt(word.length);
String temp = word[random];
int scores;
int fails;
public Quest1 () {
//announcing the JComponents to be used
JFrame frame = new JFrame ();
JButton click = new JButton("Play");
JTextField type = new JTextField(15);
JLabel pic = new JLabel(new ImageIcon("C:\\Users\\HP\\Desktop\\Sample pics\\1.png"));
JButton score = new JButton ("Check My Answer");
JPanel cont = new JPanel ();
//set up frame properties
frame.getContentPane().setBackground(Color.WHITE);
frame.setLayout(new FlowLayout());
frame.setUndecorated(true);
frame.setResizable(false);
frame.setSize(500,500);
frame.setLocationRelativeTo(null);
frame.add(cont, BorderLayout.CENTER);
frame.getRootPane().setWindowDecorationStyle(JRootPane.NONE);
frame.setVisible(true);
//setting layout of JPanel
cont.setLayout(new GridBagLayout());
cont.setOpaque(false);
cont.setPreferredSize(new Dimension(500,500));
cont.setLocation(100, 50);
GridBagConstraints g = new GridBagConstraints();
g.anchor = GridBagConstraints.WEST;
g.gridx = 4;
g.gridy = 2;
g.gridwidth = 2;
g.insets = new Insets (70, 2, 2, 2);
cont.add(pic , g);
g.anchor = GridBagConstraints.WEST;
g.gridx = 4;
g.gridy = 5;
g.gridwidth = 2;
g.insets = new Insets (50, 2, 2, 2);
cont.add(click, g);
click.addActionListener(new ActionListener(){
public void actionPerformed (ActionEvent e) {
//sound file shuffled and played
}
});
g.anchor = GridBagConstraints.EAST;
g.gridx = 10;
g.gridy = 4;
g.gridwidth = 5;
g.insets = new Insets(30, 2, 2, 10);
Font fonty = new Font("Lucida", Font.PLAIN, 15);
type.setFont(fonty);
cont.add(type, g);
g.anchor = GridBagConstraints.SOUTH;
g.gridx = 9;
g.gridy = 8;
g.gridwidth = 2;
g.insets = new Insets(2, 2, 2, 50);
cont.add(score, g);
score.addActionListener(new ActionListener(){
public void actionPerformed (ActionEvent tx) {
if (type.getText().equals(words[random])) {
//sound file played
scores+= 3;
String a = "Correct!..... The answer is " + words[random];
JOptionPane.showMessageDialog(null, a);
frame.dispose();
return;
}
else {
//sound file played again
fails+=0;
// This is where my problem is: The other 10 classes are like
//this, I want to get this value and that of scores (depending on the
//condition that is met), and add them up in the class beginner! )
String a = "Sorry, The Answer is " + words[random];
JOptionPane.showMessageDialog(null, a);
frame.dispose();
}
}
});
//sound file played
}
}
Your score and fail are local variables within the listener event. If you create an instance variable in your help class you can update them within the listener but they will persist as long as your program is running and then can be passed into more classes as constructor parameter for whatever purpose you may need.
public class help extends JFrame {
JPanel hold = new JPanel ();
JTextField enter = new JTextField(10);
JButton check = new JButton ("Check answer");
JButton quest = new JButton ("See question");
JLabel lunch = new JLabel ("Who is the current President of the United States?");
//Add fields you want to track here
int scores;
int fails;
public help () {
Then inside your listeners
scores += 3; //track them anyway you want
Update:
So it looks like you want to pass the score/fails from your Quest class back to your original class. You can do this by adding some accessor methods for scores and fails to your Quest class.
public int getScores(){
return scores;
}
public int getFails(){
return fails;
}
This will allow you get retrieve the values when you need them. You'd simply call them on the Quest object you made. However there's another problem...
new Quest1();
The quest needs to be stored in a variable like scores and fails or else it will get thrown away by the garbage collector. Add a variable that will hold the current Quest on top then swap them out when you switch quests.
Quest1 q1;
...
...
q1 = new Quest1();
...
...
scores = q1.getScores();
fails = q1.getFails();
Update: Button Flags
You can add flags to check if things have occurred by adding booleans variables. In this case you can have Quest1-5 flags in your Beginner class. When the user clicks on the class you can change it to true, then check if all of them have been done.
boolean Q1 = false;
boolean Q2 = false;
...
if (point.equals(points.get(0))) { // User clicks quest 1
Q1 = true;
...
...
if (checkQuests()){
//do stuff if all buttons are clicked
}
...
public boolean checkQuests(){ //cleaner if you use arrays
if(Q1 == false || Q2 == false || ... Q5== false){
return false;
}
else{
return true;
}
}
Update: Call back function
When working GUIs and listeners, not all actions happen in the sequence you want it to. GUIs and events happen on their own thread and often you want to trigger an event at the end of another. You can do this by utilize a call back function.
What is a callback function?
Here's how you can implement one in your program.
Inside your Quests include an interface and variable for an interface:
public class Quest{
CallBack cb;
interface CallBack{
public void callBack();
}
//add some way to set the call back, such as setter (or use constructor)
public void setCB(CallBack cb){ this.cb = cb;}
//Inside the action listener of your quest doing something
...
cb.callBack(); //call the callback method when you are done and want to do your check (it calls the beginner class back)
Inside your Beginner class:
//When creating a quest
Q1 = new Quest1();
Q1.setCB(new CallBack{
public void callBack(){
CheckQuests(); //this tells the program what to do when it hears back from Q1
}
}
What ends up happening is when the code of Q1 finishes, it calls the callBack() method (it could be any time but in your case call it when you're done with your logic).
The beginner class passes in code that tells Q1 what it should do when that method is called.
I was able to program this, and I don't have any errors that I can see, and it even displays the gui. I'm pretty sure I assigned the buttons properly. But the GUI is temperamental, and when I run it, it displays but sometimes the insides of the gui disappear when I enter values. But it calculates nCr, just not pCr.
I have a driver class. Pretty sure it's implemented properly. Here's my panel class. I'm wondering what's wrong and why the GUI doesn't function properly
I realize this is a lot of code. I'm not expecting anyone to rewrite this for me. I just want to know what I'm doing wrong, and how I can go about correcting it.
Thanks.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.Color;
import javax.swing.JOptionPane;
public class PermCombCalc extends JPanel {
JButton permButton = new JButton();
JButton combButton = new JButton();
JButton clearButton = new JButton();
JTextField npermField = new JTextField();
JTextField rperField = new JTextField();
JTextField nchooseField = new JTextField();
JTextField rchooseField = new JTextField();
JTextField pAnswerField = new JTextField();
JTextField cAnswerField = new JTextField();
public PermCombCalc() {
setLayout(new BorderLayout());
setPreferredSize(new Dimension(1000, 700));
JLabel permLabel = new JLabel("Permutation:");
permLabel.setBounds(10, 20, 100, 20);
permLabel.setForeground(Color.BLACK);
add(permLabel);
JLabel combLabel = new JLabel("Combination:");
combLabel.setBounds(215, 20, 75, 20);
combLabel.setForeground(Color.BLACK);
add(combLabel);
// Creating Permutation Button
JLabel PnrLabel = new JLabel("P (n,r)");
PnrLabel.setForeground(Color.black);
permButton.setBounds(10, 115, 100, 25);
add(permButton);
permButton.add(PnrLabel);
// Action Listener for permbutton
permButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
permButton.setActionCommand("Perm");
permButton.addActionListener(new ButtonListener());
}
});
// Creating combination button
JLabel CnrLabel = new JLabel("C(n, r)");
CnrLabel.setForeground(Color.black);
combButton.setBounds(190, 115, 100, 25);
add(combButton);
combButton.add(CnrLabel);
// ActionListener
combButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
combButton.setActionCommand("comb");
combButton.addActionListener(new ButtonListener());
}
});
// Text fields for n and r
npermField.setBounds(23, 50, 60, 20);
add(npermField);
nchooseField.setBounds(230, 50, 60, 20);
add(nchooseField);
rperField.setBounds(23, 80, 60, 20);
add(rperField);
rchooseField.setBounds(230, 80, 60, 20);
add(rchooseField);
// Input fields
JLabel npLabel = new JLabel("n:");
npLabel.setForeground(Color.black);
npLabel.setBounds(10, 55, 10, 10);
add(npLabel);
JLabel ncLabel = new JLabel("n:");
ncLabel.setForeground(Color.BLACK);
ncLabel.setBounds(217, 55, 10, 10);
add(ncLabel);
JLabel rpLabel = new JLabel("r:");
rpLabel.setForeground(Color.BLACK);
rpLabel.setBounds(10, 85, 10, 10);
add(rpLabel);
JLabel rcLabel = new JLabel("r:");
rcLabel.setForeground(Color.BLACK);
rcLabel.setBounds(217, 85, 10, 10);
add(rcLabel);
// Fields for answers
JLabel pAnswerJLabel = new JLabel("<-Answers->");
pAnswerJLabel.setForeground(Color.BLACK);
pAnswerJLabel.setBounds(115, 155, 74, 10);
add(pAnswerJLabel);
pAnswerField.setBounds(10, 150, 100, 20);
add(pAnswerField);
cAnswerField.setBounds(190, 150, 100, 20); // where is this field?!
add(cAnswerField);
// Buttons
//clearButton.setBounds(10, 210, 110, 25);
//add(clearButton);
//JLabel clearLabel = new JLabel("Clear Fields");
//clearLabel.setForeground(Color.BLACK);
//clearButton.add(clearLabel);
// clearButton.addActionListener(new ActionListener() {
// public void actionPerformed(ActionEvent e) {
// clearButton.setActionCommand("Clear");
}
private class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("perm")) {
// contentPane.setBackground(Color.red);
long Pnr = Permutation();
if (Pnr != 0) {
pAnswerField.setText(Pnr + "");
}
} else if (e.getActionCommand().equals("comb")) {
// contentPane.setBackground(Color.black);
long Cnr = Combination();
if (Cnr != 0) {
cAnswerField.setText(Cnr + "");
}
} else if (e.getActionCommand().equals("Clear")) {
// contentPane.setBackground(Color.lightGray);
npermField.setText(null);
rperField.setText(null);
pAnswerField.setText(null);
nchooseField.setText(null);
rchooseField.setText(null);
cAnswerField.setText(null);
}
}
public long Permutation() {
String npString = npermField.getText();
String rpString = rperField.getText();
int npint = 0;
int rpint = 0;
try {
npint = Integer.parseInt(npString);
rpint = Integer.parseInt(rpString);
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null,"ERROR! The values for 'n' and 'r' \n must be positive integers");
return 0;
}
if (npint <= 0 || rpint <= 0) {
JOptionPane.showMessageDialog(null,"ERROR! The values for 'n' and 'r' \n must be positive integers");
return 0;
}
if (npint < rpint) {
JOptionPane.showMessageDialog(null,"ERROR! The value of 'r' must be less than \n or equal to the value of 'n.'");
return 0;
}
long Pnr = 1;
int mult = npint;
int nmr = (npint - rpint);
while (mult > nmr) {
Pnr = Pnr * mult;
mult--;
}
return Pnr;
}
public long Combination() {
String ncString = nchooseField.getText();
String rcString = rchooseField.getText();
int ncint = 0;
int rcint = 0;
try {
ncint = Integer.parseInt(ncString);
rcint = Integer.parseInt(rcString);
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null,"ERROR! The values for 'n' and 'r' \n must be positive integers");
return 0;
}
if (ncint <= 0 || rcint <= 0) {
JOptionPane.showMessageDialog(null,"Error! The values for 'n' and 'r' \n must be positive integers");
return 0;
}
if (ncint < rcint) {
JOptionPane.showMessageDialog(null,"ERROR! The value of 'r' must be less than \n or equal to the value of 'n.'");
return 0;
}
long nfact = 1;
for (int i = 2; i <= ncint; i++) {
nfact = nfact * i;
}
long rfact = 1;
for (int i = 2; i <= rcint; i++) {
rfact = rfact * i;
}
long nmr = ncint - rcint;
int nmrfact = 1;
for (int i = 2; i <= nmr; i++) {
nmrfact = nmrfact * i;
}
long Cnr = (nfact / (rfact * nmrfact));
return Cnr;
}
}
}
You are using BorderLayout, but you aren't actually specifying the placements of your components, so they are being rendered in unexpected places.
Here is a screenshot of your application with an orange border around pAnswerField and a red border around cAnswerField
You should take a look at the A Visual Guide to Layout Managers for help on using the Layout Managers properly.
For your application, GridLayout is probably a resonable balance between complexity and layout flexibility
GridBagLayout or SpringLayout will give you the most flexibility, but they can be frustratingly complex to work with.
EDIT Another minor problem which is causing the permButton to misbehave.
In your button creation code you have:
permButton.setActionCommand("Perm");
In your action listener you have: if (e.getActionCommand().equals("perm"))
As written your ActionListener will never get invoked when permButton gets pressed... Either switch to equalsIgnoreCase or define a constant rather than using string literals.
I find adding colored borders to be very helpful when doing layout work. Here's a quick example of how to do this:
npermField.setBounds(23, 50, 60, 20);
add(npermField);
nchooseField.setBounds(230, 50, 60, 20);
// add a border to make the component easier to see during layout.
npermField.setBorder(BorderFactory.createLineBorder(Color.ORANGE));
add(nchooseField);
If you like your ButtonListener class the way it is (I don't; will comment about it after the main issue), you can simply reword the buttons' setup:
.
.
.
add(permButton);
permButton.add(PnrLabel);
// Action Listener for permbutton
permButton.setActionCommand("Perm");
permButton.addActionListener(new ButtonListener());
.
.
.
(and likewise for the other buttons).
See? There is no need to add an ActionListener more than once AND also no need to add an ActionListener in order to add the real ActionListener.
The way your application was:
it didn't work on the first button press (since only then the correct listener is set up);
after the first button press, each new press would add another listener, eventually producing unexpected results (I didn't analyzed it thoroughly, and frankly I will not).
About the ButtonListener
Roughly speaking, your class does:
if (typeA) {
doActionA();
} else if (typeB) {
doActionB();
} else if (typeC) {
doActionC();
}
You could simply create 3 separate ActionListeners, each doing just one thing (either doActionA(), or B or C), without ifs. Then set up each button with only the appropriate ActionListener. This way you could also remove the lines setActionCommand(type);, since they would become useless.