Looking at adding event listeners to JComboBoxes.
Ive done the usual window etc. Created a new JComboBox and then .addItem() islands into it.
I have then attempted to use .addItemListener(this) on my newly created combobox
But theres a problem, its mentioning abstract class which means i have not done something. Can anyone see where ive gone wrong?
Ive tried .addItemListener(this) on the individual entries and that did not work. Ive tried declaring the JComboBox inside and outside of the constructor.
It may be worth noting the method itemStateChange is from the book, I have had to build around that block.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class ComboBoxPractice extends JFrame implements ItemListener
{
//create islands
JLabel selection = new JLabel();
JComboBox islands = new JComboBox();
public ComboBoxPractice()
{
// set a window
super("action");
setSize(300,100);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
// set a container
Container content = getContentPane();
FlowLayout layout = new FlowLayout();
content.setLayout(layout);
//add item listener
islands.addItemListener(this);
// add items to list
islands.addItem("Corfu");
islands.addItem("Crete");
islands.addItem("Canada");
islands.addItem("Canary Islands");
//add island and label to container
content.add(islands);
content.add(selection);
}
public void itemStateChange(ItemEvent event)
{
String choice = event.getItem().toString();
selection.setText("chose" + choice);
}
}
#Override
public void itemStateChanged(ItemEvent event)
{
String choice = event.getItem().toString();
selection.setText("chose" + choice);
}
Try changing it to that. with the #Override on top. This then doesn't throw an error for me and works.
Related
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.
I have a JComboBox that is editable. When the user enters a new item, I want that added to the list and display it as the selected item. I am able to add it to the list but I cannot seem to make it display as the selected item. By default I display an empty string ("") which is what the user would edit to add the new item.
public class EventComboBoxListener implements ActionListener {
private JComboBox<String> eventBox=null;
public EventComboBoxListener(JComboBox<String> event_) {
eventBox=event_;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Selected: " + eventBox.getSelectedItem());
System.out.println(", Position: " + eventBox.getSelectedIndex());
if (eventBox.getSelectedIndex() < 0) {
eventBox.addItem(eventBox.getSelectedItem().toString());
eventBox.setSelectedItem(eventBox.getSelectedItem().toString());
}
}
}
It doesn't make sense to me that I have to use setSelectedItem with the getSelectedItem. That it does not work is no surprise but I don't know what else to do. The newly added item shows up in the list as it should but how do I make it the selected item in the display at the same time? I can select it after but that should not be necessary.
Added MVCE:
Main
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
public class Test {
public static void main(String[] args) {
String[] list= {"","A","B","C"};
TestTableModel model=new TestTableModel(null,new String[] {"col1","col2"});
JTable table=new JTable(model);
JDialog dialog=new JDialog();
JScrollPane scroller=new JScrollPane(table);
JComboBox<String> box=new JComboBox<String>(list);
box.setEditable(true);
box.setSelectedIndex(0);
box.addActionListener(new EventComboBoxListener(box));
JTextField field=new JTextField();
field.setPreferredSize(new Dimension(75,30));
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setLayout(new FlowLayout());
dialog.setSize(new Dimension(400,100));
dialog.add(scroller);
dialog.pack();
dialog.setVisible(true);
table.getColumnModel().getColumn(0).setCellEditor(new DefaultCellEditor(box));
table.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(field));
model.insertRow(0,new Object[] {"","placeholder"});
}
}
TestTableModel class
import javax.swing.table.DefaultTableModel;
public class TestTableModel extends DefaultTableModel {
/**
*
*/
private static final long serialVersionUID = 1L;
public TestTableModel(Object[][] data_,String[] columnNames_) {
super(data_,columnNames_);
}
}
First of all some comments about the MCVE (since you will be including one with every question in the future).
We expect the code so be in a single source file so we can easily copy/paste compile and test. We don't want 3 files lying around on our machine that we need clean up after testing.
Only relevant code directly related to the problem should be included. Why do you have the TestTableModel class. Are the "column names" relevant to the problem? The point is always test your MCVE using standard JDK classes when possible.
Regarding the EventComboListener class. Again, this can be added to the combo box by using and annoymouse inner class or a lambda. This keeps the code in a single class.
The newly added item shows up in the list as it should but how do I make it the selected item in the display at the same time?
I found that playing with your MCVE the ActionListener of the combo box is invoked at different times.
So my suggestion is to add the ActionListener to the editor of the combo box. Then we know for sure the ActionListener is only invoked when you press the Enter key. Once you press the Enter key the editor is stopped and the value is saved to the model.
So the logic would be something like:
//box.addActionListener(new EventComboBoxListener(box));
ComboBoxEditor editor = box.getEditor();
JTextField textField = (JTextField)editor.getEditorComponent();
textField.addActionListener( new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
String item = textField.getText();
DefaultComboBoxModel model = (DefaultComboBoxModel)box.getModel();
if (model.getIndexOf(item) == -1)
{
box.addItem(item);
box.setSelectedIndex( box.getItemCount() - 1 );
}
}
});
So the trick is to set the select index (not the selected item). But first the logic checks to make sure the item has not already been added to the combo box.
I have a simple java program and when I run it, using eclipse, it displays the 3 JButtons that I have set to the layout. The buttons are set to change the alignment of the layout. So you press left to align left and right to align right and center to align center.
While the buttons do this, the alignment doesn't change in the window till you resize it.
Ive tried updating both the jdk and eclipse and didnt make a difference and I cant see a problem with the code itself.
Anyone know why this is?
import javax.swing.JFrame;
public class Main {
public static void main(String []args){
Layout_buttonsAndActionEvents layout = new Layout_buttonsAndActionEvents();
layout.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
layout.setSize(300,300);
layout.setVisible(true);
}
}
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Layout_buttonsAndActionEvents extends JFrame {
private static final long serialVersionUID = 1L;
private JButton leftButton;
private JButton rightButton;
private JButton centerButton;
private FlowLayout layout;
private Container container;
public Layout_buttonsAndActionEvents(){
super("The Title");
layout = new FlowLayout();
container = new Container();
setLayout(layout);
leftButton = new JButton("Left");
add(leftButton);
//Align to the left
leftButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
layout.setAlignment(FlowLayout.LEFT);
layout.layoutContainer(container);
}
});
centerButton = new JButton("Center");
add(centerButton);
//Align to the right
centerButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
layout.setAlignment(FlowLayout.CENTER);
layout.layoutContainer(container);
}
});
rightButton = new JButton("Right");
add(rightButton);
//Align to the right
rightButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
layout.setAlignment(FlowLayout.RIGHT);
layout.layoutContainer(container);
}
});
}
}
Because you are adding the buttons to the JFrame's content
pane ( via the add() method which is really a call to
getContentPane().add() under the covers ) you need to call revalidate() on
the content pane.
In the three action listeners, change:
layout.setAlignment(FlowLayout.XXX);
layout.layoutContainer(container);
to:
layout.setAlignment(FlowLayout.XXX);
getContentPane().revalidate();
Also, you can remove all references to the variable named 'container' as it does nothing in your example.
When you resize a JFrame, it is re-validated with the new size and layout. Similarly, you must validate the and repaint the frame after adding the altered layout to apply a visual difference.
Make sure to call these methods in this order after altering the layout:
setLayout(layout);
repaint();
revalidate();
help,
my questions are:
why isn't itemStateChanges triggered, I tried to put it in the inner class ButtonHandler and also in RadioButtonHandler Im having trouble with it, what is the right way to do it?
I want to trigger and check the marked JRadioButtons after the user click the "check" button.
What is the right way to check which button was clicked, I feel like comparing the strings is bad programming practise. Maybe using an ID ?
How should I make a "reset" button(start over), I want to uncheck all radio buttons and run the constructor once again.
Thank you for your help !
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
public class ExamFrame extends JFrame {
static ArrayList<Question> qArrList;
JRadioButton a1,a2,a3,a4;
public ExamFrame() {
super("Quiz");
setLayout(new GridLayout(0, 1));
GridBagConstraints gbc = new GridBagConstraints();
Exam exam = new Exam();
qArrList = exam.getExam();
int count=0;
for(Question q : qArrList){
count++;
JLabel questionLabel = new JLabel(count+". "+q.getQustion()); //swing constant ?
ArrayList<String> ansRand = q.getAllRandomAns();
a1 = new JRadioButton(ansRand.get(0));
a2 = new JRadioButton(ansRand.get(1));
a3 = new JRadioButton(ansRand.get(2));
a4 = new JRadioButton(ansRand.get(3));
add(questionLabel);
add(a1);add(a2,gbc);add(a3);add(a4);
ButtonGroup radioGroup = new ButtonGroup(); //logical relationship
radioGroup.add(a1);radioGroup.add(a2);radioGroup.add(a3);radioGroup.add(a4);
}
//buttons:
JButton checkMe = new JButton("Check Exam");
JButton refresh = new JButton("Start Over");
ButtonHandler handler = new ButtonHandler();
checkMe.addActionListener(handler);
refresh.addActionListener(handler);
add(checkMe);
add(refresh);
}
/** Listens to the radio buttons. */
public class ButtonHandler implements ActionListener
{
public void actionPerformed (ActionEvent e) {
if(e.getActionCommand().equals("Start Over")){ //id?
//how to do this?
}
else{
RadioButtonHandler handler = new RadioButtonHandler();
a1.addItemListener(handler);
System.out.println("success?");
}
JOptionPane.showMessageDialog(ExamFrame.this, String.format("You pressed: %s", e.getActionCommand()));
}
public void itemStateChanged(ItemEvent e) //can i add it here?
{
JOptionPane.showMessageDialog(ExamFrame.this, String.format("yes?"));
System.out.println("success!");
}
}
public class RadioButtonHandler implements ItemListener
{
public void itemStateChanged(ItemEvent e)
{
JOptionPane.showMessageDialog(ExamFrame.this, String.format("radio state changed"));
}
}
}
why "itemStateChanges" isn't triggered, i tried to put it in the inner
class "ButtonHandler" and also in "RadioButtonHandler" Im having
troubles with it, what is the right way to do it? I want to trigger
and check the marked JRadioButtons after the user click the "check"
button.
ButtonHandler is implemented with ActionListener only:
public class ButtonHandler implements ActionListener{}
The itemStateChanged(ItemEvent) function belongs to ItemListener. This function is triggered if state of a source component to which this listener is registered gets changed. So implement the ItemListener. However, one more thing to note, that JButton doesn't respond to ItemListener but JRadioButton will. Because this Item events are fired by components that implement the ItemSelectable interface. Some example of such components are: check boxes, check menu items, toggle buttons and combo boxes including Radio Buttons as mentioned above.
What is the right way to check which button was clicked, i feel like
comparing the strings is wrong programming. Maybe using an ID
Well using the event source function: e.getSource(), check whither the type of the source is your expected type and cast it to appropriate type. And then you can use getName(String) function and check the name you were expecting. Of-course you should assign the name using setName(String) after initialization of component. Or using the component reference directly if it is declared in the Class context and you have direct access to the component.
#Override
public void itemStateChanged(ItemEvent e) {
if(e.getSource() instanceof JCheckBox)
{
JCheckBox checkBox = (JCheckBox)e.getSource();
if(checkBox.getName().equals("expectedName"))
; // do my thing
}
}
How should i make a "reset" button(start over), i want to uncheck all
radio buttons and run the constructor once again.
Well you are working with ButtonGroup. And ButtonGroup has a nice function: clearSelection() to help with whatever(I could not understand the part: run the constructor part) you want.
Edit: As you wanted me to see an ItemListener implemented class, Yes i can see that But:
i can not see that you have actually registered an instance of that class(a1.addItemListener(handler);) to any component before performing any action on the component to which ButtonHandler is registered to: checkMe, refresh
In addition to that, in this action performed function, you are checking with
action command, which you haven't even set with JButton.setActionCommand(String) function. You should not assign a (Item)listener depending on event-occurrence of another (Action)listener.
Tutorial:
How to Write an ItemListener
How to Write an ActionListener
How to Use the ButtonGroup Component
I've looked around quite a lot on google and followed several examples however I can't seem to get my JScrollPane working on a textarea in a JPanel.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.lang.*;
import javax.swing.event.*;
class main
{
public static void main(String Args[])
{
frame f1 = new frame();
}
}
class frame extends JFrame
{
JButton B = new JButton("B");
JButton button = new JButton("A");
JTextArea E = new JTextArea("some lines", 10, 20);
JScrollPane scrollBar = new JScrollPane(E);
JPanel grid = new JPanel ();
frame()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500,800);
setTitle("Mobile Phone App");
setLocationRelativeTo(null);
E.setLineWrap(true);
E.setEditable(false);
grid.add(button);
button.addActionListener(new action());
grid.add(B);
B.addActionListener(new action());
//grid.add(E);
grid.getContentPane().add(scrollBar);
add(grid);
setVisible(true);
}
class action implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String V = E.getText();
if(e.getSource() == button)
{
E.setText(V + "A is pressed");
}
if(e.getSource() == B)
{
E.setText(V + "B is pressed");
}
}
}
}
Would be great if someone can see where I am going wrong. I added JscrollPane in which I added the text area "e" in it.
E.setColumns(10);
E.setRows(5);
E.setPreferredSize(new Dimension(10,5)); // delete this
Don't hardcode a preferred size. The preferred size is overriding your attempt to set the rows/columns. So get rid of that line.
Note, you can also specify the row/columns when you create the text area:
JTextArea textArea = new JTextArea(5, 10);
to provide a hint to the intial size of the text area. Now the text area can change in size as text is added or removed and the scrollbar will appear when needed.
Also follow standard java naming conventions. Variable names should NOT start with an upper case character.
Right I got it!
Basically I had to add it in differently...the way I was approaching it was wrong!
grid.add(scrollBar, BorderLayout.CENTER);