2013-10-24 33 views
1

我有一個Swing GUI挑戰,我將其提煉到以下SSCCE。問題是當更新窗口底部的JLabel以反映所選節點時,JTree/JScrollPane以令人不安的方式跳轉。控制HTML JLabel的重新驗證

查看此行爲的最佳方法是運行SSCCE,單擊JTree並按住鍵盤的向下箭頭以快速遍歷JTree。圖形用戶界面閃爍,好像JLabel正在被刪除,然後再次添加。但事實並非如此 - 我只是更新了JLabel的文本。

我想控制圖形用戶界面的重新繪製,使其不那麼震撼。我需要保留「狀態欄」的包裝和動態高度 - 使用固定高度的組件可以解決跳躍問題,但是會破壞設計理念。

我已經嘗試了幾種不同的方法來更新「狀態欄」區域(您可以在SSCCE的TreeSelectionListener中看到註釋的方法之一),但是我嘗試過的任何方法都會導致不正確的重新計算高度或閃爍。

enter image description here

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 
     } 
    } 
} 
+0

另外,不要忘了'包()'。 :-) – trashgod

+1

閃爍確實是意想不到的,看起來像佈局不能應付文字環繞(只發生,如果HTML需要包裝段落,因爲文本不適合寬度)。 – kleopatra

回答

4

似乎使用的JTextPane,而不是一個JLabel當工作確定:

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

哎呀...錯字固定。 – camickr

+1

+1可行的出路:-)看起來textpane的html佈局比標籤的更好 - 有點奇怪... – kleopatra

+0

工程魅力。謝謝你揮舞着SO的神:來自camickr,kleo,TG和MK的暗示。現在,如果只有HCFoE和MP會加入進來,我的小問答將會爲錦上添花。 ;-) –