gpt4 book ai didi

java - 如何调整 TreeCellEditor 周围的 JTree 行的大小

转载 作者:行者123 更新时间:2023-11-30 11:06:52 24 4
gpt4 key购买 nike

我使用多行 JTextArea 来编辑我的 JTree 中的值。

通过一些技巧,我能够调整 JTextArea 的大小以适应其中的文本,但编辑器周围的 JTree 节点/行不会移开。 (SCCEE 截图如下)

如何让 JTree 围绕编辑器组件“回流”其所有节点?

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;

public final class TextAreaEditorForJTree {

public static final String INITIAL_TEXT = "Line 1\nLine 2\nLine 3";

public static void main(String args[]) {

JTree tree = createSimpleTree();

addTextAreaEditor(tree);

JScrollPane scrollPane = new JScrollPane(tree);

JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane, BorderLayout.CENTER);
frame.setSize(300, 300);
frame.setVisible(true);
}

private static JTree createSimpleTree() {
DefaultMutableTreeNode root = new DefaultMutableTreeNode(INITIAL_TEXT);

for (int i = 0; i < 10; i++) {
MutableTreeNode child = new DefaultMutableTreeNode(INITIAL_TEXT);
root.add(child);
}

JTree tree = new JTree(root);
tree.setEditable(true);
tree.setShowsRootHandles(true);

return tree;
}

private static void addTextAreaEditor(JTree tree) {
TreeCellEditor editor = new TextAreaTableCellEditor();
tree.setCellEditor(editor);
}

private static final class TextAreaTableCellEditor extends AbstractCellEditor implements TreeCellEditor {

private final JPanel panel;
private final JLabel label;
private final JTextArea textArea;
private DefaultMutableTreeNode currentNode;

public TextAreaTableCellEditor() {

label = new JLabel("Editor:");

textArea = new JTextArea();
textArea.setColumns(10);

panel = new JPanel();
BoxLayout boxLayout = new BoxLayout(panel, BoxLayout.X_AXIS);
panel.setLayout(boxLayout);
panel.add(label);
panel.add(textArea);

textArea.addComponentListener(new ComponentListener() {

@Override
public void componentResized(ComponentEvent e) {
setSizeToPreferredSizeLater();
}

@Override
public void componentShown(ComponentEvent e) {
setSizeToPreferredSizeLater();
}

@Override
public void componentMoved(ComponentEvent e) {
}

@Override
public void componentHidden(ComponentEvent e) {
}
});

textArea.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) {
setSizeToPreferredSizeLater();
}

public void removeUpdate(DocumentEvent e) {
setSizeToPreferredSizeLater();
}

public void changedUpdate(DocumentEvent e) {
setSizeToPreferredSizeLater();
}
});
}

private void setSizeToPreferredSizeLater() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
panel.setSize(panel.getPreferredSize());
}
});

}

public Object getCellEditorValue() {
return textArea.getText();
}

public boolean isCellEditable(EventObject anEvent) {
return true;
}

public boolean shouldSelectCell(EventObject anEvent) {
return true;
}

public boolean stopCellEditing() {
currentNode.setUserObject(textArea.getText());
return true;
}

public void cancelCellEditing() {
currentNode.setUserObject(textArea.getText());
}

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

this.currentNode = ((DefaultMutableTreeNode) value);

textArea.setText((String) currentNode.getUserObject());

return panel;
}
}
}

SCCEE 的屏幕截图 - 编辑器(灰色框和右侧的文本)出现在所有其他树节点的顶部。

TreeCellEditor appears over neighboring tree nodes

最佳答案

我找到了解决问题的方法,它与 the answer to a related question 中的实现非常相似.如果您只是处理渲染器,那么查看 other question and answer 可能会更好地为您服务,但在我的例子中,我正在处理一个在我键入时调整大小的编辑器。

两种情况下的关键是调用 AbstractLayoutCache.invalidateSizes()。此缓存在 BasicTreeUI 的 protected 成员中,您可以从 JTree.getUI() 获取它(这假设您的树的 L&F 扩展BasicTreeUI)

您应该注意,虽然该方法称为“invalidateSizes”,但它实际上会使所有节点边界 无效。节点 bounds 还包括组件的位置。我真的很想扩展 UI 对象或插入转发/代理对象,但我无法在分配的时间内找到解决方案。

在大小/边界无效后,调用 tree.repaint() 将更新 UI 以显示新编辑器的大小。

好的,所以我找到了两种调用此方法的方法,我也不太喜欢...但它们确实有效:

