【问题标题】:Controlling the revalidation of an HTML JLabel控制 HTML JLabel 的重新验证
【发布时间】:2013-10-24 00:10:41
【问题描述】:

我有一个 Swing GUI 挑战,我提炼到以下 SSCCE。问题是在更新窗口底部的 JLabel 以反映所选节点时,JTree/JScrollPane 会以一种令人不安的方式跳来跳去。

查看此行为的最佳方法是运行 SSCCE,单击 JTree,然后按住键盘的向下箭头以快速遍历 JTree。 GUI 闪烁,好像 JLabel 正在被删除然后再次添加。不过,情况并非如此——我只是在更新 JLabel 的文本。

我想控制 GUI 的重绘,使其不那么刺耳。我需要保留“状态栏”的自动换行和动态高度——使用固定高度组件可以解决跳跃问题,但会破坏设计理念。

我尝试了几种不同的方法来更新“状态栏”区域(您可以看到其中一种方法已在 SSCCE 的 TreeSelectionListener 中被注释掉),但我尝试的所有方法要么导致高度重新计算不正确,要么闪烁.

import java.awt.*;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;

public class JTreePlusStatus extends JFrame {
    JPanel _contentPane;
    JScrollPane _jScrollPane;
    JTree _jTree;
    JLabel _jLabelDescription;
    GridBagConstraints _gbcJLabelDescription;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    String sysLaf = UIManager.getSystemLookAndFeelClassName();
                    UIManager.setLookAndFeel(sysLaf);
                    JFrame frame = new JTreePlusStatus();
                    frame.setSize(300, 300);
                    frame.setLocationRelativeTo(null);
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public JTreePlusStatus() {
        initComponents();
        initCustom();
    }

    void initComponents() {
        // Boilerplate layout busywork
        _contentPane = new JPanel();
        GridBagLayout gblContentPane = new GridBagLayout();
        _contentPane.setLayout(gblContentPane);
        setContentPane(_contentPane);

        _jScrollPane = new JScrollPane();
        GridBagConstraints gbcJScrollPane = new GridBagConstraints();
        gbcJScrollPane.fill = GridBagConstraints.BOTH;
        gbcJScrollPane.weighty = 1.0;
        gbcJScrollPane.weightx = 1.0;
        gbcJScrollPane.gridx = 0;
        gbcJScrollPane.gridy = 0;
        _contentPane.add(_jScrollPane, gbcJScrollPane);

        _jTree = new JTree();
        _jScrollPane.setViewportView(_jTree);
        _jTree.addTreeSelectionListener(new TreeSelectionListenerImpl());

        _jLabelDescription = new JLabel(" ");
        _gbcJLabelDescription = new GridBagConstraints();
        _gbcJLabelDescription.fill = GridBagConstraints.HORIZONTAL;
        _gbcJLabelDescription.gridx = 0;
        _gbcJLabelDescription.gridy = 1;
        _contentPane.add(_jLabelDescription, _gbcJLabelDescription);
    }

    void initCustom() {
        // Set sample data onto the JTree
        _jTree.setModel(createSampleModel());

        // Expand entire tree
        for (int i = 0; i < _jTree.getRowCount(); i++) {
            _jTree.expandRow(i);
        }
    }

    public DefaultTreeModel createSampleModel() {
        DefaultMutableTreeNode top = new DefaultMutableTreeNode("Music");
        for (int i = 0; i < 100; i++) {
            String s = "Classical - Concertos - Beethoven "
                    + "- S No. 5 - E-Flat Major " + i;
            top.add(new DefaultMutableTreeNode(s));
        }
        DefaultTreeModel defaultTreeModel = new DefaultTreeModel(top);
        return defaultTreeModel;
    }

    class TreeSelectionListenerImpl implements TreeSelectionListener {

        public void valueChanged(TreeSelectionEvent e) {
            TreePath selectionPath = _jTree.getSelectionPath();
            String s = selectionPath.getLastPathComponent().toString();
            String newText = "<html><b>Name:</b> " + s 
                    + " <br><b>Description: </b>" + s + "</html>";

            /** Tried this -- causes the JTree to jump around */
            _jLabelDescription.setText(newText);

            /**
             * OK, try making a new JLabel and "set" it into the parent,
             * hoping that there won't be an intermediate state where label's
             * space in the GUI collapses temporarily
             */
            //final JLabel newJLabel = new JLabel(newText);
            //final Container parent = _jLabelDescription.getParent();
            //parent.add(newJLabel, _gbcJLabelDescription, 1);
            //parent.remove(_jLabelDescription);
            //if (parent instanceof JComponent) {
            //    JComponent jc = (JComponent) parent;
            //    jc.validate(); // must revalidate after adding or removing
            //}
            //_jLabelDescription = newJLabel;

            // No luck, JTree/JScrollPane still jumps around
        }
    }
}

【问题讨论】:

  • 另外,别忘了pack()。 :-)
  • 闪烁确实出乎意料,看起来布局无法应对文本换行(仅当 html 需要换行时才会发生,因为文本不适合宽度)。

标签: java swing jlabel jtree gridbaglayout


【解决方案1】:

使用 JTextPane 而不是 JLabel 时似乎可以正常工作:

    _jLabelDescription = new JTextPane();
    _jLabelDescription.setContentType( "text/html" );

【讨论】:

  • +1 一个可行的出路 :-) 看起来文本窗格的 html 布局比标签的布局更好 - 有点奇怪......
  • 很有魅力。谢谢 Swing Gods of SO:来自 camickr、kleo、TG 和 MK 的提示。现在,如果只有 HCFoE 和 MP 加入,我的小问答就会锦上添花。 ;-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-02
  • 1970-01-01
  • 2011-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多