views:

52

answers:

2

I am working on a viewer, which uses a JList to show thumbnails of the pages of a document. The user can open a page by selecting it through in the JList, or throught other mechanisms, like entering the number in a text box.

When using the latter alternative, I want that the JList also selects the page. I do this using setSelectedIndex(), but this triggers an event, which causes the page to be loaded again, as if the user had clicked and selected the page in the JList, and this is causing me some problems.

How I see it, the index should be set some way (perhaps in the model) so that only the UI of the JList updates, without firing an event that the index has changed.

Is this possible? Or is there a better way to solve my issue?

+1  A: 

It looks like setSelectedIndex() is just a convenient way to set the selection in the ListSelectionModel. Maybe your ListModel could flag or cache the result so it won't get loaded a second time.

Catalina Island
The pages are loaded when selected. I don't think it has to do with the ListModel.
Andrei Vajna II
+2  A: 
  1. You can remove all ListSelectionListener from the list, make a selection and then add them again.

  2. You can create your own ListSelectionModel with a method that doesn't throw the event and set it as a selection model to your JList, and then use getSelectionModel().yourSelectIndexMethod(index).

  3. You can also divert all your other methods of selection to the list, just find the corresponding entry if selecting the page by other means and select the item in the list. This way the item is selected and the page is loaded once.

Code for option 2:

public class ListTest extends JPanel{

private static final String[] items = new String[]{"1", "2", "3"};
private JList mylist;
private JComboBox myCombo;
private JTextArea myTA;

public ListTest() {
    setLayout(new BorderLayout());
    myCombo = new JComboBox(items);
    myCombo.addActionListener(new ActionListener(){

        @Override
        public void actionPerformed(ActionEvent e){
            valueSelectedCombo(myCombo.getSelectedIndex());
        }
    });
    JPanel pn = new JPanel();
    pn.setLayout(new BoxLayout(pn, BoxLayout.X_AXIS));
    pn.add(myCombo);
    pn.add(Box.createHorizontalGlue());
    pn.add(new JButton(new AbstractAction("Clear"){

        @Override
        public void actionPerformed(ActionEvent e){
            myTA.setText("");
        }
    }));
    add(pn, BorderLayout.NORTH);
    add(new JScrollPane(getJList()), BorderLayout.WEST);
    add(new JScrollPane(myTA = new JTextArea()), BorderLayout.CENTER);
}

private void valueSelectedList(int index){
    myTA.setText(myTA.getText() + "\n" + items[index]);
}

private void valueSelectedCombo(int index){
    myTA.setText(myTA.getText() + "\n" + items[index]);
    ((CustomSelectionModel)mylist.getSelectionModel()).setSelectionSilent(index);
}

private JList getJList(){
    if (mylist == null){
        mylist = new JList(items);
        mylist.setSelectionModel(new CustomSelectionModel());
        mylist.addListSelectionListener(new ListSelectionListener(){

            @Override
            public void valueChanged(ListSelectionEvent e){
                if (!e.getValueIsAdjusting()){
                    valueSelectedList(mylist.getSelectedIndex());
                }
            }
        });

        mylist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        mylist.setPreferredSize(new Dimension(100, 106));

    }
    return mylist;
}

private static class CustomSelectionModel extends DefaultListSelectionModel{

    private boolean isSilent = false;

    public void setSelectionSilent(int firstIndex){
        isSilent = true;
        setSelectionInterval(firstIndex, firstIndex);
        isSilent = false;
    }
    protected void fireValueChanged(int firstIndex, int lastIndex, boolean isAdjusting){
        if (isSilent){
            return;
        }
        super.fireValueChanged(firstIndex, lastIndex, isAdjusting);
    }
}

public static void main(String[] args){
    JFrame frame = new JFrame("test");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    // Add content to the window.
    frame.add(new ListTest());

    // Display the window.
    frame.pack();
    frame.setSize(300, 200);
    frame.setVisible(true);
}

}
Taisin
3. I'm not sure I understand this. I want to have the page selected in the JList, so simply bypassing this is not an option.2. If I do that, wouldn't it disable all ListSelectionEvents? Thus, when the user selects a page, no events will be triggered and no page would be loaded.1. How do I remove all listeners? I can't find a method like that. The only way I see it is to getListSelectionListeners() and remove them one by one. Really cumbersome....
Andrei Vajna II
...but other than that, it works.
Andrei Vajna II
3 - all your other then list selections just go to the list and select the corresponding item. This way, the item in the list is selected and the page is loaded once.2. You create a custom method in the model and call it when you just have to show the selection. No other methods are affected. 1. Yes, that's the only way.The easiest way, actually, would be to just load the page once unless the reload it explicitly requested.
Taisin
I updated the code, so you can see one way to do the option 2.
Taisin
+1 Very nice example. Note `text.append("\n" + items[index])` as an alternative in `valueSelectedCombo()`.
trashgod
@trashgod thanks for the note. Actually, I should have gone with `Document doc = myTA.getDocument(); doc.insertString(doc.getLength(), "\n", null); doc.insertString(doc.getLength(), items[index], null);`but well, for the test I opted for a simpler way.
Taisin