Radiobiscuit
Radiobiscuit

Reputation: 55

JButton becomes enabled after JTextfield default action

I'm getting to grips with Java again and playing with Swing. Currently trying to understand JList.

When selecting items in a JList, I enable a button (the "Remove" button). When there's no selection, the button should be disabled (can't remove an item if it's not selected, the JVM tends to vomit if you don't have an item index).

When adding a list item through a JTextField default action (enter), the button enables but there's no selection in the JList. The code to enable the button doesn't even run. How is this happening? Maybe I'm missing a listener somewhere?

All the listeners are in the main class, but it doesn't seem to be a problem with the others. I can't see the class instantiating twice, so it's not that. Any ideas would be great?

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class GUI extends JFrame implements Runnable, ActionListener, DocumentListener, ListDataListener, ListSelectionListener {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    //declare and instantiate interface components
    DefaultListModel<String> lm=new DefaultListModel<String>();
    JList<String> jl=new JList<String>(lm);

    JTextField jt=new JTextField(50);

    JButton b_add=new JButton("Add");
    JButton b_del=new JButton("Remove");    

    @Override
    public void run() {
        //FROM RUNNABLE INTERFACE

        //set GUI (JFrame) attributes
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setLocationByPlatform(true);
        setName("List of Lists");
        setSize(1280, 500);
        setLayout(new FlowLayout());

        //set component attributes
        jl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); //single selection list

        jt.getDocument().addDocumentListener(this);

        //other interface components
        JScrollPane sp=new JScrollPane(jl);
        JButton b_exit=new JButton("Exit");


        //other component attributes
        sp.setSize(500, 500);

        b_add.setEnabled(false);
        b_del.setEnabled(false);


        //set component listeners
        b_add.addActionListener(this);
        b_del.addActionListener(this);
        b_exit.addActionListener(this);

        jt.setActionCommand("TXT");
        jt.addActionListener(this);

        lm.addListDataListener(this);
        jl.addListSelectionListener(this);


        //add GUI components
        add(jt);
        add(sp);
        add(b_add);
        add(b_del);
        add(b_exit);

        //set GUI visible
        setVisible(true);
    }

    //FROM ACTIONLISTENER INTERFACE
    @Override
    public void actionPerformed(ActionEvent ae) {

        //default action on text field (enter key)
        if (ae.getActionCommand()=="TXT") {     
            lm.addElement(jt.getText());
            jt.setText(null);

        } else {

            //actions from buttons
            switch (ae.getActionCommand()) {

            //add button
            case "Add":
                lm.addElement(jt.getText());
                jt.setText(null);
                break;

            //remove button
            case "Remove":
                if (jl.getSelectedIndex()>=0) {
                    lm.remove(jl.getSelectedIndex());

                }
                break;

            //exit button   
            case "Exit":
                setVisible(false);
                dispose();
                break;

            //just in case
            default:
                break;

            }
        }
    }

    //FROM DOCUMENTEVENTLISTENER INTERFACE
    @Override
    public void changedUpdate(DocumentEvent de) {

        b_add.setEnabled(de.getDocument().getLength()>0);
    }


    @Override
    public void insertUpdate(DocumentEvent de) {

        b_add.setEnabled(de.getDocument().getLength()>0);
    }


    @Override
    public void removeUpdate(DocumentEvent de) {

        b_add.setEnabled(de.getDocument().getLength()>0);
    }

    //FROM LISTDATALISTENER INTERFACE
    @Override
    public void contentsChanged(ListDataEvent ld) {

        b_del.setEnabled(lm.getSize()>0);
    }


    @Override
    public void intervalAdded(ListDataEvent ld) {

        b_del.setEnabled(lm.getSize()>0);
    }


    @Override
    public void intervalRemoved(ListDataEvent ld) {

        b_del.setEnabled(lm.getSize()>0);

    }

    //FROM LISTSELECTIONLISTENER INTERFACE
    @Override
    public void valueChanged(ListSelectionEvent ls) {

        b_del.setEnabled(jl.getSelectedIndex()>=0);
    }

}

What should happen is that the "Remove" button should only enable when an item in the JList is highlighted (selected).

Upvotes: 0

Views: 201

Answers (2)

CristianoDeVinni
CristianoDeVinni

Reputation: 150

Just add b_del.setEnabled(false); in Add case.

  //add button
        case "Add":
            lm.addElement(jt.getText());
            jt.setText(null);
            b_del.setEnabled(false);
            break;

Also, I recommend using system.exit(0) instead of dispose (). For memory reasons only (Obviously, it depends on your needs :) ).

Upvotes: 0

camickr
camickr

Reputation: 324088

What should happen is that the "Remove" button should only enable when an item in the JList is highlighted (selected).

Then you have too many listeners in your code.

There is no need for the DocumentListener. It doesn't matter if the data in the text field is changed. When you add the data from the text field to the JList, the selection does not change automatically.

There is no need for the ListDataListener. Again, you don't care if the data changes.

The only listener that is relevant to this requirement is the ListSelectionListener. This listener will fire an event when the selection changes. Then in the listener code you enable/disable the button based on the selection in the list.

Basic code in the listener might be:

int index = list.getSelectedIndex();
button.setEnabled( index = -1 ? false : true );

Read the section from the Swing tutorial on How to Write a ListSelectionListener for more information and a working example.

Upvotes: 1

Related Questions