首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >JXTreeTable、行条纹和适当的重绘

JXTreeTable、行条纹和适当的重绘
EN

Stack Overflow用户
提问于 2014-05-23 14:36:23
回答 1查看 564关注 0票数 1

默认情况下,我使用的是表行条带的外观和感觉。当我输入一个JXTreeTable时,我注意到由于某种原因,它没有自动得到行条。

所以我用荧光笔解决了这个问题,但是看起来我又出现了一个小故障:

似乎JXTreeTable只是在重新绘制文本的边界,而不是整个单元格。我一直试图在调试器中找到原因,但是每次我在程序之间切换时,整个窗口都会重新绘制,所以几乎不可能捕捉到这类事情。

JTableJTree都表现得很正常。这种外观和感觉描绘了JTree的整个行(比如Quaqua和Synth),所以这可能也与它有关。也许JXTreeTable有某种假设,即外观和感觉不会画出树的行?如果是的话,有没有办法解决这个问题?不仅仅是这种外观和感觉才是问题所在。

守则:

代码语言:javascript
复制
import org.jdesktop.swingx.JXTreeTable;
import org.jdesktop.swingx.decorator.AbstractHighlighter;
import org.jdesktop.swingx.decorator.ComponentAdapter;
import org.jdesktop.swingx.decorator.Highlighter;
import org.jdesktop.swingx.treetable.DefaultMutableTreeTableNode;
import org.jdesktop.swingx.treetable.DefaultTreeTableModel;
import org.jdesktop.swingx.treetable.TreeTableModel;
import org.trypticon.haqua.HaquaLookAndFeel;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import java.awt.BorderLayout;
import java.awt.Component;
import java.util.Arrays;

