0

My intention is to use the ListCellRenderer in order to highlight red cells that contain links that have been visited(or clicked) and green those which have not been visited this works partially but not quite. It seems that the renderer works as far as it concerns marking the cells red. If I however add more rows, they come all red colored thereafter. In addition if I mark two cells that are not adjacent then it marks them all red as well.

I have a class Feed, where I initially had a boolean variable, but I have modified the code so that the m_isRead variable is in the listModel here is the constructor:

    public Feed (URL url, String urlName) {
         this.m_urlName = urlName;
         this.m_observers = new ArrayList<Observer>();  
         this.m_isRead = isRead;
    }

Now this instance variable is set to false in the listModel Class which is the one that contains the renderer.

 m_isRead = false.

When using the ListCellRenderer which I now have adjusted so that it does not require this method:

m_feeds.get(index).getM_urlName();

I proceed as follows:

 class MyCellRenderer extends JLabel implements ListCellRenderer {
         public MyCellRenderer() {
             setOpaque(true);
         }

         public Component getListCellRendererComponent(JList list,
                                                       Object value,
                                                       int index,
                                                       boolean isSelected,
                                                       boolean cellHasFocus) {

             setText(value.toString());

             Color background = Color.GREEN;
             Color foreground = Color.BLACK;

               //find out if the specific has been read or not
               if (m_feeds.get(index).isM_isRead() == true) {
                 background = Color.RED;
                 foreground = Color.WHITE;


             } else {
                 background = Color.GREEN;
                 foreground = Color.BLACK;
             };

             setBackground(background);
             setForeground(foreground);

             return this;
         }
     }

Then I have another inner class with a method which I use to get the selected item, at that point I set m_isRead to true (to read) this is now independent from the Feed class and the code which related to it has been commented out:

public class ChangeSelectedIndex implements ListSelectionListener {

    @Override
    public void valueChanged(ListSelectionEvent e) {

        for (int i = 0; i < m_listModel.size(); i++) {  
            if (m_listModel.getElementAt(i) != null) {    
                m_urlName = m_list.getSelectedValue();
                initiateParsing();
                m_updateFeedButton.setEnabled(true);

               // TODO fix behavior for cell renderer
               //this sets the value of the feed being clicked to true
              // m_feeds.get(i).setM_isRead(true);
                 m_isRead = true;
            }
         }// end for 
     }
}

Now the result is the same, if I add the rows they are green and that is correct, if I click on each row each turns read provided that I have clicked the adjacent rows to the first one I click but if I, for example, have four rows and I click the first row and the last row, all the rows, including those in between (which I have not clicked) turn red. Likewise, if I add new rows they come in red. That is if I click even one of those rows then the ones I add thereafter will be red.

Can anybody help?

Thank you in advance,

Cheers

bluetxxth
  • 121
  • 2
  • 16
  • 1
    Here's an idea. Rather then relying on an direct external manager to determine the state of a link, wrap the link in the state and add that to the model... – MadProgrammer Oct 01 '13 at 05:23
  • 1
    Basically, the model should model the data in the list. Where ever possible, it should not rely on some other external element, because the two can become unsynced causing your problems. So the `isRead` flag should be part of the data in the list - IMHO – MadProgrammer Oct 01 '13 at 05:47
  • `m_feeds.get(i).setM_isRead(true);` sets the value to `true`, but who's telling the model that it's changed? – MadProgrammer Oct 01 '13 at 05:50
  • So that this instance variable should be in the list and it is the list that I should tested for read and unread feeds do if I understand.? – bluetxxth Oct 01 '13 at 05:54
  • in the changedSelectedindex method, I set each feed to true, m_feeds.get(i).setM_isRead(true); if the link is clicked. I thought that would suffice.. – bluetxxth Oct 01 '13 at 05:57
  • It all depends. I would try and make it so that the object in the list had all the information it need to render, to my find, that would the `Feed` object. When ever the feed object was changed, you need to tell the model that one of it's elements has changed so that the model can raise the appropriate events and the view can be updated. From what I could piece together from you example code, it works fine for me... – MadProgrammer Oct 01 '13 at 05:57
  • *"in the changedSelectedindex method, I set each feed to true if the link is clicked. I thought that would suffice.."* But how does the model that any things changed? How does the view know that any things changed? – MadProgrammer Oct 01 '13 at 05:58
  • I am trying to digest this.... ;-) I think I understand but I need to look further in the model view controller pattern in the swing context to understand better...Many thanks for the help I might get back to this – bluetxxth Oct 01 '13 at 06:12
  • It's a little counter-intuitive, but @MadProgrammer is right: color, usually considered a visual attribute, is part of the model in this case. More on Swing MVC [here](http://stackoverflow.com/a/3072979/230513). – trashgod Oct 01 '13 at 07:08
  • For better help sooner, post an [SSCCE](http://sscce.org/). – Andrew Thompson Oct 01 '13 at 07:24
  • I have edited the code according to the comments please take a look... I will also try to make an SSCCE as suggested... – bluetxxth Oct 01 '13 at 07:41
  • Note your `else` block in `MyCellRenderer` is no needed (it's redundant). Also when you work with boolean expressions there's no need to write them this way: `expression == true` or `expression == false`. You can just use `expression` or `!expression` respectively – dic19 Oct 01 '13 at 11:25

1 Answers1

0

After a while thinking about it I have concluded that there was nothing wrong my original cell renderer, it has had to do with the list model itself. The JList simply did not support multiple NON contiguous selection without clicking the Ctrl button right out of the box. This is what triggered further searching on my side on how to emulate the Ctrl click down; which I found here on answer number 8 (working code):

Individual and not continuous JTable's cell selection

The interesting here is adding the mouse event to the list. This mouse event emulates a Ctrl down event, which the ListSelectionModel which is used by JList as well as JTable is set to MULTPLE_SELECTION_INTERVAL it behaves as desired. That is, the user now able to click on whatever feed, even if it is not contiguous, and it will color the desired feed or feeds without coloring whatever unclicked feed may lay in between.

As for the renderer, it would suffice to use the isSelected parameter which comes in through with its method getListCellRenderer(). However, in my case, what I had done has the same effect with the addition that I was using an array to add all the statuses of the feeds, meaning, read or unread. Proceeding this way, I had in mind that if I closed the program and save the feed list, including its isRead parameter set to either true or false, then later on upon retrieving the feed list, the same feed status would be restored from, for example, a file, or at least that is what I had in mind.

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
bluetxxth
  • 121
  • 2
  • 16