javatextboxzkitemrenderer

ZK - Accessing GUI elements from ItemRenderer


I am having problems accessing GUI elements outside the model class in my ZK project. I have a ListItemRenderer that renders the data and the position of the corresponding model when I click on an element in a list box, but my instance is permanently null when I access the article class again, as well as all GUI elements that I connect when I create the class for the first time (via getFellow ()). Is that even the right approach? Alternatively, could I add a listener to a variable that reloads the text box if it is changed? Thanks for every hint, I've already had several frustrating hours behind me and hope the code snippet is enough.

ZUL:

<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" root="./winArticles"?>
<window id="winArticles" title="Looking for Evidence" width="1100px"  height="880px" 
border="normal" use="xxx.Articles" closable="true" sizable="false">
...
 <listbox id="artikel_output" width="100%" height="" multiple="true"  
          checkmark="true"   vflex="true" nonselectableTags="*">
 <listhead>
      <listheader label="Artikel"/> 
 </listhead> 
 </listbox> 
...
      <div   vflex="1">
            <textbox style="font-size:50px" 
                     id="tb_article_abstract"
                     multiline="true"/>
     </div>
...
</window>

Model :

public class Articles extends Window implements AfterCompose, 
IGenericDomainValueSelectorActions, IUpdateModal, IGenericListActions {
     private static Articles instance;

public Articles() { }

public static Articles getInstance() { 
    if (instance == null) {
        instance = new Articles();
    }
    logger.debug("Instance getInstance " + instance.getId());
    return instance;
}

@Override
public void afterCompose() {
    instance = new Articles(); 
    tb_article_abstract = (Textbox) getFellow("tb_article_abstract");  
  ...}

Initializing the listbox renderer:

public void fillListBoxWithArticles(final Listbox lb, List<Article> articles) {  
    if (articles.size() == 0) {
        lb.appendChild((Component) articles.get(0));
    } 
    lb.setItemRenderer(new ArticleItemRenderer());        
    lb.setCheckmark(true);
    lb.setMultiple(true); 
    ListModelList<Article> lml_articles = new ListModelList<Article>(articles);
    lml_articles.setMultiple(true);
    lb.setModel(lml_articles); 
    lb.focus();
}

If a list box element has been selected, display an attribute of it in a text box, but the textbox is always null...

public void setArticleToInfobox(Article selectedArticle, int selectedIndex) {
    this.selectedArticle = selectedArticle;  
    // tb_article_abstract = null 
    tb_article_abstract.setValue(selectedArticle.getAbstract_full());
    tb_article_abstract.invalidate();
}}

The ItemRenderer is getting the data (and the index) of the selected Item:

public class ArticleItemRenderer implements ListitemRenderer<Article> {  
@Override
public void render(Listitem item, Article data, int index) throws Exception {

    item.appendChild(new Listcell(data.getArticletitle() + ", "  ); 
    item.addEventListener(Events.ON_CLICK, new EventListener() {
        @Override 
        public void onEvent(Event event) throws Exception {     
            EvidenceBasedArticles.getInstance().setArticleToInfobox(data, item.getIndex());
        }});}

Solution

  • You are making some crucial faults here.

    public static Articles getInstance() { 
        if (instance == null) {
            instance = new Articles();
        }
        logger.debug("Instance getInstance " + instance.getId());
        return instance;
    }
    

    This will never work good, you are developing a web application.
    This means that 2 users at the same time can have only 1 instance, however your Article is allocated to a specific Desktop, so 1 user will have problems.

    What's wrong with :

    lb.setItemRenderer(new ArticleItemRenderer(tb_article_abstract));
    

    Your renderer has a new instance for this specific class, so it's bound to the correct desktop.
    As long you don't remove that item from the DOM, this would be no problem to do.