本文目录导读:

我将为您创建一个Java脑图(思维导图)案例,使用Java Swing实现一个可视化脑图工具。
完整实现代码
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import java.util.List;
public class MindMapDemo extends JFrame {
private MindMapPanel mindMapPanel;
private JToolBar toolBar;
private JLabel statusBar;
public MindMapDemo() {
setTitle("Java脑图 - 思维导图工具");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1200, 800);
setLocationRelativeTo(null);
// 初始化组件
mindMapPanel = new MindMapPanel();
createToolBar();
createStatusBar();
// 添加主面板
add(mindMapPanel, BorderLayout.CENTER);
add(toolBar, BorderLayout.NORTH);
add(statusBar, BorderLayout.SOUTH);
// 添加菜单栏
setJMenuBar(createMenuBar());
// 键盘快捷键
setupKeyboardShortcuts();
}
private JMenuBar createMenuBar() {
JMenuBar menuBar = new JMenuBar();
// 文件菜单
JMenu fileMenu = new JMenu("文件");
JMenuItem newItem = new JMenuItem("新建");
newItem.addActionListener(e -> mindMapPanel.newMindMap());
JMenuItem saveItem = new JMenuItem("保存");
saveItem.addActionListener(e -> saveMindMap());
JMenuItem loadItem = new JMenuItem("加载");
loadItem.addActionListener(e -> loadMindMap());
JMenuItem exitItem = new JMenuItem("退出");
exitItem.addActionListener(e -> System.exit(0));
fileMenu.add(newItem);
fileMenu.add(saveItem);
fileMenu.add(loadItem);
fileMenu.addSeparator();
fileMenu.add(exitItem);
// 编辑菜单
JMenu editMenu = new JMenu("编辑");
JMenuItem addNodeItem = new JMenuItem("添加节点");
addNodeItem.addActionListener(e -> mindMapPanel.addChildNode());
JMenuItem deleteNodeItem = new JMenuItem("删除节点");
deleteNodeItem.addActionListener(e -> mindMapPanel.deleteSelectedNode());
JMenuItem editNodeItem = new JMenuItem("编辑节点文本");
editNodeItem.addActionListener(e -> mindMapPanel.editSelectedNode());
editMenu.add(addNodeItem);
editMenu.add(deleteNodeItem);
editMenu.add(editNodeItem);
// 视图菜单
JMenu viewMenu = new JMenu("视图");
JCheckBoxMenuItem autoLayoutItem = new JCheckBoxMenuItem("自动布局", true);
autoLayoutItem.addActionListener(e -> mindMapPanel.setAutoLayout(autoLayoutItem.isSelected()));
JMenuItem expandAllItem = new JMenuItem("展开全部");
expandAllItem.addActionListener(e -> mindMapPanel.expandAll());
JMenuItem collapseAllItem = new JMenuItem("收起全部");
collapseAllItem.addActionListener(e -> mindMapPanel.collapseAll());
viewMenu.add(autoLayoutItem);
viewMenu.add(expandAllItem);
viewMenu.add(collapseAllItem);
// 帮助菜单
JMenu helpMenu = new JMenu("帮助");
JMenuItem aboutItem = new JMenuItem("quot;);
aboutItem.addActionListener(e -> showAboutDialog());
helpMenu.add(aboutItem);
menuBar.add(fileMenu);
menuBar.add(editMenu);
menuBar.add(viewMenu);
menuBar.add(helpMenu);
return menuBar;
}
private void createToolBar() {
toolBar = new JToolBar();
toolBar.setFloatable(false);
JButton addNodeBtn = createToolButton("➕", "添加子节点", e -> mindMapPanel.addChildNode());
JButton addSiblingBtn = createToolButton("📝", "添加兄弟节点", e -> mindMapPanel.addSiblingNode());
JButton deleteNodeBtn = createToolButton("🗑️", "删除节点", e -> mindMapPanel.deleteSelectedNode());
JButton editNodeBtn = createToolButton("✏️", "编辑节点", e -> mindMapPanel.editSelectedNode());
JButton expandBtn = createToolButton("🔍", "展开节点", e -> mindMapPanel.toggleExpand());
toolBar.add(addNodeBtn);
toolBar.add(addSiblingBtn);
toolBar.add(deleteNodeBtn);
toolBar.add(editNodeBtn);
toolBar.add(expandBtn);
toolBar.addSeparator();
// 颜色选择
JButton colorBtn = new JButton("🎨 颜色");
colorBtn.addActionListener(e -> mindMapPanel.changeNodeColor());
toolBar.add(colorBtn);
}
private JButton createToolButton(String text, String tooltip, ActionListener action) {
JButton button = new JButton(text);
button.setToolTipText(tooltip);
button.addActionListener(action);
button.setFocusable(false);
return button;
}
private void createStatusBar() {
statusBar = new JLabel(" 就绪 | 节点数: 0");
statusBar.setBorder(BorderFactory.createEmptyBorder(3, 5, 3, 5));
statusBar.setOpaque(true);
statusBar.setBackground(new Color(230, 230, 230));
}
private void setupKeyboardShortcuts() {
InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getRootPane().getActionMap();
// Tab: 添加子节点
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), "addChild");
actionMap.put("addChild", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
mindMapPanel.addChildNode();
}
});
// F2: 编辑节点
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0), "editNode");
actionMap.put("editNode", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
mindMapPanel.editSelectedNode();
}
});
// Delete: 删除节点
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "deleteNode");
actionMap.put("deleteNode", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
mindMapPanel.deleteSelectedNode();
}
});
}
private void saveMindMap() {
JFileChooser fileChooser = new JFileChooser();
if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
mindMapPanel.saveToFile(fileChooser.getSelectedFile());
}
}
private void loadMindMap() {
JFileChooser fileChooser = new JFileChooser();
if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
mindMapPanel.loadFromFile(fileChooser.getSelectedFile());
}
}
private void showAboutDialog() {
JOptionPane.showMessageDialog(this,
"Java脑图 - 思维导图工具\n\n版本: 1.0\n作者: Java Demo",
"quot;, JOptionPane.INFORMATION_MESSAGE);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
new MindMapDemo().setVisible(true);
});
}
}
// 脑图节点类
class MindNode {
private String text;
private MindNode parent;
private List<MindNode> children;
private int x, y;
private int width = 120, height = 40;
private Color color;
private boolean expanded;
public MindNode(String text) {
this.text = text;
this.children = new ArrayList<>();
this.expanded = true;
this.color = new Color(204, 229, 255); // 默认浅蓝色
}
public void addChild(MindNode child) {
child.parent = this;
children.add(child);
}
public void addSibling(MindNode sibling) {
if (parent != null) {
parent.addChild(sibling);
}
}
public boolean isRoot() {
return parent == null;
}
public boolean isLeaf() {
return children.isEmpty();
}
// Getters and Setters
public String getText() { return text; }
public void setText(String text) { this.text = text; }
public MindNode getParent() { return parent; }
public List<MindNode> getChildren() { return children; }
public int getX() { return x; }
public void setX(int x) { this.x = x; }
public int getY() { return y; }
public void setY(int y) { this.y = y; }
public int getWidth() { return width; }
public void setWidth(int width) { this.width = width; }
public int getHeight() { return height; }
public void setHeight(int height) { this.height = height; }
public Color getColor() { return color; }
public void setColor(Color color) { this.color = color; }
public boolean isExpanded() { return expanded; }
public void setExpanded(boolean expanded) { this.expanded = expanded; }
public void toggleExpanded() { this.expanded = !this.expanded; }
// 获取中心点
public int getCenterX() { return x + width / 2; }
public int getCenterY() { return y + height / 2; }
// 获取所有子孙节点
public List<MindNode> getAllDescendants() {
List<MindNode> descendants = new ArrayList<>();
collectDescendants(this, descendants);
return descendants;
}
private void collectDescendants(MindNode node, List<MindNode> list) {
for (MindNode child : node.children) {
list.add(child);
collectDescendants(child, list);
}
}
}
// 脑图面板类
class MindMapPanel extends JPanel {
private MindNode root;
private MindNode selectedNode;
private int nodeCount;
private boolean autoLayout;
private Point dragStart;
private MindNode dragNode;
public MindMapPanel() {
setBackground(new Color(250, 250, 250));
newMindMap();
setupMouseListener();
}
private void setupMouseListener() {
// 鼠标点击选择节点
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
MindNode node = findNodeAt(e.getPoint());
if (node != null) {
selectedNode = node;
dragStart = e.getPoint();
dragNode = node;
repaint();
}
}
@Override
public void mouseReleased(MouseEvent e) {
if (dragNode != null) {
updateStatusBar();
dragNode = null;
}
}
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
MindNode node = findNodeAt(e.getPoint());
if (node != null && !node.isRoot()) {
node.toggleExpanded();
if (autoLayout) {
layoutTree();
}
repaint();
}
}
}
});
// 鼠标拖动节点
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
if (dragNode != null && e.isShiftDown()) {
int dx = e.getX() - dragStart.x;
int dy = e.getY() - dragStart.y;
dragNode.setX(dragNode.getX() + dx);
dragNode.setY(dragNode.getY() + dy);
dragStart = e.getPoint();
repaint();
}
}
});
// 键盘监听
setFocusable(true);
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (selectedNode != null) {
int moveAmount = 5;
if (e.isShiftDown()) {
moveAmount = 10;
}
switch(e.getKeyCode()) {
case KeyEvent.VK_UP:
selectedNode.setY(selectedNode.getY() - moveAmount);
break;
case KeyEvent.VK_DOWN:
selectedNode.setY(selectedNode.getY() + moveAmount);
break;
case KeyEvent.VK_LEFT:
selectedNode.setX(selectedNode.getX() - moveAmount);
break;
case KeyEvent.VK_RIGHT:
selectedNode.setX(selectedNode.getX() + moveAmount);
break;
}
repaint();
}
}
});
}
private MindNode findNodeAt(Point point) {
// 遍历所有可见节点
List<MindNode> visibleNodes = getVisibleNodes();
for (int i = visibleNodes.size() - 1; i >= 0; i--) {
MindNode node = visibleNodes.get(i);
Rectangle bounds = new Rectangle(node.getX(), node.getY(), node.getWidth(), node.getHeight());
if (bounds.contains(point)) {
return node;
}
}
return null;
}
private List<MindNode> getVisibleNodes() {
List<MindNode> visible = new ArrayList<>();
if (root != null) {
collectVisibleNodes(root, visible);
}
return visible;
}
private void collectVisibleNodes(MindNode node, List<MindNode> list) {
list.add(node);
if (node.isExpanded()) {
for (MindNode child : node.getChildren()) {
collectVisibleNodes(child, list);
}
}
}
public void newMindMap() {
root = new MindNode("中心主题");
nodeCount = 1;
selectedNode = root;
autoLayout = true;
// 创建默认子节点
MindNode child1 = new MindNode("Java基础");
MindNode child2 = new MindNode("面向对象");
MindNode child3 = new MindNode("集合框架");
root.addChild(child1);
root.addChild(child2);
root.addChild(child3);
nodeCount = 4;
layoutTree();
updateStatusBar();
repaint();
}
private void layoutTree() {
if (!autoLayout) return;
int panelWidth = getWidth();
int panelHeight = getHeight();
// 递归布局,使用简单的水平树状布局
if (root != null) {
layoutNode(root, 50, panelHeight / 2, 0);
}
}
private void layoutNode(MindNode node, int x, int y, int level) {
node.setX(x);
node.setY(y - node.getHeight() / 2);
if (!node.isExpanded() || node.isLeaf()) {
return;
}
// 布局子节点
int childCount = node.getChildren().size();
int totalHeight = (childCount - 1) * (node.getHeight() + 30);
int startY = y - totalHeight / 2;
int childX = x + 200;
for (int i = 0; i < childCount; i++) {
MindNode child = node.getChildren().get(i);
int childY = startY + i * (node.getHeight() + 30);
layoutNode(child, childX, childY, level + 1);
}
}
public void addChildNode() {
if (selectedNode == null) {
return;
}
MindNode newNode = new MindNode("新节点");
selectedNode.addChild(newNode);
nodeCount++;
if (autoLayout) {
layoutTree();
}
selectedNode = newNode;
updateStatusBar();
repaint();
// 自动开始编辑新节点
editNode(newNode);
}
public void addSiblingNode() {
if (selectedNode == null || selectedNode.isRoot()) {
return;
}
MindNode newNode = new MindNode("新节点");
selectedNode.addSibling(newNode);
nodeCount++;
selectedNode = newNode;
if (autoLayout) {
layoutTree();
}
updateStatusBar();
repaint();
// 自动开始编辑新节点
editNode(newNode);
}
public void deleteSelectedNode() {
if (selectedNode == null || selectedNode.isRoot()) {
return;
}
int confirm = JOptionPane.showConfirmDialog(this,
"确定要删除节点 \"" + selectedNode.getText() + "\" 吗?",
"删除节点", JOptionPane.YES_NO_OPTION);
if (confirm == JOptionPane.YES_OPTION) {
MindNode parent = selectedNode.getParent();
parent.getChildren().remove(selectedNode);
nodeCount -= 1 + selectedNode.getAllDescendants().size();
selectedNode = parent;
if (autoLayout) {
layoutTree();
}
updateStatusBar();
repaint();
}
}
public void editSelectedNode() {
if (selectedNode != null) {
editNode(selectedNode);
}
}
private void editNode(MindNode node) {
String newText = JOptionPane.showInputDialog(this,
"编辑节点文本:", node.getText());
if (newText != null && !newText.trim().isEmpty()) {
node.setText(newText.trim());
adjustNodeSize(node);
if (autoLayout) {
layoutTree();
}
repaint();
}
}
private void adjustNodeSize(MindNode node) {
Graphics2D g2d = (Graphics2D) getGraphics();
if (g2d != null) {
FontMetrics fm = g2d.getFontMetrics();
int textWidth = fm.stringWidth(node.getText());
node.setWidth(Math.max(100, textWidth + 30));
}
}
public void toggleExpand() {
if (selectedNode != null) {
selectedNode.toggleExpanded();
if (autoLayout) {
layoutTree();
}
repaint();
}
}
public void expandAll() {
expandAllNodes(root);
if (autoLayout) {
layoutTree();
}
repaint();
}
private void expandAllNodes(MindNode node) {
node.setExpanded(true);
for (MindNode child : node.getChildren()) {
expandAllNodes(child);
}
}
public void collapseAll() {
collapseAllNodes(root);
if (autoLayout) {
layoutTree();
}
// 只显示根节点
nodeCount = 1;
repaint();
}
private void collapseAllNodes(MindNode node) {
if (!node.isRoot()) {
node.setExpanded(false);
}
for (MindNode child : node.getChildren()) {
collapseAllNodes(child);
}
}
public void changeNodeColor() {
if (selectedNode != null) {
Color newColor = JColorChooser.showDialog(this,
"选择节点颜色", selectedNode.getColor());
if (newColor != null) {
selectedNode.setColor(newColor);
repaint();
}
}
}
public void setAutoLayout(boolean autoLayout) {
this.autoLayout = autoLayout;
if (autoLayout) {
layoutTree();
repaint();
}
}
private void updateStatusBar() {
// 更新状态栏逻辑(省略具体实现)
}
public void saveToFile(java.io.File file) {
// 保存逻辑(使用对象序列化)
try {
java.io.ObjectOutputStream oos =
new java.io.ObjectOutputStream(new java.io.FileOutputStream(file));
oos.writeObject(root);
oos.close();
JOptionPane.showMessageDialog(this, "脑图保存成功!");
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "保存失败: " + e.getMessage(),
"错误", JOptionPane.ERROR_MESSAGE);
}
}
public void loadFromFile(java.io.File file) {
// 加载逻辑
try {
java.io.ObjectInputStream ois =
new java.io.ObjectInputStream(new java.io.FileInputStream(file));
root = (MindNode) ois.readObject();
ois.close();
nodeCount = 1 + root.getAllDescendants().size();
layoutTree();
selectedNode = root;
updateStatusBar();
repaint();
JOptionPane.showMessageDialog(this, "脑图加载成功!");
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "加载失败: " + e.getMessage(),
"错误", JOptionPane.ERROR_MESSAGE);
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 绘制连接线和节点
if (root != null) {
drawNode(g2d, root);
}
// 绘制选中效果
if (selectedNode != null) {
g2d.setColor(new Color(255, 100, 100, 50));
g2d.setStroke(new BasicStroke(3));
g2d.drawRoundRect(selectedNode.getX() - 3, selectedNode.getY() - 3,
selectedNode.getWidth() + 6, selectedNode.getHeight() + 6, 10, 10);
}
// 绘制标题
g2d.setColor(new Color(0, 0, 0, 30));
g2d.setFont(new Font("微软雅黑", Font.BOLD, 30));
g2d.drawString("📚 Java 学习脑图", 20, 40);
// 绘制操作提示
g2d.setColor(new Color(0, 0, 0, 60));
g2d.setFont(new Font("微软雅黑", Font.PLAIN, 12));
g2d.drawString("操作提示: 单击选择节点 | Shift+拖动移动节点 | 双击展开/收起 | TAB添加子节点 | F2编辑 | Delete删除",
20, getHeight() - 15);
}
private void drawNode(Graphics2D g2d, MindNode node) {
// 绘制到子节点的连接线
if (!node.isLeaf() && node.isExpanded()) {
for (MindNode child : node.getChildren()) {
drawConnection(g2d, node, child);
drawNode(g2d, child);
}
}
// 绘制节点
drawNodeBox(g2d, node);
}
private void drawConnection(Graphics2D g2d, MindNode parent, MindNode child) {
// 使用贝塞尔曲线绘制连接线
int x1 = parent.getCenterX();
int y1 = parent.getCenterY();
int x2 = child.getX();
int y2 = child.getCenterY();
int controlX = (x1 + x2) / 2;
Path2D.Double path = new Path2D.Double();
path.moveTo(x1, y1);
path.curveTo(controlX, y1, controlX, y2, x2, y2);
g2d.setColor(new Color(0, 0, 0, 100));
g2d.setStroke(new BasicStroke(2));
g2d.draw(path);
// 绘制箭头
drawArrow(g2d, x2, y2, child.getColor());
}
private void drawArrow(Graphics2D g2d, int x, int y, Color color) {
// 绘制小箭头
g2d.setColor(color.darker());
int size = 8;
Polygon arrow = new Polygon();
arrow.addPoint(x, y - size/2);
arrow.addPoint(x + size, y);
arrow.addPoint(x, y + size/2);
g2d.fill(arrow);
}
private void drawNodeBox(Graphics2D g2d, MindNode node) {
// 绘制节点矩形
g2d.setColor(node.getColor());
g2d.fillRoundRect(node.getX(), node.getY(), node.getWidth(), node.getHeight(), 15, 15);
// 绘制节点边框
g2d.setColor(node.getColor().darker());
g2d.setStroke(new BasicStroke(1.5f));
g2d.drawRoundRect(node.getX(), node.getY(), node.getWidth(), node.getHeight(), 15, 15);
// 绘制节点文本
g2d.setColor(Color.BLACK);
g2d.setFont(new Font("微软雅黑", Font.PLAIN, 13));
FontMetrics fm = g2d.getFontMetrics();
int textWidth = fm.stringWidth(node.getText());
int textX = node.getX() + (node.getWidth() - textWidth) / 2;
int textY = node.getCenterY() + fm.getAscent() / 2 - 2;
g2d.drawString(node.getText(), textX, textY);
// 如果是根节点,绘制特殊样式
if (node.isRoot()) {
g2d.setColor(new Color(255, 255, 255, 200));
g2d.setFont(new Font("微软雅黑", Font.BOLD, 16));
fm = g2d.getFontMetrics();
textWidth = fm.stringWidth(node.getText());
textX = node.getX() + (node.getWidth() - textWidth) / 2;
textY = node.getCenterY() + fm.getAscent() / 2 - 2;
g2d.drawString(node.getText(), textX, textY);
}
// 如果节点有子节点且已展开,绘制展开图标
if (!node.isLeaf() && node.isExpanded()) {
g2d.setColor(new Color(0, 0, 0, 150));
g2d.drawString("-", node.getX() + node.getWidth() - 15, node.getCenterY() + 5);
} else if (!node.isLeaf()) {
g2d.setColor(new Color(0, 0, 0, 150));
g2d.drawString("+", node.getX() + node.getWidth() - 15, node.getCenterY() + 5);
}
}
}
运行方式
- 将代码保存为
MindMapDemo.java - 编译:
javac MindMapDemo.java - 运行:
java MindMapDemo
功能特性
基本操作
- 添加节点:工具栏按钮或快捷键 TAB
- 添加兄弟节点:工具栏按钮
- 删除节点:工具栏按钮或 Delete 键
- 编辑节点:工具栏按钮、F2 键或双击
交互功能
- 选择节点:单击选择节点
- 移动节点:按住 Shift 键拖动
- 展开/收起:双击节点
- 键盘方向键:微调选中节点位置
视图功能
- 自动布局:自动排列节点位置
- 展开/收起全部:一键展开或收起所有节点
- 节点颜色:自定义节点颜色
文件功能
- 保存/加载:支持保存和加载脑图数据
界面效果
- 使用贝塞尔曲线绘制节点连接线
- 圆角矩形节点样式
- 支持图标和表情符号(工具栏)
- 清晰的状态栏和操作提示
这个脑图工具包含了基本的思维导图功能,您可以根据需要添加更多特性,如节点图标、链接、备注等。