My JCheckBox program only displays one box. Why is that? - java

I am attempting to add another checkbox to this program but for some reason it will not display when I run the program. Only the check box for the blue pill displays. I have attempted to add a couple things or change the way the program is structured, but nothing I have done so far has helped.
Code Below:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class CMIS242WK4DonnersonAReply {
static JCheckBox red;
static JCheckBox blue;
static JButton button;
public CMIS242WK4DonnersonAReply() {
button = new JButton("submit"); // Creates submit button
widget
ButtonHandler listener = new ButtonHandler(); // Creates the handler for the button.
button.addActionListener((ActionListener) listener); // adds the handler to the button widget
JPanel content = new JPanel(); // "container"
content.setLayout(new BorderLayout());
content.add(button, BorderLayout.PAGE_END);// places submit button at the bottom of panel.
JLabel label = new JLabel("At last. Welcome, Neo. As you no doubt have guessed, I am Morpheus. This is your last chance. After this there is no turning back."); // Label in frame.
content.add(label, BorderLayout.NORTH);// places label at the top of the screen.
//Creating Check Boxes
JCheckBox red = new JCheckBox("You take the red pill, you stay in Wonderland and I show you how deep the rabbit hole goes.");
red.setBounds(100,100, 50,50);
content.add(red);
JCheckBox blue = new JCheckBox("You take the blue pill, the story ends, you wake up in your bed and believe whatever you want to believe. ");
blue.setBounds(100,100, 50,50);
content.add(blue);
//Adding Frame
JFrame window = new JFrame("Matrix Monologue"); // JFrame = Window
window.setContentPane(content);
window.setSize(750,200); // Length, Height
window.setLocation(200,200); // X/Y "OF THE ENTIRE FRAME" Not the contents
window.setVisible(true); // makes window visible
}
// Method handles what happens when button is pressed.
private static class ButtonHandler implements ActionListener{
public void actionPerformed1(ActionEvent e) {
// Checks if which pill was selected and responds to user depending on their action.
if (red.isSelected() == true) {
System.out.println("Follow me");
System.out.println();
}
if (blue.isSelected() == true) {
System.out.println("Very Well, You may go back to your world");
System.out.println();
}
else
System.out.println("You must make a choice for what pill you will take");
System.exit(0); //closes program
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
// Main/driver method that runs everything.
public static void main(String[] args) {
CMIS242WK4DonnersonAReply matrixMonologue= new CMIS242WK4DonnersonAReply();
}
}
Any pointers?

When you're stuck on a problem, it never hurts to go back and consult the documentation.
You'll find information like this:
A border layout lays out a container, arranging and resizing its
components to fit in five regions: north, south, east, west, and
center. Each region may contain no more than one component, and is
identified by a corresponding constant: NORTH, SOUTH, EAST, WEST, and
CENTER. When adding a component to a container with a border layout,
use one of these five constants...
When you add your button, you do this:
content.add(button, BorderLayout.PAGE_END);
But then, when it's time to add checkboxes, you do this:
content.add(red);
...
content.add(blue);
Are you seeing what's missing? My bet is that you only see the blue checkbox because you added it on top of (or simply displaced) the red checkbox. Remember, the doc says "Each region may contain no more than one component..."
Try specifying the region of your BorderLayout where you want to see each checkbox.
If you want them to appear in the same region, put them in a JPanel of their own and lay them out at NORTH and SOUTH or EAST and WEST and then add that checkbox panel to your content panel in the region you want them to appear.

I feel that you need some guidance with your Swing programming. I have rewritten your CMIS242WK4DonnersonAReply class. Code is below. But first some comments about the code in your question.
JCheckBox red = new JCheckBox("You take the red pill, you stay in Wonderland and I show you how deep the rabbit hole goes.");
You have created a local variable which is hiding the class member. Hence static JCheckBox red; remains null and consequently the following if statement will throw NullPointerException.
if (red.isSelected() == true) {
By the way, the == true is not necessary. The following is sufficient.
if (red.isSelected()) {
Now another point.
red.setBounds(100,100, 50,50);
Since you are using a layout manager, namely BorderLayout, method setBounds will be ignored. The layout manager determines where to place the component on the screen.
window.setContentPane(content);
By default, the content pane of JFrame is a JPanel with BorderLayout so no need to replace the default content pane.
private static class ButtonHandler implements ActionListener
No need to create a nested class. Simply make class CMIS242WK4DonnersonAReply implement the ActionListener interface.
System.out.println("Follow me");
I don't think it's a good idea to involve the console in a GUI application. I would use JOptionPane to display a message to the user.
static JCheckBox blue;
I think that JRadioButton is more appropriate than JCheckBox in your situation.
Here is my code.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
public class CMIS242WK4DonnersonAReply implements Runnable, ActionListener {
private JButton button;
private JRadioButton blue;
private JRadioButton red;
private JFrame window;
#Override
public void actionPerformed(ActionEvent event) {
if (red.isSelected()) {
JOptionPane.showMessageDialog(window, "Follow me.");
}
else if (blue.isSelected()) {
JOptionPane.showMessageDialog(window, "Very Well, You may go back to your world");
}
else {
JOptionPane.showMessageDialog(window, "You must make a choice for what pill you will take");
}
}
#Override
public void run() {
createAndShowGui();
}
private void createAndShowGui() {
window = new JFrame("Matrix Monologue");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("At last. Welcome, Neo. As you no doubt have guessed, I am Morpheus. This is your last chance. After this there is no turning back."); // Label in frame.
window.add(label, BorderLayout.PAGE_START);
window.add(createCheckBoxes(), BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
button = new JButton("submit");
button.addActionListener(this);
buttonPanel.add(button);
window.add(buttonPanel, BorderLayout.PAGE_END);
window.setSize(750,200); // Length, Height
window.setLocation(200,200); // X/Y "OF THE ENTIRE FRAME" Not the contents
window.setVisible(true); // makes window visible
}
private JPanel createCheckBoxes() {
JPanel panel = new JPanel();
BoxLayout layout = new BoxLayout(panel, BoxLayout.PAGE_AXIS);
panel.setLayout(layout);
red = new JRadioButton("You take the red pill, you stay in Wonderland and I show you how deep the rabbit hole goes.");
blue = new JRadioButton("You take the blue pill, the story ends, you wake up in your bed and believe whatever you want to believe.");
ButtonGroup grp = new ButtonGroup();
grp.add(red);
grp.add(blue);
panel.add(red);
panel.add(blue);
return panel;
}
public static void main(String[] args) {
EventQueue.invokeLater(new CMIS242WK4DonnersonAReply());
}
}
Here is how the app looks when I run it.

Related

ActionListener never fires if previous listener calls revalidate()

So I've made a basic UI that shows text fields that will alert the user if the contents is outside of given bounds by causing a label to appear below it. This occurs if the user hits return or Tabs away from the field.
There is also a button that will advance the program so long as all of the fields are correct. If they are not it will cause the text fields to 'flash' (animation background red back to white).
This works fine except for one little bug - if the user enters incorrect data and immediately clicks the button, without first leaving the field, the focus listener fires and adds the label below the text field, but the click button action never fires (no flash). This appears to be due to the FocusListener event calling revalidate() on the panel and or pack() on the enclosing jframe.
Here's a working minimal example to demonstrate the problem
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
/**
* Demonstration that running revalidate() or JFrame.pack() in FocusListener
* (on a textField) causes the action listener for a JButton to never fire.
*
* This is only a problem if the contents of the frame are changed (ie. only
* happens once when label is added).
*/
public final class App {
private App() {
JFrame jFrame = new JFrame();
JPanel main = new JPanel();
MyPanel myPanel = new MyPanel();
JButton button = new JButton("Click");
button.addActionListener(event->{
/* with the code as it is this will never print if
the button is pressed while textField has focus
and label is not yet displayed */
System.out.print("\n Click has been pressed");
});
main.add(myPanel);
main.add(button);
jFrame.add(main);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(()-> new App());
}
/**
* Creates a panel containing a text box.
* when this text box looses focus it causes
* a label to be added and the frame to resize (.pack())
*/
class MyPanel extends JPanel{
JLabel label;
JTextField textField;
public MyPanel(){
label = new JLabel("hello");
textField = new JTextField(10);
this.add(textField);
textField.addFocusListener(new Handler(this));
}
private class Handler implements FocusListener{
JPanel panel;
public Handler(JPanel panel){
this.panel = panel;
}
#Override
public void focusGained(FocusEvent e) {
}
#Override
public void focusLost(FocusEvent e) {
// if this line is removed
panel.add(label);
// if the below two lines are removed
// button ActionListener will fire
panel.revalidate();
SwingUtilities.getWindowAncestor(panel).pack(); // side note if this is called is revalidate() needed?
}
}
}
}
Any advice on how to fix this would be great. One thing to note is that in the real program the MyPanel class would be in its own file, if that affects any solutions.
Cheers.
=============== EDIT ======================
I was running it in my IDE (vscode) where the problem occured. When I compiled it and ran it from the terminal it worked fine. I presume its some quirk of the IDE.

Adding more mouselisteners to 1 JButton?

Is it possible to add more than 1 mouselistener to a JButton? You know when I click on the button it should change color and text, and do something (e.g system.out.println), and when I click it again it should go back to the previous state, and print something else.
What I've tried:
JButton b = new JButton("First");
b.setBackground(Color.GREEN);
b.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e)
{
b.setBackground(Color.RED);
b.setText("Second");
System.out.println("You've clicked the button");
}
if(b.getModel.isPressed){
b.setBackground(Color.GREEN);
b.setText("Second");
System.out.println("You're back");
}
The problem is that the button doesn't go back to the previous state with the color (green) and text, and I don't how to handle that.
First of all, you shouldn't be using a MouseListener to do these things, because a better listener, ActionListener, was built specifically to be used with JButtons and similar entities to notify programs that a button has been pressed.
Having said that, sure you can add multiple ActionListeners (or MouseListeners) to a JButton, or you can have an ActionListener change its behaviors depending on the state of the program (usually meaning the values held by fields of the class).
A problem with your code and question is that I don't see when you expect or want the button to change its color back to green. If after a certain period of time, then have your ActionListener start a Swing Timer that changes the button's color back to green after x milliseconds.
Edit: I see, you want to toggle color -- then use a boolean field that you toggle or check the button's current color and base the listener's response based on that color.
example
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
#SuppressWarnings("serial")
public class ToggleColor extends JPanel {
public ToggleColor() {
JButton button = new JButton(new MyButtonAction());
button.setBackground(Color.GREEN);
add(button);
}
private static void createAndShowGui() {
ToggleColor mainPanel = new ToggleColor();
JFrame frame = new JFrame("ToggleColor");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
#SuppressWarnings("serial")
class MyButtonAction extends AbstractAction {
// !! parallel arrays being used below -- avoid if possible
private static final String[] TEXT = {"First", "Second", "Third"};
private static final Color[] COLORS = {Color.GREEN, Color.RED, new Color(108, 160, 220)};
private int index = 0;
public MyButtonAction() {
super(TEXT[0]);
}
#Override
public void actionPerformed(ActionEvent e) {
index++;
index %= TEXT.length;
putValue(NAME, TEXT[index]);
Component c = (Component) e.getSource();
c.setBackground(COLORS[index]);
}
}
This uses an AbstractAction class which is like an ActionListener but on "steroids"
You should only register one lister, but that listener will maintain some state regarding the number for mouse clicks. A simple if/else block will change the actions and change the text on the button label.

JLabel does not appear in the JFrame

I am having trouble implementing JLabel with JFrame. The program needs to show either "Hello" or "World" in the center of the screen when the button "study" is pressed. Also with this being a flashcard program, when study is pressed a word is placed on the middle of the screen and the program is suppose to read from the text field for the user input and print whether it is right or wrong. The problem is that the program is reading the text field after study is pressed so it is printing false before the user can input a answer.
Can someone briefly explain why this is not working and what I can do to fix this issue?
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JButton;
public class NoteCardGUI implements ActionListener {
public static JFrame frame;
public static JPanel panel;
public static JLabel label;
private NoteCard ex;
private JButton study;
public static Box box1 = new Box(), box2 = new Box(), box3 = new Box();
public NoteCardGUI() {
ex = new NoteCard("Hello", "World");
frame = new JFrame("Flash Card");
panel = new JPanel();
study = new JButton("Study");
study.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String resp = NoteCard.getResponse(ex);
String chal = NoteCard.getChallenge(ex);
String a = text.getText();
label = new JLabel(chal, label.CENTER);
label.setAlignmentX(0);
label.setAlignmentY(0);
frame.add(label, BorderLayout.SOUTH);
frame.revalidate();
if(resp.compareTo(a) == 0)
{
label = new JLabel("Correct!");
}
label = new JLabel("Incorrect");
}
});
panel.add(study);
frame.add(panel);
frame.setSize(500, 500);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
new NoteCardGUI();
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
You are adding the label to your frame, but you already have added a JPanel on top of the frame. The solution is to add the label to the panel instead of the frame.
So change: frame.add(label); to panel.add(label);
By default, a JFrame (or rather, its content pane) has BorderLayout. This means that if you add components to it without specifying a constraint, they will be added at the CENTER. But you can't add more than one element at any of the BorderLayout's regions.
So in order for this to work, you need to add the label somewhere else other than the center, or have the panel added with some other, explicit region.
So if you change the add, for example, to:
frame.add(label, BorderLayout.NORTH);
It will work - but you must not forget to also add:
frame.revalidate();
Whenever you add components to your GUI, you should call this when you've added them all, in order for it to rebuild the hierarchy of components as needed.
Another option would be to change the layout manager of the Frame, or to add to the panel.

Swing: grayable multi-line JCheckBox?

I want to have a checkbox with multi-line text and I want to disable it sometimes.
Simple JCheckBox works fine and gets disabled, but it's not multiline.
Putting <html>line1<br>line2</html> provides correct size and layout, but when I disable the control, only the checkbox itself is grayed, the text remains black.
I know I can change the HTML text color to gray, but this will not work for the "Classic Windows" look-and-feel where disabled text should rendered as "sunken". Or, actually, it will work, but the appearance will differ from other disabled controls nearby, which is not good.
I can create a simple JCheckBox containing the first line of text and a JLabel with the second line and disable them simultaneously, but clicking the second line (the JLabel) doesn't activate the checkbox, and clicking the checkbox displays the keyboard focus only around the first line which confuses the user.
Is it possible to have a checkbox and its label as separate controls and have some kind of link between them, as in HTML? Probably I would be able to cook something from this.
Is it possible to subclass JButton and override something there, for example, to change the way the focus rectangle is drawn? The rectangle is drawn by com.sun.java.swing.plaf.windows.WindowsButtonUI but I'm kinda afraid of subclassing that class because it's too deep in the standard library and my application may break with a new JRE.
EDIT 04.02.2015: The above applies to Java 1.6. In Java 1.7 and higher, disabling a multi-line checkbox changes its appearance, but it still looks not the same as a disabled single-line checkbox; in particular, on Classic Windows theme the text doesn't become sunken.
(source: keep4u.ru)
I might be missing something, but I just disable the JCheckBox and the JLabel.
Using Java 1.7 and Windows Vista.
Here's the code
package com.ggl.testing;
import java.awt.BorderLayout;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class CheckBoxTest implements Runnable {
private JCheckBox checkBox;
private JLabel multiLineLabel;
private JFrame frame;
#Override
public void run() {
frame = new JFrame("Check Box Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
JPanel checkBoxPanel = new JPanel();
checkBox = new JCheckBox();
checkBoxPanel.add(checkBox);
String s = "<html>When in the course of human events it becomes"
+ "<br>necessary for one people to dissolve the political"
+ "<br>bands which have connected them with another and to"
+ "<br>assume among the powers of the earth, the separate"
+ "<br>and equal station to which the Laws of Nature and"
+ "<br>of Nature's God entitle them, a decent respect to the"
+ "<br>opinions of mankind requires that they should declare"
+ "<br>the causes which impel them to the separation.";
multiLineLabel = new JLabel(s);
multiLineLabel.setLabelFor(checkBox);
checkBoxPanel.add(multiLineLabel);
mainPanel.add(checkBoxPanel, BorderLayout.CENTER);
JPanel toggleButtonPanel = new JPanel();
JToggleButton toggleButton = new JToggleButton("Disable Checkbox");
toggleButton.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent event) {
JToggleButton toggleButton = (JToggleButton) event.getSource();
if (toggleButton.isSelected()) {
checkBox.setEnabled(false);
multiLineLabel.setEnabled(false);
} else {
checkBox.setEnabled(true);
multiLineLabel.setEnabled(true);
}
}
});
toggleButtonPanel.add(toggleButton);
mainPanel.add(toggleButtonPanel, BorderLayout.SOUTH);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new CheckBoxTest());
}
}

New JCheckboxes not appearing below eachother

I am trying to make a basic program where whenever you press a button, a JCheckbox is generated and added below the other JCheckbox on a panel. I figured out how to generate the JCheckbox with a ActionListener but I can't figure out how to get each new check box to appear below the previous one. Everything else seems to be working but I can't get this location thing to work.
box.setVisible(true);
_p.add(box);
int i = 0;
int u = i++;
box.setAlignmentX(0);
box.setAlignmentY(u);
Here is a sample of my code. I've been stuck on this problem for a very long time and would greatly appreciate any and all help.
Check out the Swing tutorial on Using Layout Managers. You could use a vertical BoxLayout or a GridBagLayout or maybe a GridLayout.
Whatever layout you choose to use the basic code for adding components to a visible GUI is:
panel.add(...);
panel.revalidate();
panel.repaint();
The other statements in your code are not necessary:
//box.setVisible(true); // components are visible by default
The following methods do not set a grid position.
//box.setAlignmentX(0);
//box.setAlignmentY(u);
JCheckbox lives in a container like a JPanel (that means that you add checkbox to a panel) . A JPanel have a layoutManager. Take a look about Using Layout Managers
You could use BoxLayout with Y_AXIS orientation or a GridLayout with 1 column and n rows.
Example:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CheckBoxTest {
private JPanel panel;
private int counter=0;
public CheckBoxTest(){
panel = new JPanel();
panel.setLayout(new BoxLayout(panel,BoxLayout.Y_AXIS));
JButton button = new JButton(" Add checkbox ");
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent evt){
panel.add(new JCheckBox("CheckBox"+Integer.toString(counter++)));
//now tell the view to show the new components added
panel.revalidate();
panel.repaint();
//optional sizes the window again to show all the checkbox
SwingUtilities.windowForComponent(panel).pack();
}
});
panel.add(button);
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("Checkbox example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationByPlatform(Boolean.TRUE);
CheckBoxTest test = new CheckBoxTest();
frame.add(test.panel);
//sizes components
frame.pack();
frame.setVisible(Boolean.TRUE);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}

Categories

Resources