public class TreeTableDemo2 implements Runnable {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new TreeTableDemo2());
    }

    @Override
    public void run() {
        try {
            UIManager.setLookAndFeel(new HaquaLookAndFeel());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        JFrame frame = new JFrame("Tree Table Demo");
        frame.setLayout(new BorderLayout());
        frame.add(createPanel(), BorderLayout.CENTER);
        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

    public JPanel createPanel() {
        JPanel panel = new JPanel(new BorderLayout());

        TreeTableModel treeTableModel = new DummyTreeTableModel();
        JXTreeTable treeTable = new FixedTreeTable(treeTableModel);
        JScrollPane treeTableScroll = new JScrollPane(treeTable);

        panel.add(treeTableScroll, BorderLayout.CENTER);
        return panel;
    }

    private static class FixedTreeTable extends JXTreeTable {
        private static final Highlighter oddRowHighlighter = new AbstractHighlighter() {
            @Override
            protected Component doHighlight(Component component, ComponentAdapter componentAdapter) {
                if (componentAdapter.row % 2 != 0 &&
                        !componentAdapter.isSelected()) {
                    component.setBackground(UIManager.getColor("Table.alternateRowColor"));
                }
                return component;
            }
        };

        public FixedTreeTable(TreeTableModel treeModel) {
            super(treeModel);

            // This hack makes it paint correctly after releasing the mouse, which is not quite good enough.
//            getSelectionModel().addListSelectionListener(new ListSelectionListener() {
//                @Override
//                public void valueChanged(ListSelectionEvent e) {
//                    Rectangle repaintRange = getCellRect(e.getFirstIndex(), 0, true);
//                    repaintRange.add(getCellRect(e.getLastIndex(), 0, true));
//                    repaint(repaintRange);
//                }
//            });
        }

        @Override
        public void updateUI() {
            removeHighlighter(oddRowHighlighter);

            super.updateUI();

            // JTable does this striping automatically but JXTable's default renderer
            // seems to ignore it, so JXTreeTable inherits this broken behaviour.
            if (UIManager.get("Table.alternateRowColor") != null) {
                addHighlighter(oddRowHighlighter);
            }
        }
    }

    private static class DummyTreeTableNode extends DefaultMutableTreeTableNode {
        private final Object[] values;

        private DummyTreeTableNode(String name) {
            super(name);
            values = new Object[5];
            values[0] = name;
        }

        private DummyTreeTableNode(Object... values) {
            super(values[0]);
            this.values = values;
        }

        @Override
        public Object getValueAt(int column) {
            return values[column];
        }
    }

    private static class DummyTreeTableModel extends DefaultTreeTableModel {
        private static DefaultMutableTreeTableNode rootNode = new DefaultMutableTreeTableNode();
        static {
            DefaultMutableTreeTableNode blue = new DefaultMutableTreeTableNode("Blue");
            blue.add(new DummyTreeTableNode("Orionis C",          33000,  30000.0,    18.0,   5.90));
            rootNode.add(blue);

            DefaultMutableTreeTableNode bluish = new DefaultMutableTreeTableNode("Bluish");
            bluish.add(new DummyTreeTableNode("Becrux",             30000,  16000.0,    16.0,   5.70));
            bluish.add(new DummyTreeTableNode("Spica",              22000,  8300.0,     10.5,   5.10));
            bluish.add(new DummyTreeTableNode("Achernar",           15000,  750.0,      5.40,   3.70));
            bluish.add(new DummyTreeTableNode("Rigel",              12500,  130.0,      3.50,   2.70));
            rootNode.add(bluish);

            DefaultMutableTreeTableNode blueWhite = new DefaultMutableTreeTableNode("Blue-White");
            blueWhite.add(new DummyTreeTableNode("Sirius A",           9500,   63.0,       2.60,   2.30));
            blueWhite.add(new DummyTreeTableNode("Fomalhaut",          9000,   40.0,       2.20,   2.00));
            blueWhite.add(new DummyTreeTableNode("Altair",             8700,   24.0,       1.90,   1.80));
            rootNode.add(blueWhite);

            DefaultMutableTreeTableNode white = new DefaultMutableTreeTableNode("White");
            white.add(new DummyTreeTableNode("Polaris A",          7400,   9.0,        1.60,   1.50));
            white.add(new DummyTreeTableNode("Eta Scorpii",        7100,   6.3,        1.50,   1.30));
            white.add(new DummyTreeTableNode("Procyon A",          6400,   4.0,        1.35,   1.20));
            rootNode.add(white);

            DefaultMutableTreeTableNode yellowWhite = new DefaultMutableTreeTableNode("Yellow-White");
            yellowWhite.add(new DummyTreeTableNode("Alpha Centauri A",   5900,   1.45,       1.08,   1.05));
            yellowWhite.add(new DummyTreeTableNode("The Sun",            5800,   100.0,      1.00,   1.00));
            yellowWhite.add(new DummyTreeTableNode("Mu Cassiopeiae",     5600,   0.70,       0.95,   0.91));
            yellowWhite.add(new DummyTreeTableNode("Tau Ceti",           5300,   0.44,       0.85,   0.87));
            rootNode.add(yellowWhite);

            DefaultMutableTreeTableNode orange = new DefaultMutableTreeTableNode("Orange");
            orange.add(new DummyTreeTableNode("Pollux",             5100,   0.36,       0.83,   0.83));
            orange.add(new DummyTreeTableNode("Epsilon Eridani",    4830,   0.28,       0.78,   0.79));
            orange.add(new DummyTreeTableNode("Alpha Centauri B",   4370,   0.18,       0.68,   0.74));
            rootNode.add(orange);

            DefaultMutableTreeTableNode red = new DefaultMutableTreeTableNode("Red");
            red.add(new DummyTreeTableNode("Lalande 21185",      3400,   0.03,       0.33,   0.36));
            red.add(new DummyTreeTableNode("Ross 128",           3200,   0.0005,     0.20,   0.21));
            red.add(new DummyTreeTableNode("Wolf 359",           3000,   0.0002,     0.10,   0.12));
            rootNode.add(red);
        }

        private static final Object[] columnNames = {
                "Star", "Temperature (K)", "Luminosity", "Mass", "Radius"
        };

        public DummyTreeTableModel() {
            super(rootNode, Arrays.asList(columnNames));
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            if (columnIndex == 0) {
                return String.class;
            } else {
                return Double.class;
            }
        }

        @Override
        public boolean isCellEditable(Object node, int column) {
            return false;
        }
    }
}

进一步调查第1轮:

最后,我通过在JXTreeTable中查看paint方法,成功地捕获了调试器中的条件。我看到的是,它有一种叫做ClippedTreeCellRenderer的东西,它有一些看起来与可疑行为相对应的字段:

代码语言:javascript
复制
iconRect = {java.awt.Rectangle@2946}"java.awt.Rectangle[x=20,y=92,width=16,height=16]"
textRect = {java.awt.Rectangle@2947}"java.awt.Rectangle[x=20,y=-17,width=62,height=15]"
itemRect = {java.awt.Rectangle@2948}"java.awt.Rectangle[x=20,y=36,width=103,height=18]"

我还没有确认它确实使用这个值来绘制矩形,但是textRect正好是它重新绘制的小窗口的大小。所以现在的问题是,JXTreeTable到底是从哪里提取这些值的,为什么要使用它们呢?

我的直觉告诉我,JXTreeTable的渲染器在某种程度上使用树状细胞渲染器来直接渲染单元格,而不仅仅是让树自己绘制。绘制行背景和展开/折叠图标的逻辑是在树中,而不是在单元格中,所以如果它这样做,那么它没有一贯地绘制树就有意义了。

进一步调查第2轮:

我想我走错路了。看起来整行都正在绘制,但是tree.isPathSelected(路径)返回新选定的蓝色行的false,并为刚刚被选中的行返回true

我可以通过DefaultTreeSelectionModel中的断点来确认,只有在释放鼠标之后才更新树选择,这就是为什么它最终返回到正确呈现的原因。

我将深入研究JXTreeTable,看看它是如何保持这些同步的。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-05-24 04:31:19

我找到窃听器了。它看起来像是JXTreeTable.java中一些善意的代码,它试图减少更新:

代码语言:javascript
复制
    /**
     * Class responsible for calling updateSelectedPathsFromSelectedRows
     * when the selection of the list changse.
     */
    class ListSelectionHandler implements ListSelectionListener {
        @Override
        public void valueChanged(ListSelectionEvent e) {
            if (!e.getValueIsAdjusting()) {
                updateSelectedPathsFromSelectedRows();
            }
        }
    }

如果删除该if检查,一切都会正常工作。我想我只需要对SwingX做一些本地更改,因为这个项目基本上已经死了。:(

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23832023

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档