1

皆さん、

グラデーション JTree コントロールを作成しようとしています。次のコードは、ツリー セルの背景が透明でないことを除いて、ほとんど機能します。誰かが電話して、私が正しく行っていないことを教えていただければ幸いです.

よろしくお願いいたします。

よろしく、
ピーター


package TestPackage;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import java.awt.*;

public class Test {

    public Test() {
        JFrame frame = new JFrame();

        JPanel framePanel = new JPanel();
        framePanel.setLayout(new BorderLayout());
        frame.setContentPane(framePanel);


        DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("Item");
        DefaultMutableTreeNode childNode = new DefaultMutableTreeNode("Child");
        rootNode.add(childNode);

        GradientTree tree = new GradientTree(rootNode);
        // JTree tree = new JTree(rootNode);
        // tree.setBackground(Color.blue);
        tree.setCellRenderer(new MyRenderer());

        JScrollPane scroll = new JScrollPane(tree);
        scroll.setOpaque(false);
        framePanel.add(scroll, BorderLayout.CENTER);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

    }

    public static void main(String[] args) {

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new Test();
            }
        });
    }


    @SuppressWarnings("serial")
    public static class GradientTree extends JTree {

        public GradientTree(DefaultMutableTreeNode node) {
            super(node);
        }


        @Override
        protected void paintComponent(Graphics g) {

            int h = getHeight();
            int w = getWidth();

            GradientPaint gradientPaint = new GradientPaint(0, 0, Color.LIGHT_GRAY, 0, h, Color.WHITE);

            Graphics2D g2D = (Graphics2D) g;
            g2D.setPaint(gradientPaint);
            g2D.fillRect(0, 0, w, h);

            this.setOpaque(false);
            super.paintComponent(g);
            this.setOpaque(true);
        }
    }

    @SuppressWarnings({"serial" })
    private class MyRenderer extends DefaultTreeCellRenderer {
        public MyRenderer() {
            this.setOpaque(false);
            this.setForeground(Color.RED);
        }

        public Component getTreeCellRendererComponent(
                JTree tree,
                Object value,
                boolean sel,
                boolean expanded,
                boolean leaf,
                int row,
                boolean hasFocus) {

            super.getTreeCellRendererComponent(
                    tree, value, sel,
                    expanded, leaf, row,
                    hasFocus);

            return this;
        }
    }
}

4

4 に答える 4

5

これは本当に苦痛です。は値DefaultTreeCellRendererを無視し、opaqueとにかくその内容を埋めます。ただし、試すことができるフラグがあります。過去にやったことがありますが、テストする時間がありません...

試してみてくださいUIManager.put("Tree.rendererFillBackground", false)。何かをレンダラーにする前に、ルック アンド フィール設定を適用した後にこれを試してみてください。

更新しました

ツリーを作成する前に、このプロパティを設定することが非常に重要です

なし | と...

ここに画像の説明を入力ここに画像の説明を入力

public class TestTreeRenderer {

    public static void main(String[] args) {
        new TestTreeRenderer();
    }

    public TestTreeRenderer() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TreePane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class TreePane extends JPanel {

        private JTree tree;

        public TreePane() {
            // THIS IS VERY IMPORTANT
            // You must set this BEFORE creating ANY trees!!
            UIManager.put("Tree.rendererFillBackground", false);

            setLayout(new BorderLayout());
            tree = new JTree();
            tree.setBackground(Color.BLUE);

            System.out.println("Loading files...");
            File root = new File("/etc");
            DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(root.getName());
            for (File file : root.listFiles()) {
                rootNode.add(new DefaultMutableTreeNode(file.getName()));
            }
            System.out.println("Loading model");
            DefaultTreeModel model = new DefaultTreeModel(rootNode);
            tree.setModel(model);

            add(new JScrollPane(tree));
        }
    }
}
于 2012-12-06T02:30:37.177 に答える
2

答え

(@Madの回答を拡張すると、根本的な問題の長い分析が最後にあります):

