gpt4 book ai didi

Java Swing : Need a good quality developed JTree with checkboxes

转载 作者:IT老高 更新时间:2023-10-28 20:59:00 24 4
gpt4 key购买 nike

我正在寻找一个 JTree 实现,它包含复选框并且:

  • 当你选择一个节点时,它在树中的所有后继节点都会被自动选中

  • 当您取消选择一个节点时,树中的所有后继节点都将自动取消选择

  • 当一个父节点已经被选中,并且选择从它的一个后继节点中移除时,节点颜色将会改变,以直观地表明虽然这个父节点被选中,但并不是它的所有后继节点都被选中已选中(就像您在常用安装程序中选择要安装的组件时一样)

  • 点击一个节点会导致(无需按住'Ctrl'键!):

    • 如果节点已被选中,则它会变为未选中状态,包括其所有后继节点
    • 如果节点没有被选中,它会被选中,它的所有后继节点都被选中

我在网上搜索了一些简单的东西,但找不到我想要的简单的东西。

有谁知道这种树的良好实现?

最佳答案

回答我自己:

我决定与大家分享我的代码。

这是结果的截图:

Screenshot

实现细节:

  • 创建了一个扩展 JTree 的新类

  • 用我创建的一个新类替换了“TreeCellRenderer”,它显示了一个复选框和一个标签。复选框选择被更改,而不是标签背景和边框。

  • 完全终止选择机制。将“选择模型”替换为“DefaultTreeSelectionModel”覆盖的内联,它具有空实现

    • 为检查复选框创建了新的事件类型

    • 创建了有助于快速指示每个节点状态的特殊数据结构

享受!!

这是一个用法示例:

public class Main extends JFrame {

private static final long serialVersionUID = 4648172894076113183L;

public Main() {
super();
setSize(500, 500);
this.getContentPane().setLayout(new BorderLayout());
final JCheckBoxTree cbt = new JCheckBoxTree();
this.getContentPane().add(cbt);
cbt.addCheckChangeEventListener(new JCheckBoxTree.CheckChangeEventListener() {
public void checkStateChanged(JCheckBoxTree.CheckChangeEvent event) {
System.out.println("event");
TreePath[] paths = cbt.getCheckedPaths();
for (TreePath tp : paths) {
for (Object pathPart : tp.getPath()) {
System.out.print(pathPart + ",");
}
System.out.println();
}
}
});
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}

public static void main(String args[]) {
Main m = new Main();
m.setVisible(true);
}
}

这是类本身的源代码:

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.EventListener;
import java.util.EventObject;
import java.util.HashMap;
import java.util.HashSet;

import javax.swing.JCheckBox;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.event.EventListenerList;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeSelectionModel;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

public class JCheckBoxTree extends JTree {

private static final long serialVersionUID = -4194122328392241790L;

JCheckBoxTree selfPointer = this;



// Defining data structure that will enable to fast check-indicate the state of each node
// It totally replaces the "selection" mechanism of the JTree
private class CheckedNode {
boolean isSelected;
boolean hasChildren;
boolean allChildrenSelected;

public CheckedNode(boolean isSelected_, boolean hasChildren_, boolean allChildrenSelected_) {
isSelected = isSelected_;
hasChildren = hasChildren_;
allChildrenSelected = allChildrenSelected_;
}
}
HashMap<TreePath, CheckedNode> nodesCheckingState;
HashSet<TreePath> checkedPaths = new HashSet<TreePath>();

// Defining a new event type for the checking mechanism and preparing event-handling mechanism
protected EventListenerList listenerList = new EventListenerList();

public class CheckChangeEvent extends EventObject {
private static final long serialVersionUID = -8100230309044193368L;

public CheckChangeEvent(Object source) {
super(source);
}
}

public interface CheckChangeEventListener extends EventListener {
public void checkStateChanged(CheckChangeEvent event);
}

public void addCheckChangeEventListener(CheckChangeEventListener listener) {
listenerList.add(CheckChangeEventListener.class, listener);
}
public void removeCheckChangeEventListener(CheckChangeEventListener listener) {
listenerList.remove(CheckChangeEventListener.class, listener);
}

void fireCheckChangeEvent(CheckChangeEvent evt) {
Object[] listeners = listenerList.getListenerList();
for (int i = 0; i < listeners.length; i++) {
if (listeners[i] == CheckChangeEventListener.class) {
((CheckChangeEventListener) listeners[i + 1]).checkStateChanged(evt);
}
}
}

// Override
public void setModel(TreeModel newModel) {
super.setModel(newModel);
resetCheckingState();
}

// New method that returns only the checked paths (totally ignores original "selection" mechanism)
public TreePath[] getCheckedPaths() {
return checkedPaths.toArray(new TreePath[checkedPaths.size()]);
}

// Returns true in case that the node is selected, has children but not all of them are selected
public boolean isSelectedPartially(TreePath path) {
CheckedNode cn = nodesCheckingState.get(path);
return cn.isSelected && cn.hasChildren && !cn.allChildrenSelected;
}

private void resetCheckingState() {
nodesCheckingState = new HashMap<TreePath, CheckedNode>();
checkedPaths = new HashSet<TreePath>();
DefaultMutableTreeNode node = (DefaultMutableTreeNode)getModel().getRoot();
if (node == null) {
return;
}
addSubtreeToCheckingStateTracking(node);
}

// Creating data structure of the current model for the checking mechanism
private void addSubtreeToCheckingStateTracking(DefaultMutableTreeNode node) {
TreeNode[] path = node.getPath();
TreePath tp = new TreePath(path);
CheckedNode cn = new CheckedNode(false, node.getChildCount() > 0, false);
nodesCheckingState.put(tp, cn);
for (int i = 0 ; i < node.getChildCount() ; i++) {
addSubtreeToCheckingStateTracking((DefaultMutableTreeNode) tp.pathByAddingChild(node.getChildAt(i)).getLastPathComponent());
}
}

// Overriding cell renderer by a class that ignores the original "selection" mechanism
// It decides how to show the nodes due to the checking-mechanism
private class CheckBoxCellRenderer extends JPanel implements TreeCellRenderer {
private static final long serialVersionUID = -7341833835878991719L;
JCheckBox checkBox;
public CheckBoxCellRenderer() {
super();
this.setLayout(new BorderLayout());
checkBox = new JCheckBox();
add(checkBox, BorderLayout.CENTER);
setOpaque(false);
}

@Override
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
Object obj = node.getUserObject();
TreePath tp = new TreePath(node.getPath());
CheckedNode cn = nodesCheckingState.get(tp);
if (cn == null) {
return this;
}
checkBox.setSelected(cn.isSelected);
checkBox.setText(obj.toString());
checkBox.setOpaque(cn.isSelected && cn.hasChildren && ! cn.allChildrenSelected);
return this;
}
}

