This discussion is archived
12 Replies Latest reply: Jun 12, 2012 1:21 AM by 941623 RSS

Conditionally update the list cell

941623 Newbie
Currently Being Moderated
Is it possible to update the list cell based on a given condition?

I was trying something like this, but it turns out that updateItem() is called later (and not when the Listview is updated from the ObservableList which i presumed)
 
 public class lCell extends ListCell<String> {
...
@Override
public void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);
            label.setText(getItem());//hbox contains image & a label
            System.out.println(item);
            if (item != null && !isCurrentUser)
              setGraphic(hbox);// Set the list cell as a hbox
            else if (item!=null && isCurrentUser) 
             setText(getItem()); //Set it as the message present in the ObservableList
            
        }
isCurrentUser is a "global" variable which changes it's value in a method (when another user - other than the one currently posting messages -enters the message)

Is there a way to get an output like:

<Image> User 1:
msg1
msg2
msg3...
<Image> User2:
msg1
msg2...
<Image> User1:
msgs...
  • 1. Re: Conditionally update the list cell
    JohnHendrikx Pro
    Currently Being Moderated
    It's even worse, those ListCells are temporary, so your check on that global variable is going to have different results next time the same contents must be displayed.

    You must make sure all the information that you need to render the ListCell the way you want it is present in the parameters to the updateItem call. You may need to create your own cell factory with ListCells that accept an object that contains both the messages + the user who created them, and then render the cell accordingly.

    Create a ListCell<UserMessage> for example, where UserMessage contains the user who typed the message and the message itself.
  • 2. Re: Conditionally update the list cell
    941623 Newbie
    Currently Being Moderated
    If you don't mind me asking could please tell me how to do this:
     >>You may need to create your own cell factory with ListCells that accept an object that contains both the messages + the user who created them, and then render the cell accordingly. 
    Preferably with an example.
  • 3. Re: Conditionally update the list cell
    JohnHendrikx Pro
    Currently Being Moderated
    Please read this tutorial about how to set a cell factoryl: http://docs.oracle.com/javafx/2/ui_controls/list-view.htm

    Then, instead of creating a ListView of Strings, create a ListView of UserMessage:
    ListView<UserMessage> list = new ListView<UserMessage>();
    Set the cell factory:
    list.setCellFactory(new Callback<ListView<UserMessage>, ListCell<UserMessage>>() {
        @Override 
        public ListCell<UserMessage> call(ListView<UserMessage> list) {
           return new UserMessageCell();
        }
    });
    And the cell class:
    public class UserMessageCell extends ListCell<UserMessage> {
      public void updateItem(UserMessage message, boolean empty) {
        super.updateItem(message, empty);
    
        if(!empty) {
          // configure the cell here with your UserMessage object
        }
      }
    }
  • 4. Re: Conditionally update the list cell
    941623 Newbie
    Currently Being Moderated
    Like you said, I created an object userMessage which has the username and the message. >>
     public class userMessage {
            private static String user;
            private static String message;
    
            public userMessage(String u, String m) {
            this.user = u;
            this.message=m;
            }
            public static String getUser() {
            return user;
            }       
            public void setUser(String user) {
            this.user = user;
            }
            public static String getMessage() {
            return message;
            }
            public void setMessage(String message) {
            this.message = message;
            }
    }
    And my list cell class looks something like this:
     public class lCell extends ListCell<userMessage> { 
     @Override
            public void updateItem(userMessage item, boolean empty) {
                super.updateItem(item, empty);
                if (item != null)
                {
                    StringBuilder sb = new StringBuilder();
                    sb.append(item.getUser()).append(": \n").append(item.getMessage());
                    setText(sb.toString());
                }
    }
    }
    Q). How do I add a <user name> and a <message> to the list?

    I thought, if i want a new message to be sent, i call a function add() which does the needful.>>
    public void add(String user, String message)
    {
           userMessage um = new userMessage(user, message);
           obs.addAll(um);
    }
    But it seems like the last known item (object) created over rides all the previous ones.

    so if for example I have:
    add(user1, Hi);
    add(user2, Hi!);
    add(user1, zzz); 
    The list view shows me:
    user1, zzz
    user1, zzz
    user1, zzz

    What do I do to prevent this? Do I have to create a different object every time? :\
  • 5. Re: Conditionally update the list cell
    JohnHendrikx Pro
    Currently Being Moderated
    You've declared your fields in your userMessage class with the 'static' keyword... which basically means something like 'global'...

    So when you change the field, it changes for all the userMessage instances. Remove the static keyword, and it should be better:
    public class UserMessage {
            private String user;
            private String message;
     
            public UserMessage(String u, String m) {
            this.user = u;
            this.message=m;
            }
            public String getUser() {
            return user;
            }       
            public void setUser(String user) {
            this.user = user;
            }
            public String getMessage() {
            return message;
            }
            public void setMessage(String message) {
            this.message = message;
            }
    }
    ps. Java naming conventions recommends that you start class names with a capital letter, so "UserMessage" instead of "userMessage".

    Good luck!
  • 6. Re: Conditionally update the list cell
    JohnHendrikx Pro
    Currently Being Moderated
    You've declared your fields in your userMessage class with the 'static' keyword... which basically means something like 'global'...

    So when you change the field, it changes for all the userMessage instances. Remove the static keyword, and it should be better:
    public class UserMessage {
            private String user;
            private String message;
     
            public UserMessage(String u, String m) {
            this.user = u;
            this.message=m;
            }
            public String getUser() {
            return user;
            }       
            public void setUser(String user) {
            this.user = user;
            }
            public String getMessage() {
            return message;
            }
            public void setMessage(String message) {
            this.message = message;
            }
    }
    ps. Java naming conventions recommends that you start class names with a capital letter, so "UserMessage" instead of "userMessage".

    Good luck!
  • 7. Re: Conditionally update the list cell
    941623 Newbie
    Currently Being Moderated
    Weird. Before it wouldn't run without static. (Can't call non static from static methods...).

    Anyway, now it's working!!

    And yes. I'll keep the naming of class convention different from that of variables.

    Thanks a lot! :D
  • 8. Re: Conditionally update the list cell
    941623 Newbie
    Currently Being Moderated
    How do I store the last used "username" so that it can be checked with the next incoming one?

    Cause trying something like this, doesn't seem to work. >>

    public class lCell extends ListCell<UserMessage> {
           String userTemp="";
    
    @Override
            public void updateItem(UserMessage item, boolean empty) {
              super.updateItem(item, empty);
                if (item != null)
                 {
                  StringBuilder sb = new StringBuilder();
                  if (!userTemp.equals(item.getUser()))
                  {
                      sb.append(item.getUser()).append(": \n");
                      userTemp=item.getUser();
                  }
                  sb.append(item.getMessage());
                  setText(sb.toString());
                }
                
            }
    }
    Wanted to print something like this:
    User1:
    msg1
    msg2
    msg3
    User2:
    msg1
    msg2
    User1:
    ...

    The above seems to print:
    User1:
    msg1
    User1:
    msg2
    User1:
    msg3
    User2:
    ...
  • 9. Re: Conditionally update the list cell
    JohnHendrikx Pro
    Currently Being Moderated
    Donot do this in your Cell, that won't work (they are drawn in random order)....

    Instead, when adding a new UserMessage, check if the previous one was of the same user... something like this:
    UserMessage lastUserMessage = userMessages.get(userMessages.size() - 1);
    
    if(lastUserMessage.getUser().equals(currentUser)) {
      lastUserMessage.append(message);
    }
    else {
      userMessages.add(new UserMessage(currentUser, message));
    }
  • 10. Re: Conditionally update the list cell
    941623 Newbie
    Currently Being Moderated
    What is userMessages?
  • 11. Re: Conditionally update the list cell
    941623 Newbie
    Currently Being Moderated
    Ok. userMessages is the ObservableList.

    If I want to append more messages to the last user-message pair, first of all 'append' won't work in this object. So even if I create a function append in the UserMessage class:
    public class UserMessage
    {
            ....
            public void append(String message){
                this.message.concat("\n"+message);
            }
    }
    I would still need to add it (in the object format) to the ObservableList.
    How would I reflect the above change (append) in the ObservableList?
    ...
    static currentUser=""; //global variable
    ...
    public void add(String user, String message)
     {
           if(!user.equals(currentUser))
           {
               obs.add(new UserMessage(user, message));
               currentUser=user;
           }
           else
           {
               UserMessage lastUserMessage = obs.get(obs.size() - 1);
               lastUserMessage.append(message);
              //How do I reflect this change in the ObservableList?
    
           }
    }
  • 12. Re: Conditionally update the list cell
    941623 Newbie
    Currently Being Moderated
    Got it. Got it.

    Stupid error.>>
    this.message=this.message.concat("\n"+message); 
    Answer to my question:
    ....
    else
           {
               UserMessage lastUserMessage = obs.get(obs.size() - 1);
               lastUserMessage.add(message);
               obs.set(obs.size() - 1, lastUserMessage);//Answer
           }

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points