Поместите JTable в JTree

в связи с потоком Jtable как узел Jtree я помещаю JTable в JTree, но JTree View неправильно отображается при запуске, как я могу setPreferredSize вместо JTable, потому что PreferredScrollableViewportSize сжался JTable с рендерингом TableHeader + один Row, один Row остаются скрытыми, но после расширения узлов TreeRenderer меняет и перерисовывает setPreferredSize до ожидаемого Dimension

введите здесь описание изображениявведите здесь описание изображения

import java.awt.*;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.tree.*;

public class TreeWithTableRenderer extends JFrame {

    private static final long serialVersionUID = 1L;
    private JTree tree;

    public TreeWithTableRenderer() {
        DefaultMutableTreeNode AA1 = new DefaultMutableTreeNode("AA1");
        DefaultMutableTreeNode AA2 = new DefaultMutableTreeNode("AA2");
        DefaultMutableTreeNode A = new DefaultMutableTreeNode("A");
        A.add(AA1);
        A.add(AA2);
        DefaultMutableTreeNode BB1 = new DefaultMutableTreeNode("BB1");
        DefaultMutableTreeNode BB2 = new DefaultMutableTreeNode("BB2");
        DefaultMutableTreeNode B = new DefaultMutableTreeNode("B");
        B.add(BB1);
        B.add(BB2);
        DefaultMutableTreeNode CC1 = new DefaultMutableTreeNode("CC1");
        DefaultMutableTreeNode CC2 = new DefaultMutableTreeNode("CC2");
        DefaultMutableTreeNode C = new DefaultMutableTreeNode("C");
        C.add(CC1);
        C.add(CC2);
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
        root.add(A);
        root.add(B);
        root.add(C);
        tree = new JTree(root);
        tree.setCellRenderer(new MyTableInTreeCellRenderer());
        tree.setRowHeight(0);
        JScrollPane jsp = new JScrollPane(tree);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        add(jsp, BorderLayout.CENTER);
        pack();
        setLocationRelativeTo(null);
    }

    class MyTableInTreeCellRenderer extends JPanel implements TreeCellRenderer {

        private static final long serialVersionUID = 1L;
        private JTable table;

        public MyTableInTreeCellRenderer() {
            super(new BorderLayout());
            table = new JTable();
            JScrollPane scrollPane = new JScrollPane(table);
            add(scrollPane);
        }

        public Component getTreeCellRendererComponent(JTree tree, Object value,
                boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
            final String v = (String) ((DefaultMutableTreeNode) value).getUserObject();
            table.setModel(new DefaultTableModel() {

                private static final long serialVersionUID = 1L;

                @Override
                public int getRowCount() {
                    return 2;
                }

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

                @Override
                public Object getValueAt(int row, int column) {
                    return v + ":" + row + ":" + column;
                }
            });
            table.setPreferredScrollableViewportSize(table.getPreferredSize());
            return this;
        }
    }

    public static void main(String[] args) throws Exception {
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                new TreeWithTableRenderer().setVisible(true);
            }
        });
    }
}

person mKorbel    schedule 12.01.2012    source источник


Ответы (2)


Избавьтесь от scrollPane, он все равно неработоспособен (пока я согласен с Расселом :-) и добавьте таблицу и ее заголовок на панель, используя соответствующий LayoutManager:

public MyTableInTreeCellRenderer() {
    super();
    setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
    table = new JTable();
    add(table.getTableHeader());
    add(table);
}

вам, вероятно, нужно немного настроить визуальные эффекты, левая и верхняя линии границы отсутствуют - не совсем уверен, какой компонент рисует их нормально, может быть scrollPane

Изменить

Забыли: причина запроса prefSize scrollPane при вычислении требуемого размера (сделанного в делегате пользовательского интерфейса, а именно VariableHeightLayoutCache) компонента рендеринга заключается в том, что scrollPane еще не настроен с заголовком. Запрос выполняется до добавления панели в rendererPane, полная конфигурация выполняется в addNotify таблицы, что происходит только после добавления панели в иерархию.

person kleopatra    schedule 13.01.2012
comment
мне не нужен там JScrollPane по умолчанию, хм, удалите JScrollPane, я думаю, что это неправильное предложение, потому что этот JTable может иметь одну строку, такую ​​же, как 5T Rows, не имеет значения, я забыл для stackoverflow.com/questions/7369814/, спасибо - person mKorbel; 13.01.2012

Вы можете просто избавиться от ScrollPane и разместить заголовок и таблицу непосредственно на панели (с помощью null LayoutManager, чтобы вы могли контролировать все самостоятельно):

static class TableTreeCellRenderer extends JPanel implements TreeCellRenderer {
    private final JTable table;

    TableTreeCellRenderer() {
        table = new JTable();
        setLayout(null);
        add(table.getTableHeader());
        add(table);
    }

    public Dimension getPreferredSize() {
        Dimension headerSize = table.getTableHeader().getPreferredSize();
        Dimension tableSize = table.getPreferredSize();

        return new Dimension(Math.max(headerSize.width, tableSize.width),
                headerSize.height + tableSize.height);
    }

    public void setBounds(int x, int y, int width, int height) {
        super.setBounds(x, y, width, height);
        int headerHeight = table.getTableHeader().getPreferredSize().height;
        table.getTableHeader().setBounds(0, 0, width, headerHeight);
        table.setBounds(0, headerHeight, width, height - headerHeight);
    }

    public Component getTreeCellRendererComponent(JTree tree, Object value,
            boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
        final String v = (String) ((DefaultMutableTreeNode) value).getUserObject();
        table.setModel(new DefaultTableModel(new Object[][] { 
                { v + "0", "1" },
                { v + "2", "3" }
        }, new Object[] { "id", "value" } ));
        invalidate();
        return this;
    }
}
person Russell Zahniser    schedule 13.01.2012
comment
согласен с @kleopatra, но спасибо за (остальное) table.getTableHeader().getPreferredSize(); +1 - person mKorbel; 13.01.2012
comment
@kleopatra: Обычно нулевой LayoutManager был бы взломом, но, учитывая, что это штамп, а не реальный компонент, который живет в иерархии, я думаю, что никакого вреда не будет. - person Russell Zahniser; 14.01.2012
comment
не имеет значения, где он не используется, дублирование кода (== захват ответственности другого класса путем ручного кодирования) всегда является худшим возможным запахом. Это пустая трата времени на написание и трата времени ваших коллег во время технического обслуживания на чтение и попытки понять, почему, черт возьми, вы не придерживаетесь лучших практик ... - person kleopatra; 14.01.2012
comment
@kleopatra Я полностью согласен, и это то, с чем я боролся со своим кодом последние пару лет, это большое приложение на основе графического интерфейса, использующее нулевой макет везде - person Ashish; 10.05.2013