public JCheckBoxTree() {
super();
// Disabling toggling by double-click
this.setToggleClickCount(0);
// Overriding cell renderer by new one defined above
CheckBoxCellRenderer cellRenderer = new CheckBoxCellRenderer();
this.setCellRenderer(cellRenderer);

// Overriding selection model by an empty one
DefaultTreeSelectionModel dtsm = new DefaultTreeSelectionModel() {
private static final long serialVersionUID = -8190634240451667286L;
// Totally disabling the selection mechanism
public void setSelectionPath(TreePath path) {
}
public void addSelectionPath(TreePath path) {
}
public void removeSelectionPath(TreePath path) {
}
public void setSelectionPaths(TreePath[] pPaths) {
}
};
// Calling checking mechanism on mouse click
this.addMouseListener(new MouseListener() {
public void mouseClicked(MouseEvent arg0) {
TreePath tp = selfPointer.getPathForLocation(arg0.getX(), arg0.getY());
if (tp == null) {
return;
}
boolean checkMode = ! nodesCheckingState.get(tp).isSelected;
checkSubTree(tp, checkMode);
updatePredecessorsWithCheckMode(tp, checkMode);
// Firing the check change event
fireCheckChangeEvent(new CheckChangeEvent(new Object()));
// Repainting tree after the data structures were updated
selfPointer.repaint();
}
public void mouseEntered(MouseEvent arg0) {
}
public void mouseExited(MouseEvent arg0) {
}
public void mousePressed(MouseEvent arg0) {
}
public void mouseReleased(MouseEvent arg0) {
}
});
this.setSelectionModel(dtsm);
}

// When a node is checked/unchecked, updating the states of the predecessors
protected void updatePredecessorsWithCheckMode(TreePath tp, boolean check) {
TreePath parentPath = tp.getParentPath();
// If it is the root, stop the recursive calls and return
if (parentPath == null) {
return;
}
CheckedNode parentCheckedNode = nodesCheckingState.get(parentPath);
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) parentPath.getLastPathComponent();
parentCheckedNode.allChildrenSelected = true;
parentCheckedNode.isSelected = false;
for (int i = 0 ; i < parentNode.getChildCount() ; i++) {
TreePath childPath = parentPath.pathByAddingChild(parentNode.getChildAt(i));
CheckedNode childCheckedNode = nodesCheckingState.get(childPath);
// It is enough that even one subtree is not fully selected
// to determine that the parent is not fully selected
if (! childCheckedNode.allChildrenSelected) {
parentCheckedNode.allChildrenSelected = false;
}
// If at least one child is selected, selecting also the parent
if (childCheckedNode.isSelected) {
parentCheckedNode.isSelected = true;
}
}
if (parentCheckedNode.isSelected) {
checkedPaths.add(parentPath);
} else {
checkedPaths.remove(parentPath);
}
// Go to upper predecessor
updatePredecessorsWithCheckMode(parentPath, check);
}

// Recursively checks/unchecks a subtree
protected void checkSubTree(TreePath tp, boolean check) {
CheckedNode cn = nodesCheckingState.get(tp);
cn.isSelected = check;
DefaultMutableTreeNode node = (DefaultMutableTreeNode) tp.getLastPathComponent();
for (int i = 0 ; i < node.getChildCount() ; i++) {
checkSubTree(tp.pathByAddingChild(node.getChildAt(i)), check);
}
cn.allChildrenSelected = check;
if (check) {
checkedPaths.add(tp);
} else {
checkedPaths.remove(tp);
}
}

}

关于Java Swing : Need a good quality developed JTree with checkboxes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21847411/

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