ツリーに手動で設定された defaultTreeCellRenderer でグローバル プロパティを有効にする場合、そのレンダラーは updateUI を再度呼び出す必要があります

UIManager.put("Tree.rendererFillBackground", false);
    ...
TreeCellRenderer r = new DefaultTreeCellRenderer() {
     {
          updateUI();
     }
};
tree.setCellRenderer(r);

グローバル設定を変更せ、透明なレンダラーをいくつかのツリー インスタンスのみにする場合、オプションは次のとおりです。

  • TreeCellRenderer をゼロから実装し、すべての汚れを残します (ペイントをオーバーライドしたり、予期しないハードコードされたトリックを実行したりするなど... すごい!)
  • updateUI で ui プロパティを一時的に設定することにより、レンダラーを騙します

だますコード:

TreeCellRenderer r = new DefaultTreeCellRenderer() {
    {
         updateUI();
    }

    @Override
    public void updateUI() {
        Object old = UIManager.get("Tree.rendererFillBackground");
        try {
            UIManager.put("Tree.rendererFillBackground", false);
            super.updateUI();
        } finally {
            UIManager.put("Tree.rendererFillBackground", old);
        }
    }
};

分析

私のコメントから始めて:

奇妙なことに、CellRenderer を設定するだけで (UI にお気に入りをインストールさせるのではなく)、フラグが無効になります。

このパズルは解決されます:

DefaultTreeCellRenderer には、UIManager の設定から fillBackground フィールドを設定する意図がありますが、インスタンス化時に失敗します。その理由は - 非常に一般的なエラーです ;-) - スーパーのコンストラクターでオーバーライドされたメソッドを呼び出すため、スーパーのインスタンス化で実際にそうする場合:

// this is implemented in DefaultTreeCellRenderer
// but called in JLabel constructor 
public void updateUI() {
    ....
    // we are in JLabel, that is fillBackground not yet known 
    fillBackground = DefaultLookup.getBoolean(this, ui, "Tree.rendererFillBackground", true);
    ...
}

その後、インスタンス化プロセスの後半で、フィールド値がハードコーディングされます。

private boolean fillBackground = true;

最終的な結果は (リフレクションを介してフィールド fi へのアクセスを強制すると仮定すると)、UIManager の設定に関係なく、常に次のパスになります。

DefaultTreeCellRenderer renderer = new DefaultTreeRenderer();
assertTrue(renderer.fillBackground);

珍しいのは、UI にデフォルトをインストールさせるときに、UIManager の設定が影響するのはなぜですか? ここでの理由は、レンダラー updateUI が 2 回呼び出されるためです。インスタンス化時に 1 回、ツリーの updateUI で 1 回です。

public void updateUI() {
    setUI((TreeUI)UIManager.getUI(this));
    // JW: at this point the renderer has its fillbackground hard-coded to true
    SwingUtilities.updateRendererOrEditorUI(getCellRenderer());
    // JW: now it's updateUI has been called again, and correctly set to the 
    // UIManager's value 
    SwingUtilities.updateRendererOrEditorUI(getCellEditor());
}

ところで:このインスタンス化の混乱はjdk7で導入されたようです...おそらく(チェックしませんでしたが)レンダラーの色のデフォルト設定も機能していません。

于 2012-12-06T14:45:05.607 に答える
0

次のように DefaultTreeCellRenderer を拡張するのはどうですか:

public class MyRenderer extends DefaultTreeCellRenderer {

public Component getTreeCellRendererComponent(JTree tree, Object value,
        boolean isSelected, boolean expanded, boolean leaf, int row,
        boolean hasFocus) {

    JComponent c = (JComponent) super.getTreeCellRendererComponent(tree, value, isSelected, expanded, leaf, row, hasFocus);

          c.setOpaque(true);

      return c; 
    }

}

設定 c.setOpaque(true); 解決するようです。

于 2015-08-11T01:03:32.610 に答える