我有一個Swing GUI挑戰,我將其提煉到以下SSCCE。問題是當更新窗口底部的JLabel以反映所選節點時,JTree/JScrollPane以令人不安的方式跳轉。控制HTML JLabel的重新驗證
查看此行爲的最佳方法是運行SSCCE,單擊JTree並按住鍵盤的向下箭頭以快速遍歷JTree。圖形用戶界面閃爍,好像JLabel正在被刪除,然後再次添加。但事實並非如此 - 我只是更新了JLabel的文本。
我想控制圖形用戶界面的重新繪製,使其不那麼震撼。我需要保留「狀態欄」的包裝和動態高度 - 使用固定高度的組件可以解決跳躍問題,但是會破壞設計理念。
我已經嘗試了幾種不同的方法來更新「狀態欄」區域(您可以在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
}
}
}
另外,不要忘了'包()'。 :-) – trashgod
閃爍確實是意想不到的,看起來像佈局不能應付文字環繞(只發生,如果HTML需要包裝段落,因爲文本不適合寬度)。 – kleopatra