How to calibrate rows dimension of TreeTable & HierarchicalContainer

in my project I have a Table (number 1) into panel CRUD with correct rows dimension, but in other view I have a TreeTable with HierarchicalContainer and Item Iterface to compose TreeTable (number 2) with too large rows.

I need to have same dimension of Table number 1 (or like your demo.vaadin example, number 3).
Please someone can help me?

here the code and the image attached :

private void loadArticlesTree(TreeTable treeToCompile) {
    try {
        LOGGER.info("Loading article tree...");
        
        treeToCompile.addContainerProperty("CATEGORIE", String.class, "");
        
        HierarchicalContainer hc = new HierarchicalContainer();
        hc.addContainerProperty("CATEGORIE", String.class, "");
        
        // load Parent Categories
        List<ObjectType> objTypeCategory = rvdbManager.getArticleUtils().getMacroCategory();
        for (ObjectType cat : objTypeCategory) {

            //Create parent macro category ObjectType with children
            Item categoryItem = hc.addItem(cat);
            categoryItem.getItemProperty("CATEGORIE").setValue(cat.getName());
            hc.setChildrenAllowed(cat, true);
            
            for (Article article : rvdbManager.getArticleUtils().getArticlesByCategory(cat)) {
                Item addItem = hc.addItem(article);
                addItem.getItemProperty("CATEGORIE").setValue(article.getName());
                hc.setParent(article, cat);
                hc.setChildrenAllowed(article, false);
            }
        
        } // end for each Article categories
        
        treeToCompile.setContainerDataSource(hc);
        LOGGER.info("Loaded article tree...");
        
        // (item, false) TO EXPAND ALL ITEMS BY DEFAULT
        // (item, true) TO COLLAPSE ALL ITEMS BY DEFAULT
        for(Object item : tree.getItemIds().toArray()) tree.setCollapsed(item, true);
        
    } catch (Exception e) {
        LOGGER.info("Error loading article tree: {}", e.getCause(), e);
        WebAppNotifier.notify(e);
    }
}

32601.jpg

Hi,

try setting the following in your theme .scss file (replace 20px with the height you want):

.v-table-cell-content { height: 20px; } Best regards,

Olli

Thanks a lot Olli,

can I ask you some patience and help me understand how and where to apply this change,
I’m not very experienced at CSS in maven complex projects.

Thanks to the availability

This Is a TreeTable (not a normal Table)… i understood well your suggest?

is possible too expand parent item by pressing rows and not only triangles?

see the image attached please

Thanks!!!

33406.png

Hi,

same should work for regular Table and TreeTable. Read the docs here for more information on theming: https://vaadin.com/docs/-/part/framework/themes/themes-creating.html

You could try expanding items from row clicks by adding an item click listener with addItemClickListener and expanding the rows in code in the handler.

Best regards,

Olli

Hi Olli, THANKS FOR YOUR REPLY, AND THANK YOU FOR YOUR AVAIABILITY



thi is the method code used to complete UI of view, it’s correct