private static class MyJTree extends JTree {
...
public void invalidateNodeBoundsViaSideEffect() {
if (ui instanceof BasicTreeUI) {
BasicTreeUI basicTreeUI = (BasicTreeUI) ui;
basicTreeUI.setLeftChildIndent(basicTreeUI.getLeftChildIndent());
}}

public void invalidateNodeBoundsViaRefection() {
if (ui instanceof BasicTreeUI) {
try {
Field field = BasicTreeUI.class.getDeclaredField("treeState");
field.setAccessible(true);

AbstractLayoutCache treeState = (AbstractLayoutCache) field.get(ui);

if (treeState != null) {
treeState.invalidateSizes();
}
} catch (Exception e) {
}
}}}

修订后的 SCCEE 包括此解决方案:

import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.Field;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.plaf.basic.*;
import javax.swing.tree.*;

public final class TextAreaEditorForJTree2 {

public static final String INITIAL_TEXT = "Line 1\nLine 2\nLine 3";

public static void main(String args[]) {

JTree tree = createSimpleTree();

addTextAreaEditor(tree);

JScrollPane scrollPane = new JScrollPane(tree);

JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane, BorderLayout.CENTER);
frame.setSize(300, 300);
frame.setVisible(true);
}

private static JTree createSimpleTree() {

DefaultMutableTreeNode root = new DefaultMutableTreeNode(INITIAL_TEXT);

for (int i = 0; i < 10; i++) {
MutableTreeNode child = new DefaultMutableTreeNode(INITIAL_TEXT);
root.add(child);
}

JTree tree = new MyJTree(root);
tree.setRowHeight(0); // CRITICAL - Setting to '0' means the row heights are variable and the renderer's **bounds** should be recomputed more often!
tree.setEditable(true);
tree.setShowsRootHandles(true);

return tree;
}

private static void addTextAreaEditor(JTree tree) {
TreeCellEditor editor = new TextAreaTableCellEditor(tree);
tree.setCellEditor(editor);
}

private static final class TextAreaTableCellEditor extends AbstractCellEditor implements TreeCellEditor {

private final JPanel editorPanel;
private final JLabel editorLabel;
private final JTextArea textArea;
private DefaultMutableTreeNode currentNode;
private final JTree tree;

public TextAreaTableCellEditor(final JTree target) {
this.tree = target;

editorLabel = new JLabel("Editor:");

textArea = new JTextArea();
textArea.setColumns(10);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);

editorPanel = new JPanel();
BoxLayout boxLayout = new BoxLayout(editorPanel, BoxLayout.X_AXIS);
editorPanel.setLayout(boxLayout);
editorPanel.add(editorLabel);
editorPanel.add(textArea);

editorPanel.setSize(editorPanel.getPreferredSize());

textArea.addComponentListener(new ComponentListener() {
public void componentResized(ComponentEvent e) {somethingChanged();}
public void componentShown(ComponentEvent e) {somethingChanged();}
public void componentMoved(ComponentEvent e) {}
public void componentHidden(ComponentEvent e) {}
});

textArea.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) {somethingChanged();}
public void removeUpdate(DocumentEvent e) {somethingChanged();}
public void changedUpdate(DocumentEvent e) {somethingChanged();}
});
}

private void somethingChanged() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// TODO: skip if size is not changing
editorPanel.setSize(editorPanel.getPreferredSize());
((MyJTree) tree).invalidateNodeBounds();
tree.repaint();
}
});
}

public Object getCellEditorValue() {
return textArea.getText();
}

public boolean isCellEditable(EventObject anEvent) {
return true;
}

public boolean shouldSelectCell(EventObject anEvent) {
return true;
}

public boolean stopCellEditing() {
currentNode.setUserObject(textArea.getText());
return true;
}

public void cancelCellEditing() {
currentNode.setUserObject(textArea.getText());
}

public Component getTreeCellEditorComponent(final JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) {
this.currentNode = ((DefaultMutableTreeNode) value);
textArea.setText((String) currentNode.getUserObject());
return editorPanel;
}
}

private static class MyJTree extends JTree {

public MyJTree(TreeNode root) {
super(root);
}

public void invalidateNodeBounds() {
invalidateNodeBoundsViaSideEffect();
//invalidateNodeBoundsViaRefection();
}

public void invalidateNodeBoundsViaSideEffect() {
if (ui instanceof BasicTreeUI) {
BasicTreeUI basicTreeUI = (BasicTreeUI) ui;
basicTreeUI.setLeftChildIndent(basicTreeUI.getLeftChildIndent());
}
}

public void invalidateNodeBoundsViaRefection() {

if (ui instanceof BasicTreeUI) {

try {
Field field = BasicTreeUI.class.getDeclaredField("treeState");
field.setAccessible(true);

AbstractLayoutCache treeState = (AbstractLayoutCache) field.get(ui);

if (treeState != null) {
treeState.invalidateSizes();
}
} catch (Exception e) {
}
}
}
}
}

关于java - 如何调整 TreeCellEditor 周围的 JTree 行的大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29127786/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com