javaswingswingxjtreetable

JXTreeTable: how to use ComponentProvider to set the renderer for one column


I'm using JXTreeTable to display some data and I want to use the provided mechanisms of SwingX to change the renderer for some columns.

I previously used a JXTable and custom implementations of TableCellRenderer but this doesn't work anymore (I see strings where I should have progress bars, buttons,...).

I thus tried to achieve what I want by doing:

examsTable.getColumn(6).setCellRenderer(new DefaultTableRenderer(new ButtonProvider()));

But the overriden method createRenderer of ComponentProvider is called once (even when I have more than one line in my JXTreeTable) and no button is shown (the method only contains return new JButton();).

Thanks!

Edit> Hoped you would answer kleopatra and thus happy you did.

I did my best but somehow the table is not displayed. I guess I forgot something (I'm a C++ developer new to Java) but I guess it's not a serious problem and it's probably not related to my main problem.

import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import org.jdesktop.swingx.JXTreeTable;
import org.jdesktop.swingx.decorator.HighlighterFactory;
import org.jdesktop.swingx.renderer.CellContext;
import org.jdesktop.swingx.renderer.ComponentProvider;
import org.jdesktop.swingx.renderer.DefaultTableRenderer;
import org.jdesktop.swingx.treetable.AbstractTreeTableModel;

public class Test extends JFrame {
    JXTreeTable table = new JXTreeTable();
    JPanel panel = new JPanel();

    public Test() {
        setMinimumSize(new Dimension(400, 400));

        table.setEditable(false);
        table.setDragEnabled(false);
        table.setColumnSelectionAllowed(false);
        table.setHighlighters(HighlighterFactory.createAlternateStriping());
        table.setRowHeight(20);
        table.setMinimumSize(new Dimension(200, 200));

        class Series {
            public String seriesInstanceUID;
            public String patientName;
            public String patientBirthDate;
            public String securityToken;

            public Series(String seriesInstanceUID, String patientName, String patientBirthDate, String securityToken) {
                this.seriesInstanceUID = seriesInstanceUID;
                this.patientName = patientName;
                this.patientBirthDate = patientBirthDate;
                this.securityToken = securityToken;
            }
        }

        class Study {
            public List<Series> series = new ArrayList<Series>();
        }

        class Root {
            public List<Study> studies = new ArrayList<Study>();
        }

        AbstractTreeTableModel model = new AbstractTreeTableModel() {
            Root root = new Root() {
                {
                    studies.add(new Study() {
                        {
                            series.add(new Series("Series 1.1", "Mr. X", "1988-10-23", "sec-xx-1"));
                            series.add(new Series("Series 1.2", "Mr. X", "1988-10-23", "sec-xx-2"));
                            series.add(new Series("Series 1.3", "Mr. X", "1988-10-23", "sec-xx-3"));
                        }
                    });
                    studies.add(new Study() {
                        {
                            series.add(new Series("Series 2.1", "Mrs. Y", "1960-02-11", "sec-yy-1"));
                        }
                    });
                    studies.add(new Study() {
                        {
                            series.add(new Series("Series 3.1", "HAL 9000", "1975-04-21", "sec-zz-1"));
                            series.add(new Series("Series 3.2", "HAL 9000", "1975-04-21", "sec-zz-2"));
                        }
                    });
                }
            };

            @Override
            public String getColumnName(int columnIndex) {

                switch (columnIndex) {
                case 0:
                    return "Series Instance UID";

                case 1:
                    return "Patient Name";

                case 2:
                    return "Patient Birth Date";

                case 3:
                    return "View online";

                default:
                    return "";
                }
            }

            @Override
            public int getIndexOfChild(Object parent, Object child) {
                if (parent == root) {
                    return root.studies.indexOf(child);
                }

                if (parent instanceof Study) {
                    Study study = (Study) parent;

                    return study.series.indexOf(child);
                }

                return -1;
            }

            @Override
            public int getChildCount(Object parent) {
                if (parent == root) {
                    return root.studies.size();
                }

                if (parent instanceof Study) {
                    Study study = (Study) parent;

                    return study.series.size();
                }

                return 0;
            }

            @Override
            public Object getChild(Object parent, int index) {
                if (parent == root) {
                    return root.studies.get(index);
                }

                if (parent instanceof Study) {
                    Study study = (Study) parent;

                    return study.series.get(index);
                }

                return null;
            }

            @Override
            public Object getValueAt(Object node, int columnIndex) {
                if (!(node instanceof Series) && !(node instanceof Study))
                    return null;

                if (columnIndex < 0 || columnIndex >= getColumnCount())
                    return null;

                if (root == null)
                    return null;

                if (node instanceof Series) {
                    Series series = (Series) node;

                    if (columnIndex == 0)
                        return series.seriesInstanceUID;
                    else if (columnIndex == 1)
                        return series.patientName;
                    else if (columnIndex == 2)
                        return series.patientBirthDate;
                    else if (columnIndex == 3)
                        return series.securityToken;
                } else if (node instanceof Study) {
                    // Empty for now
                }

                return null;
            }

            @Override
            public int getColumnCount() {
                return 4;
            }

            @Override
            public Object getRoot() {
                return root;
            }

            public void update() {
                modelSupport.fireNewRoot();
            }
        };

        table.setTreeTableModel(model);

        table.getColumnModel().getColumn(3).setCellRenderer(new DefaultTableRenderer(new ComponentProvider<JButton>() {
            {
                rendererComponent.setHorizontalAlignment(JButton.CENTER);
            }

            @Override
            protected void format(CellContext context) {
                rendererComponent.setText(getValueAsString(context));
            }

            @Override
            protected void configureState(CellContext context) {
                rendererComponent.setHorizontalAlignment(getHorizontalAlignment());
            }

            @Override
            protected JButton createRendererComponent() {
                return new JButton("View online");
            }
        }));

        panel.add(table);
        this.setContentPane(panel);
    }

    public static void main(String[] args) {
        (new Test()).setVisible(true);
    }
}

EDIT> I actually have observed that it works. But not the way I want. I want to see a real button (now it looks just a little bit different from the rest of the line), know the path to it (parent object and column index) and see effects when clicking or hovering on it (button should look pressed,...).

How do I achieve that?


Solution

  • The button is used, it only appears not to be in some LAFs:-)

    Technically, the reasons are

    In combination the button doesn't look like a button for Metal (while it is unchanged f.i. in Windows)

    No satisfying solution, options are