[color=#0000FF]
private void completeUI() {

    tree = new TreeTable();
    tree.setWidth("100%");
    tree.setMultiSelect(true);
    tree.addValueChangeListener(event -> { 
        
        Object value = event.getProperty().getValue();
        if ( event.getProperty() == null || value == null) {
            return;
        }
        
        if (value instanceof Collection){
        
            List<Article> selectedArticles = new ArrayList<Article>((Collection<Article>) value);
            if ( !validArticle(selectedArticles)) {
                return;

[/color]
[color=#FF0000]
[b]
it’s correct that HERE I MUST INTERCEPT addItemClickListener ???
WICH METHOD I MUST CALL???
tree.addItemClickListener(event → {

                          toggleChildVisibility(Object itemId,
                            boolean forceFullRefresh) { 
                         
                           changeVariables(Object source, Map<String, Object> variables)
                }

[/b]
[/color]

[color=#0000FF]
// public void changeVariables(Object source, Map<String, Object> variables) {
// super.changeVariables(source, variables);
//
// Object objx = returnObjectArticle(selectedArticles);
//
// if (objx != null) tree.toggleChildVisibility( objx, false);
// else return;

            }
                            
            try {
                controller.setSelectedArticle(selectedArticles);
            } catch (Exception e) {
                WebAppNotifier.notify(e);
            }
        } else return;
    });

// if (getEditor() != null) {
//
// table.addItemClickListener((ItemClickListener) itemClickEvent → {
//
// if (!table.isSelected(itemClickEvent.getItemId())) {
// activeEditor();
// getEditor().edit(itemClickEvent.getItem());
// } else {
// deactiveEditor();
// getEditor().edit(null);
// }
//
// });
[/color]



I MUST CALL THIS IS METHOD OF TableTree.class (Vaadin pattern)

private void toggleChildVisibility(Object itemId,
boolean forceFullRefresh) {
getContainerStrategy().toggleChildVisibility(itemId);
// ensure that page still has first item in page, DON’T clear the
// caches.
setCurrentPageFirstItemIndex(getCurrentPageFirstItemIndex(), false);

    if (isCollapsed(itemId)) {
        fireCollapseEvent(itemId);
    } else {
        fireExpandEvent(itemId);
    }

    if (containerSupportsPartialUpdates && !forceFullRefresh) {
        markAsDirty();
    } else {
        // For containers that do not send item set change events, always do
        // full repaint instead of partial row update.
        refreshRowCache();
    }
}



OR I MUST CALL THIS METHOD TableTree.class (Vaadin pattern)

@Override
public void changeVariables(Object source, Map<String, Object> variables) {
super.changeVariables(source, variables);

    if (variables.containsKey("toggleCollapsed")) {
        String object = (String) variables.get("toggleCollapsed");
        Object itemId = itemIdMapper.get(object);
        toggledItemId = itemId;
        toggleChildVisibility(itemId, false);
        if (variables.containsKey("selectCollapsed")) {
            // ensure collapsed is selected unless opened with selection
            // head
            if (isSelectable()) {
                select(itemId);
            }
        }
    } else if (variables.containsKey("focusParent")) {
        String key = (String) variables.get("focusParent");
        Object refId = itemIdMapper.get(key);
        Object itemId = getParent(refId);
        focusParent(itemId);
    }
}

Hi,

You probably don’t want to add an item click listener inside the value change listener. Just do it in the same level.

For expanding / collapsing items in the item click listener, try
treeTable.setCollapsed(Object itemId, boolean collapsed)
, where the second parameter is
true
if you want to collapse the item and
false
if you want to expand it. You can get the expanded/collapsed status of the current item with
treeTable.isCollapsed(Object itemId)
, so if you want to toggle the status, you can do it with
treeTable.setCollapsed(itemId, !treeTable.isCollapsed(itemId));

You’ll get the itemId from the event object.

-Olli


Yes Thank you, actually debugging my appIications I noticed that pressing the triangle of the TreeTable is called the method


changeVariables(Object source, Map<String, Object> variables)


that call


toggleChildVisibility(Object itemId, boolean forceFullRefresh)


Where state control is handled

[color=#000000]

[/color]

if (isCollapsed(itemId)) {
fireCollapseEvent(itemId);
} else {
fireExpandEvent(itemId);
}

[color=#FF0000]
I would not skip some passage … so it’s correct to apply your suggestion directly?

Thank you very much, I hope That I’m not exaggerating to use your support give here, in the forum it’s correct about?

Sorry for my English if i’m not Immediately clear.
[/color]

Hi,

you don’t need to imitate the client when doing server side actions - the correct actions, like updating state, should happen when using the normal server side api.

-Olli

Vaadin is great!!!
but I’m not so good at using these features yet.

Unfortunately my programmer, who is now not available, handled me things this way,

This TreeTable you see in attached file handled for select any item by this addValueChangeListener method (event → {
And when I hit a item I always go inside this method and I do not go to the addItemClickListener (ClickListener) event
at the same level
but why???
so i try to change addValueChangeListener method (event →
with addItemClickListener (ClickListener) event

I do not understand anything anymore
what can i do about?

here the code

private void completeUI() {

    tree = new TreeTable();
    tree.setWidth("100%");
    tree.setMultiSelect(true);

// tree.addValueChangeListener(event → {
tree.addItemClickListener(( ClickListener) event → {

        Object value = event.getProperty().getValue();
        if ( event.getProperty() == null || value == null) {
            return;
        }
        
        if (value instanceof Collection){
        
            List<Article> selectedArticles = new ArrayList<Article>((Collection<Article>) value);
            if ( !validArticle(selectedArticles)) {
                   tree.setCollapsed(event, tree.isCollapsed((Object) event));
                    return;                    
            }
                            
            try {
                controller.setSelectedArticle(selectedArticles);
            } catch (Exception e) {
                WebAppNotifier.notify(e);
            }
        } else return;
    });

// tree.addItemClickListener((ItemClickListener) itemClickEvent → {
//
// // togliere altri prodotti ed alla consegna di RCR
// if (RVMobileUI.getCurrent_().getMyConfiguration().getLogoFileName().equalsIgnoreCase(“logorcr”)
// || RVMobileUI.getCurrent_().getMyConfiguration().getLogoFileName().equalsIgnoreCase(“logorcrgenerico”)) {
// return;
// }
//
// treeTable.setCollapsed(Object itemId, boolean collapsed);
// treeTable.isCollapsed(Object itemId);
//
// if (!tree.isSelected(itemClickEvent.getItemId())) {
//
// tree.setCollapsed(itemClickEvent, !tree.isCollapsed(itemClickEvent.getItemId()));
//
// } else {
//
// tree.setCollapsed(itemClickEvent, !tree.isCollapsed(itemClickEvent.getItemId()));
//
// }
//
//
//
//
//// } else return;
// });

    tree.addGeneratedColumn("AGG", (source, itemId, columnId) -> {
        
        if ( itemId instanceof ObjectType) {
            return null;
        }
        
        Article a = (Article) itemId;
        
        if (a.getIdType().getIdParent() == null) {
            return null;
        }
        
        BigCheckBox b = new BigCheckBox();
        b.setSplitPosition(0, true);
        b.getCb().setSizeFull();
        b.setWidth("60");
        b.setHeight("60");
        b.setIcon(FontAwesome.PLUS);
        b.setValue(controller.isSelected(a));
        b.addClickListener(event-> {
            
            try {
                if (b.booleanValue()) {
                    controller.addSelectedArticle(a);
                } else {
                    controller.removeSelectArticle(a);
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
        });
        return b;
        
    });
    
    tree.setColumnExpandRatio("CATEGORIE", 1);
    tree.setColumnWidth("AGG", 60);
    
    loadArticlesTree(tree);
    
    setCaption("ORDINA DAGLI ARTICOLI DISPONIBILI");
    setStyleName(DESIGN_ATTR_PLAIN_TEXT);
    
    setSizeFull();
    setResponsive(true);
    
    Panel pTree = new Panel(tree);
    pTree.addStyleName(ValoTheme.PANEL_BORDERLESS);
    pTree.setSizeFull();
    
    VerticalSplitPanel vl = new VerticalSplitPanel(buildSearchTF(), pTree);
    vl.setSizeFull();
    vl.setSplitPosition(59, Unit.PIXELS);
    setContent(vl);
}

SO I NEED TO IMPLEMENT THIS COLLAPSE OR EXPAND INTO THIS METHOD
I DON’T KNOW HOW CAN I DO OTHERELSE

INSIDE

tree.addValueChangeListener(event → {

if (value instanceof Collection){

            List<Article> selectedArticles = new ArrayList<Article>((Collection<Article>) value);
            [color=#FF0000]

if ( !validArticle(selectedArticles)) {
tree.setCollapsed(event, tree.isCollapsed((Object) event));
return;
}
[/color]

            try {
                controller.setSelectedArticle(selectedArticles);
            } catch (Exception e) {
                WebAppNotifier.notify(e);
            }
        } else return;

Please Olli
help me because I am confused

I made this sample project where you can click on items and expand/collapse them without using the triangle:
https://github.com/OlliTietavainen/treetable-open-on-click

-Olli

Hi Olli,
Thank you very much for the example you created for me, I understood as already from your posts,

Unfortunately my programmer, with whom I speak little today, has given me several problems, has made complicated technical choices and I do not understand all of them,

I have attached the method because for the object you see in the attached image has chosen the

tree.addValueChangeListener (event → {


And not the



Ttable.addItemClickListener (event → {
Object itemId = event.getItemId ();
Ttable.setCollapsed (itemId,! Ttable.isCollapsed (itemId));
});

As indicated by you, so I am in the conception that clikkando on the item is always called

addValueChangeListener (event → {

[b]
How can I integrate the listed listener in the code I am?

Sorry if I insist but I do not understand how to do … can you still help me with courtesy?

Thanks a lot, I attach the .java file of the whole class

MARKED TEXT COLOR PINK AND UNDERLINE, POINT WHERE I MUST IMPLEMENT COLLAPSE OR EXPAND FOR ITEM, BECAUSE THE LISTENER ENTER ALWAYS IN tree.addValueChangeListener(event → { AND I DON’T KNOW WHY???
[/b]



VERY THANKS OLLI

package rv.mobile.components;

import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.slf4j.Logger;

import com.vaadin.data.Item;
import com.vaadin.data.util.HierarchicalContainer;
import com.vaadin.data.util.filter.SimpleStringFilter;
import com.vaadin.server.FontAwesome;
import com.vaadin.ui.Component;
import com.vaadin.ui.Panel;
import com.vaadin.ui.Tree;
import com.vaadin.ui.TreeTable;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.VerticalSplitPanel;
import com.vaadin.ui.themes.ValoTheme;

import my.vaadin.WebAppLoggerFactory;
import my.vaadin.components.BigCheckBox;
import my.vaadin.components.BigTextField;
import my.vaadin.components.WebAppNotifier;
import rv.db.RVDBManager;
import rv.db.entity.Article;
import rv.db.entity.ObjectType;
import rv.mobile.controller.RVMobileWebAppController;
import rv.mobile.controller.RVNewRequestController;

public class RVArticleTreeTable extends Panel {

private static final long serialVersionUID = 5929096408810161546L;

private final Logger LOGGER = WebAppLoggerFactory.getLogger(RVArticleTreeTable.class);

private TreeTable tree;
private RVDBManager rvdbManager;

private RVNewRequestController controller;


public RVArticleTreeTable(RVNewRequestController controller) {
    super();
    this.controller = controller;
    try {
        this.rvdbManager = RVMobileWebAppController.getRVDBManager();
    } catch (SQLException e) {
        WebAppNotifier.notify(e);
    }

    completeUI();
}

private void completeUI() {
    
    tree = new TreeTable();
    tree.setWidth("100%");
    tree.setMultiSelect(true);
    tree.addValueChangeListener(event -> { 
     
        Object value = event.getProperty().getValue();
        if ( event.getProperty() == null || value == null) {
            return;
        }
        
        if (value instanceof Collection){
        
            List<Article> selectedArticles = new ArrayList<Article>((Collection<Article>) value);
            if ( !validArticle(selectedArticles)) {
         [color=#EE82EE]




return;



[/color]
}

            try {
                controller.setSelectedArticle(selectedArticles);
            } catch (Exception e) {
                WebAppNotifier.notify(e);
            }
        } else return;
    });

    
    tree.addGeneratedColumn("AGG", (source, itemId, columnId) -> {
        
        if ( itemId instanceof ObjectType) {
            return null;
        }
        
        Article a = (Article) itemId;
        
        if (a.getIdType().getIdParent() == null) {
            return null;
        }
        
        BigCheckBox b = new BigCheckBox();
        b.setSplitPosition(0, true);
        b.getCb().setSizeFull();
        b.setWidth("60");
        b.setHeight("60");
        b.setIcon(FontAwesome.PLUS);
        b.setValue(controller.isSelected(a));
        b.addClickListener(event-> {
            
            try {
                if (b.booleanValue()) {
                    controller.addSelectedArticle(a);
                } else {
                    controller.removeSelectArticle(a);
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
        });
        return b;
        
    });
    
    tree.setColumnExpandRatio("CATEGORIE", 1);
    tree.setColumnWidth("AGG", 60);
    
    loadArticlesTree(tree);
    
    setCaption("ORDINA DAGLI ARTICOLI DISPONIBILI");
    setStyleName(DESIGN_ATTR_PLAIN_TEXT);
    
    setSizeFull();
    setResponsive(true);
    
    Panel pTree = new Panel(tree);
    pTree.addStyleName(ValoTheme.PANEL_BORDERLESS);
    pTree.setSizeFull();
    
    VerticalSplitPanel vl = new VerticalSplitPanel(buildSearchTF(), pTree);
    vl.setSizeFull();
    vl.setSplitPosition(59, Unit.PIXELS);
    setContent(vl);
}


private boolean validArticle(List<Article> selectedArticles) {
    for ( Object check : selectedArticles) {
        if ( !(check instanceof Article)) {
            return false;
        }
    }
    return true;
}

private Object returnObjectArticle(List<Article> selectedArticles) {
    for ( Object check : selectedArticles) {
        if ( !(check instanceof Article)) {
            return check;
        }
    }
    return null;
}

/**
 * @return
 */
private Component buildSearchTF() {
    BigTextField tf = new BigTextField(true);
    tf.setWidth("100%");
    //tf.setHeight("70");
    tf.setInputPrompt("Ricerca articoli");
    tf.addStyleName(ValoTheme.TEXTFIELD_BORDERLESS);
    tf.addTextChangeListener(event -> {
        
        HierarchicalContainer treeContainer = (HierarchicalContainer) tree.getContainerDataSource();
        treeContainer.removeAllContainerFilters();
        if (event.getText().isEmpty()) {
            return;
        }
        
        treeContainer.setIncludeParentsWhenFiltering(true);

        // Create a new filter which ignores case and only matches String prefix
        //SimpleStringFilter filter = new SimpleStringFilter("CATEGORIE", event.getText(), true, true);

        // Add the new filter
        treeContainer.addContainerFilter(new SimpleStringFilter("CATEGORIE", event.getText(), true, false));
        
    });
    
    VerticalLayout vl = new VerticalLayout(tf);
    //vl.setMargin(true);
    //vl.setSizeFull();
    return vl;
}

/**
 * @param articles
 * @throws Exception 
 */
private void loadArticlesTree(TreeTable treeToCompile) {
    try {
        LOGGER.info("Loading article tree...");
        
        treeToCompile.addContainerProperty("CATEGORIE", String.class, "");
        
        HierarchicalContainer hc = new HierarchicalContainer();
        hc.addContainerProperty("CATEGORIE", String.class, "");
        
        // load Parent Categories
        List<ObjectType> objTypeCategory = rvdbManager.getArticleUtils().getMacroCategory();
        for (ObjectType cat : objTypeCategory) {

            //Create parent macro category ObjectType with children
            Item categoryItem = hc.addItem(cat);
            categoryItem.getItemProperty("CATEGORIE").setValue(cat.getName());
            hc.setChildrenAllowed(cat, true);
            
            //Create children article for this category

// String article = "Articolo 1 di " + cat.getName();
// hc.addItem(article);
// hc.setParent(article, cat);

            for (Article article : rvdbManager.getArticleUtils().getArticlesByCategory(cat)) {
                Item addItem = hc.addItem(article);
                addItem.getItemProperty("CATEGORIE").setValue(article.getName());
                hc.setParent(article, cat);
                hc.setChildrenAllowed(article, false);
            }
            
            
            
            // select * from object_type o where o.idparent = cats.id;                

// for (Article articleForCategory : rvdbManager.getObjectTypeUtils().get(cats.getName(), cats.getObjectTable(), //cats.getIdParent())) {
// completeCategory(articleForCategory, false, treeToCompile);
// }
//
// for (Article article : rvdbManager.getArticleUtils().getArticles()) {
// completeCategory(article, false, treeToCompile);
// }

        } // end for each Article categories
        
        treeToCompile.setContainerDataSource(hc);
        LOGGER.info("Loaded article tree...");
        
        //EXPAND ALL NOTES FOR CATEGORIES

// for (ObjectType cat : tree.get) {
// //treeToCompile.expandItemsRecursively(cat);
// }

        // (item, false) TO EXPAND ALL ITEMS BY DEFAULT
        // (item, true) TO COLLAPSE ALL ITEMS BY DEFAULT
        for(Object item : tree.getItemIds().toArray()) tree.setCollapsed(item, true);
        
    } catch (Exception e) {
        LOGGER.info("Error loading article tree: {}", e.getCause(), e);
        WebAppNotifier.notify(e);
    }
}


protected void completeCategory(Article article, boolean haveChilds, Tree treeToCompile) {
    Item addItem = treeToCompile.addItem(article);
    addItem.getItemProperty("CATEGORIE").setValue(article.getName());
    
    treeToCompile.setItemCaption(article, article.getName());
    treeToCompile.setChildrenAllowed(article, haveChilds);
    treeToCompile.expandItem(article); // Expand programmatically
}

}

when i check on triangle item parent,
or i check on item parent row,
or i check on item child

the listener that respond is

tree.addValueChangeListener(event → {

        Object value = event.getProperty().getValue();
        if ( event.getProperty() == null || value == null) {
            return;
        }
        
        if (value instanceof Collection){
        
            List<Article> selectedArticles = new ArrayList<Article>((Collection<Article>) value);
            if ( !validArticle(selectedArticles)) {





HERE CONTROL IF ITEM IS ARTICLE CHECK BY SQUARE CHECK, OR ITEM PARENT ROW,
IF I CHECKED IN ROW CHILD AND DO NOTHIG




return;
}

            try {
                controller.setSelectedArticle(selectedArticles);
            } catch (Exception e) {

33414.png

If I understand you correctly, you want to stop expanding the row if the validity check fails? I would maybe rather then do that in an ExpandListener - if trying to expand a node that’s not supposed to expand, just collapse it immediately.

-Olli

No, I did not explain it well.

I need to collapse parent item lines if I press on the line besides the triangle, but I didn’t call the event suggest by you

Ttable.addItemClickListener (event → {
Object itemId = event.getItemId ();
Ttable.setCollapsed (itemId,! Ttable.isCollapsed (itemId));
});

because for all click the class enter in method

tree.addValueChangeListener(event → {

and here is the point of control if click occurred on child row article OR PARENT ROW and that the application do nothing

List selectedArticles = new ArrayList((Collection) value);
if ( !validArticle(selectedArticles)) {
HERE CONTROL IF ITEM IS ARTICLE CHECK BY SQUARE CHECK, OR ITEM PARENT ROW,
IF I CHECKED IN ROW CHILD AND DO NOTHIG
return;
}

I need to change with coillapse the item parent row if this is expanded or expand viceversa

Okay, so you want to collapse parent item lines? Like close all of the root items except the current one? I’m not sure 100% what the behavior should look like, but think you should try work from the top down in that case - maybe externalize the object tree structure and travel that to see which nodes should be expanded and which should be collapsed. Sorry I can’t be of more specific help here, but that’s the best I can think of right now.

-Olli