Swing完整实例 JTree(右键菜单,可拖拽)+JTable(可翻页,列中含有按钮,隐藏列)

本文介绍如何使用Java Swing构建文件管理界面,包括使用JTree实现树形目录展示与拖拽功能,以及JTable的定制与交互。通过详细代码示例,展示了如何设置布局、事件监听、数据绑定等关键步骤,提供了实现文件目录浏览与管理的完整解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先来看一下展示界面,JTree的特点有:节点可拖拽,根据输入生成目录,右键有菜单,点击触发事件等

                                           JTable的特点有:含有隐藏列,可以进行翻页,列中含有下载按钮等

有一点小技巧,在使用WindowsBuidler在画Swing界面时,Panel可以选择GridBagLayout的布局模式,采用这种布局时,所见即所得,还可以指定GridBag的长度是否可以增长:双击GridBag的任何一个行或列,会跳出一个属性框,在属性框中指定Resize Behavior 中的None即可设置改Grid不在增长。



在来看一下代码吧,基本代码由Eclipse上的WindowBuilder进行拖拽式产生的,所以看起来有点乱,不过没事

在使用WindowBuilder的时候要画JTree和JTable时要注意,这两个有几个共同点,必须放到JScrollPanel中,因为这两个控件的内容长度会发生突然变化,所以要使用JScrollPanel。

BTW:如果要使用WindowBuidler,除了在Eclipse上安装插件,最方便的方法是直接下载含有该插件的Eclipse版本:http://www.eclipse.org/downloads/packages/eclipse-ide-java-developers/keplerr


package test;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.border.EmptyBorder;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.tree.DefaultMutableTreeNode;


public class InnerDocsMgt extends JFrame {

	private static final long serialVersionUID = 1L;
	private JPanel contentPane;
	private JTable table;
	private JTree tree;
	private JLabel currentDirLabel;
	private JLabel totalFilesNumLabel;
	private List<VEachFile> docFils;
	private final int maxFilesAPage = 50;
	private JLabel curPageLabel;
	private int curPageNum = 0;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					InnerDocsMgt frame = new InnerDocsMgt();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public InnerDocsMgt() {
		setTitle("\u5185\u90E8\u8D44\u6599\u7BA1\u7406");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 450, 300);
		this.setSize(800, 600);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);

		JPanel panel = new JPanel();
		contentPane.add(panel, BorderLayout.WEST);
		GridBagLayout gbl_panel = new GridBagLayout();
		gbl_panel.columnWidths = new int[] { 54, 0, 0, 0, 0, 0, 0, 0 };
		gbl_panel.rowHeights = new int[] { 31, 0, 0 };
		gbl_panel.columnWeights = new double[] { 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
				0.0, Double.MIN_VALUE };
		gbl_panel.rowWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE };
		panel.setLayout(gbl_panel);

		JLabel lblNewLabel = new JLabel(
				"\u5185\u90E8\u8D44\u6599\u76EE\u5F55\u5217\u8868");
		GridBagConstraints gbc_lblNewLabel = new GridBagConstraints();
		gbc_lblNewLabel.gridwidth = 5;
		gbc_lblNewLabel.insets = new Insets(0, 0, 5, 5);
		gbc_lblNewLabel.gridx = 0;
		gbc_lblNewLabel.gridy = 0;
		panel.add(lblNewLabel, gbc_lblNewLabel);

		JButton button_4 = new JButton("\u4FDD\u5B58\u76EE\u5F55\u64CD\u4F5C");
		GridBagConstraints gbc_button_4 = new GridBagConstraints();
		gbc_button_4.insets = new Insets(0, 0, 5, 5);
		gbc_button_4.gridx = 5;
		gbc_button_4.gridy = 0;
		panel.add(button_4, gbc_button_4);

		JScrollPane scrollPane = new JScrollPane();
		GridBagConstraints gbc_scrollPane = new GridBagConstraints();
		gbc_scrollPane.gridwidth = 7;
		gbc_scrollPane.fill = GridBagConstraints.BOTH;
		gbc_scrollPane.gridx = 0;
		gbc_scrollPane.gridy = 1;
		panel.add(scrollPane, gbc_scrollPane);

		DefaultMutableTreeNode top = new DefaultMutableTreeNode("/");
		createNodes(top);
		tree = new JTree(top);
		scrollPane.setViewportView(tree);
		tree.setEditable(true);
		tree.setDragEnabled(true);
		this.setPopupMenu();
		try {
			tree.setTransferHandler(new DocsTreeTransferHanlder());
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

		JPanel panel_1 = new JPanel();
		contentPane.add(panel_1, BorderLayout.CENTER);
		GridBagLayout gbl_panel_1 = new GridBagLayout();
		gbl_panel_1.columnWidths = new int[] { 708, 0 };
		gbl_panel_1.rowHeights = new int[] { 556, 0 };
		gbl_panel_1.columnWeights = new double[] { 1.0, Double.MIN_VALUE };
		gbl_panel_1.rowWeights = new double[] { 1.0, Double.MIN_VALUE };
		panel_1.setLayout(gbl_panel_1);

		JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
		GridBagConstraints gbc_tabbedPane = new GridBagConstraints();
		gbc_tabbedPane.fill = GridBagConstraints.BOTH;
		gbc_tabbedPane.gridx = 0;
		gbc_tabbedPane.gridy = 0;
		panel_1.add(tabbedPane, gbc_tabbedPane);

		JPanel panel_2 = new JPanel();
		tabbedPane.addTab("\u6587\u4EF6\u4E0E\u76EE\u5F55\u7BA1\u7406", null,
				panel_2, null);
		GridBagLayout gbl_panel_2 = new GridBagLayout();
		gbl_panel_2.columnWidths = new int[] { 166, 59, 0, 0, 0, 0, 0 };
		gbl_panel_2.rowHeights = new int[] { 30, 0, 49, 0, 0, 0 };
		gbl_panel_2.columnWeights = new double[] { 1.0, 0.0, 0.0, 0.0, 0.0,
				0.0, Double.MIN_VALUE };
		gbl_panel_2.rowWeights = new double[] { 0.0, 0.0, 1.0, 0.0, 0.0,
				Double.MIN_VALUE };
		panel_2.setLayout(gbl_panel_2);

		currentDirLabel = new JLabel(
				"\u5F53\u524D\u76EE\u5F55\uFF1Aone->two->three");
		GridBagConstraints gbc_lblonetwothree = new GridBagConstraints();
		gbc_lblonetwothree.gridwidth = 6;
		gbc_lblonetwothree.anchor = GridBagConstraints.WEST;
		gbc_lblonetwothree.insets = new Insets(0, 0, 5, 0);
		gbc_lblonetwothree.gridx = 0;
		gbc_lblonetwothree.gridy = 0;
		panel_2.add(currentDirLabel, gbc_lblonetwothree);

		JButton button_3 = new JButton("\u5168\u9009/\u5168\u4E0D\u9009");
		GridBagConstraints gbc_button_3 = new GridBagConstraints();
		gbc_button_3.insets = new Insets(0, 0, 5, 5);
		gbc_button_3.gridx = 3;
		gbc_button_3.gridy = 1;
		panel_2.add(button_3, gbc_button_3);

		JButton button = new JButton("\u5220\u9664");
		GridBagConstraints gbc_button = new GridBagConstraints();
		gbc_button.insets = new Insets(0, 0, 5, 5);
		gbc_button.gridx = 4;
		gbc_button.gridy = 1;
		panel_2.add(button, gbc_button);

		JButton button_1 = new JButton("\u79FB\u52A8\u5230");
		button_1.setToolTipText("\u8BF7\u5148\u9009\u62E9\u8981\u79FB\u52A8\u7684\u6587\u4EF6\uFF0C\u7136\u540E\u518D\u9009\u62E9\u4E00\u4E2A\u5DE6\u4FA7\u76EE\u5F55");
		GridBagConstraints gbc_button_1 = new GridBagConstraints();
		gbc_button_1.insets = new Insets(0, 0, 5, 0);
		gbc_button_1.gridx = 5;
		gbc_button_1.gridy = 1;
		panel_2.add(button_1, gbc_button_1);

		JScrollPane scrollPane_1 = new JScrollPane();
		GridBagConstraints gbc_scrollPane_1 = new GridBagConstraints();
		gbc_scrollPane_1.gridwidth = 6;
		gbc_scrollPane_1.insets = new Insets(0, 0, 5, 0);
		gbc_scrollPane_1.fill = GridBagConstraints.BOTH;
		gbc_scrollPane_1.gridx = 0;
		gbc_scrollPane_1.gridy = 2;
		panel_2.add(scrollPane_1, gbc_scrollPane_1);

		String[] headNames = new String[] { "\u9009\u62E9",
				"\u6587\u4EF6\u540D", "\u5927\u5C0F\uFF08KB\uFF09",
				"\u6587\u4EF6\u65E5\u671F", "\u4F5C\u8005", "", "\u4E0B\u8F7D" };

		Object[][] tableDatas = new Object[50][7];
		for (int i = 0; i < 50; i++) {
			for (int j = 0; j < 7; j++) {
				tableDatas[i][j] = null;
			}
		}
		table = new JTable(new DocsTableModel(headNames, tableDatas));
		table.getColumnModel().getColumn(0)
				.setCellEditor(table.getDefaultEditor(Boolean.class));
		table.getColumnModel().getColumn(0)
				.setCellRenderer(table.getDefaultRenderer(Boolean.class));
		table.getColumnModel().getColumn(0).setPreferredWidth(38);
		table.getColumnModel().getColumn(1).setPreferredWidth(206);
		table.getColumnModel().getColumn(2).setPreferredWidth(53);
		table.getColumnModel().getColumn(3).setPreferredWidth(134);
		table.getColumnModel().getColumn(4).setPreferredWidth(58);
		
		// hide the 5th column,it contans the filepath
		table.getTableHeader().getColumnModel().getColumn(5).setMaxWidth(0);// hide
		table.getTableHeader().getColumnModel().getColumn(5).setMinWidth(0);// hide
		table.getTableHeader().getColumnModel().getColumn(5)
				.setPreferredWidth(0);
		table.getTableHeader().getColumnModel().getColumn(5).setWidth(0);
		table.getColumnModel().getColumn(6)
				.setCellRenderer(new ButtonCellRenderer());
		table.getColumnModel().getColumn(6)
				.setCellEditor(new ButtonCellEditor(table));
		scrollPane_1.setViewportView(table);
		totalFilesNumLabel = new JLabel("\u6587\u4EF6\u603B\u6570\uFF1A0");
		GridBagConstraints gbc_totalFilesNumLabel = new GridBagConstraints();
		gbc_totalFilesNumLabel.anchor = GridBagConstraints.WEST;
		gbc_totalFilesNumLabel.insets = new Insets(0, 0, 0, 5);
		gbc_totalFilesNumLabel.gridx = 0;
		gbc_totalFilesNumLabel.gridy = 4;
		panel_2.add(totalFilesNumLabel, gbc_totalFilesNumLabel);
		curPageLabel = new JLabel(
				"\u5F53\u524D\u9875\u6570\uFF1A0| \u603B\u9875\u6570\uFF1A0");
		GridBagConstraints gbc_curPageLabel = new GridBagConstraints();
		gbc_curPageLabel.gridwidth = 2;
		gbc_curPageLabel.insets = new Insets(0, 0, 0, 5);
		gbc_curPageLabel.gridx = 2;
		gbc_curPageLabel.gridy = 4;
		panel_2.add(curPageLabel, gbc_curPageLabel);
		JButton btnNewButton = new JButton("\u4E0A\u4E00\u9875");
		btnNewButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				prePage();
			}
		});
		GridBagConstraints gbc_btnNewButton = new GridBagConstraints();
		gbc_btnNewButton.insets = new Insets(0, 0, 0, 5);
		gbc_btnNewButton.gridx = 4;
		gbc_btnNewButton.gridy = 4;
		panel_2.add(btnNewButton, gbc_btnNewButton);
		JButton button_2 = new JButton("\u4E0B\u4E00\u9875");
		button_2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				nextPage();
			}
		});
		GridBagConstraints gbc_button_2 = new GridBagConstraints();
		gbc_button_2.gridx = 5;
		gbc_button_2.gridy = 4;
		panel_2.add(button_2, gbc_button_2);
		JPanel panel_3 = new JPanel();
		tabbedPane.addTab("\u7F16\u8F91\u6587\u6863", null, panel_3, null);
		GridBagLayout gbl_panel_3 = new GridBagLayout();
		gbl_panel_3.columnWidths = new int[] { 0 };
		gbl_panel_3.rowHeights = new int[] { 0 };
		gbl_panel_3.columnWeights = new double[] { Double.MIN_VALUE };
		gbl_panel_3.rowWeights = new double[] { Double.MIN_VALUE };
		panel_3.setLayout(gbl_panel_3);
	}

	private void createNodes(DefaultMutableTreeNode top) {
		List<DefaultMutableTreeNode> nodes = DocsMgtRmi.getINS()
				.getFirstLevelDirs();
		for (DefaultMutableTreeNode one : nodes) {
			top.add(one);
		}
	}

	public void setPopupMenu() {
		final JPopupMenu pop = new JPopupMenu();
		pop.add(new AbstractAction("添加子目录") {
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				System.out.println("Tree Add");
			}
		});
		pop.add(new AbstractAction("删除目录") {
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				System.out.println("Delete");
			}
		});
		tree.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseReleased(MouseEvent e) {
				if (e.isMetaDown()) {
					pop.show(tree, e.getX(), e.getY());
				}
			}

			public void mouseClicked(MouseEvent evt) {
				if (evt.getClickCount() == 1) {
					VEachDir eDir = (VEachDir) getSelectedNode()
							.getUserObject();
					docFils = DocsMgtRmi.getINS().getFilesViaDirid(
							eDir.getDirId());
					int filesNum = docFils.size();
					currentDirLabel
							.setText("\u5F53\u524D\u76EE\u5F55\uFF1Aone->two->three,=>DirID:"
									+ eDir.getDirId());
					totalFilesNumLabel.setText("\u6587\u4EF6\u603B\u6570\uFF1A"
							+ filesNum);
					int maxNum = Math.min(maxFilesAPage, filesNum);
					if (filesNum <= maxFilesAPage) {
						curPageLabel
								.setText("\u5F53\u524D\u9875\u6570\uFF1A 1 | \u603B\u9875\u6570\uFF1A 1");
					} else {
						int totalNum = filesNum / maxFilesAPage;
						if (totalNum * maxFilesAPage < filesNum) {
							totalNum++;
						}
						curPageLabel
								.setText("\u5F53\u524D\u9875\u6570\uFF1A 1 | \u603B\u9875\u6570\uFF1A "
										+ totalNum);
					}
					curPageNum = 0;
					setDocTableValues(docFils.subList(0, maxNum));
				}
			}
		});
	}

	public void prePage() {
		if (this.curPageNum <= 0) {
			return;
		}
		int filesNum = docFils.size();
		curPageNum--;
		int totalPage = filesNum / maxFilesAPage;
		if (totalPage * maxFilesAPage < filesNum) {
			totalPage++;
		}
		curPageLabel
				.setText("\u5F53\u524D\u9875\u6570\uFF1A " + (curPageNum + 1)
						+ " | \u603B\u9875\u6570\uFF1A " + totalPage);
		setDocTableValues(docFils.subList(curPageNum * maxFilesAPage,
				Math.min((curPageNum + 1) * maxFilesAPage, filesNum)));
	}

	public void nextPage() {
		int filesNum = docFils.size();
		int totalPage = filesNum / maxFilesAPage;
		if (totalPage * maxFilesAPage < filesNum) {
			totalPage++;
		}
		if (curPageNum >= totalPage - 1) {
			return;
		}
		curPageNum++;
		setDocTableValues(docFils.subList(curPageNum * maxFilesAPage,
				Math.min((curPageNum + 1) * maxFilesAPage, filesNum)));
		curPageLabel
				.setText("\u5F53\u524D\u9875\u6570\uFF1A " + (curPageNum + 1)
						+ " | \u603B\u9875\u6570\uFF1A " + totalPage);
	}

	public void setDocTableValues(List<VEachFile> subDocs) {
		int i = 0;
		for (; i < subDocs.size(); i++) {
			table.getModel().setValueAt(false, i, 0);
			table.getModel().setValueAt(subDocs.get(i).getFileName(), i, 1);
			table.getModel().setValueAt(subDocs.get(i).getFileSize(), i, 2);
			table.getModel().setValueAt(
					subDocs.get(i).getFileDate().toLocaleString(), i, 3);
			table.getModel().setValueAt(subDocs.get(i).getFileAuthor(), i, 4);
			table.getModel().setValueAt(subDocs.get(i).getFilePath(), i, 5);
		}
		if (subDocs.size() < maxFilesAPage) {
			for (; i < maxFilesAPage; i++) {
				table.getModel().setValueAt(false, i, 0);
				table.getModel().setValueAt(null, i, 1);
				table.getModel().setValueAt(null, i, 2);
				table.getModel().setValueAt(null, i, 3);
				table.getModel().setValueAt(null, i, 4);
				table.getModel().setValueAt(null, i, 5);
			}
		}
		table.updateUI();
		table.repaint();
	}

	public DefaultMutableTreeNode getSelectedNode() {
		return (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
	}

	class DocsTableModel extends AbstractTableModel {
		private String headName[];
		private Object obj[][];
		private Class[] columnTypes = new Class[] { Boolean.class,
				Object.class, Object.class, Object.class, Object.class,
				Object.class, Object.class };

		public DocsTableModel() {
			super();
		}

		public DocsTableModel(String[] headName, Object[][] obj) {
			this();
			this.headName = headName;
			this.obj = obj;
		}

		public int getColumnCount() {
			return headName.length;
		}

		public int getRowCount() {
			return obj.length;
		}

		public Object getValueAt(int r, int c) {
			return obj[r][c];
		}

		public String getColumnName(int c) {
			return headName[c];
		}

		public Class<?> getColumnClass(int columnIndex) {
			return columnTypes[columnIndex].getClass();
		}

		@Override
		public boolean isCellEditable(int rowIndex, int columnIndex) {
			return true;
		}

		public void setValueAt(Object value, int row, int col) {
			obj[row][col] = value;
			fireTableCellUpdated(row, col);
		}
	}
}

class ButtonCellEditor extends DefaultCellEditor {
	private static final long serialVersionUID = -6546334664166791132L;
	private JButton button;
	private JTable table;

	public ButtonCellEditor(JTable table) {
		super(new JTextField());
		this.setClickCountToStart(1);
		this.initButton();
		this.table = table;
	}

	private void initButton() {
		this.button = new JButton();
		this.button.setSize(50, 15);
		this.button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				ButtonCellEditor.this.fireEditingCanceled();
				System.out.println("Selected Column:"
						+ table.getSelectedColumn()
						+ ",row:"
						+ table.getSelectedRow()
						+ ",and filePath:"
						+ table.getModel()
								.getValueAt(table.getSelectedRow(), 5));
			}
		});
	}

	@Override
	public Component getTableCellEditorComponent(JTable table, Object value,
			boolean isSelected, int row, int column) {
		this.button.setText("下载");
		return this.button;
	}

	@Override
	public Object getCellEditorValue() {
		return this.button.getText();
	}
}

class ButtonCellRenderer implements TableCellRenderer {
	private JButton button;

	public ButtonCellRenderer() {
		this.button = new JButton();
	}

	public Component getTableCellRendererComponent(JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int column) {
		this.button.setText("下载");
		return this.button;
	}
}



关于上面的TableCellRenderer子类和CellEditor子类,这两个都被设置到table的ColumnModel中了, ButtonCellRenderer在每次GUI渲染的时候都会调用,ButtonCellEditor只会在点击到这个Cell的时候才会调用,并且如果失去焦点后return的Component将消失,所以ButtonCellRenderer这个很重要。
table.getColumnModel().getColumn(7).setCellRenderer(new ButtonCellRenderer());table.getColumnModel().getColumn(7).setCellEditor(new ButtonCellEditor(table)); 
可以在ButtonCellRenderer中加上一些逻辑,用来判断是否显示按钮,比如在初始化的时候不要显示按钮,比如可以可以根据隐藏列的值显示按钮,只要修改getTableRenderComponent方法即可。
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
String filePath = (String) table.getModel().getValueAt(row, 7);
if (filePath == null) {
return null;
} else {
this.button.setText("下载");
return this.button;
}
}

下面讲一下支持Tree拖拽的事件响应器DocsTreeTransferHanlder,TransferHanlder用来处理Transferable一个Swing Component对象上的transfer to和from,就是拖拽,而Transferable对象代表通过剪切到,拷贝自剪贴板上的数据对象。
这几个对象被用来实现拖拽,TansferHanlder对拖拽支持良好,开发者只需要实现一个具体的Transfer对象,然后将hanlder设置到Swing组件上。
Please see How to Use Drag and Drop and Data Transfer, a section in The Java Tutorial, for more information. 
简单的说,通过TransferHandler来实现拖拽,首先要创建Transferable对象JTreeTransferable,然后比较重要的是ImportData和exportDone方法,在importData方法中可以通过Support对象获取DropLocation,然后通过TreePath的getLastPathComponent方法得到拖拽的目标Tree对象结点,继而通过getUserObject可以获得之前自定义的放到TreeNode的用户数据,如下面下面四句:
JTree.DropLocation location = (JTree.DropLocation) support.getDropLocation();
DefaultMutableTreeNode newParent = (DefaultMutableTreeNode) location.getPath().getLastPathComponent();
VEachDir eDir = (VEachDir) newParent.getUserObject();
System.out.println("The drage after NewParent DirName:"+ eDir.getDirName() + ",DirID:" + eDir.getDirId());
显然按照之前的理论 Transfer中放置的是被移动的对象,则通过下面的两句就可以得到被移动对象的结点列表,要注意的是这个地方是列表,即表示拖拽时可以使用Shift来选择多个结点进行拖拽到一个目标结点!
Transferable transfer = support.getTransferable();
List<DefaultMutableTreeNode> nodes = (List<DefaultMutableTreeNode>) transfer.getTransferData(JTreeTransferable.FLAVOR);
由此可见通过拖拽过程的实现,最重要的一个类是TransferHandler.TransferSupport 类,这个类中包含了目的树节点和源节点列表,最重要的是,我们可以不用丝毫关心Support怎么做到的,只要记住怎么获取源和目的就行了。


当然在拖拽之前,实现TranseferHanlder最重要的就是创建自己的Transferable对象,这个其实也比较简单,就两点(1)创建Favor (2)塞入TreeNodes 就可以了
由此可见Swing实现JTree的拖拽非常强大吧!


package test;

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JComponent;
import javax.swing.JTree;
import javax.swing.TransferHandler;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

import com.car.cs.pojodata.VEachDir;

public class DocsTreeTransferHanlder extends TransferHandler {

	private static final long serialVersionUID = 1910170308494195795L;

	public int getSourceActions(JComponent c) {
		return MOVE;
	}

	@Override
	protected Transferable createTransferable(JComponent c) {
		JTree tree = (JTree) c;
		TreePath[] paths = tree.getSelectionPaths();
		ArrayList nodes = new ArrayList();
		for (TreePath path : paths) {
			nodes.add(path.getLastPathComponent());
		}
		return new JTreeTransferable(nodes);
	}

	@Override
	protected void exportDone(JComponent source, Transferable data, int action) {
	}

	@Override
	public boolean canImport(TransferSupport support) {
		if (support.isDataFlavorSupported(JTreeTransferable.FLAVOR)) {
			if (support.getDropAction() == MOVE)
				return true;
		}
		return false;
	}

	@Override
	public boolean importData(TransferSupport support) {
		System.out.println("ImportData");
		JTree tree = (JTree) support.getComponent();
		DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
		Transferable transfer = support.getTransferable();
		try {
			List<DefaultMutableTreeNode> nodes = (List<DefaultMutableTreeNode>) transfer
					.getTransferData(JTreeTransferable.FLAVOR);
			JTree.DropLocation location = (JTree.DropLocation) support
					.getDropLocation();
			DefaultMutableTreeNode newParent = (DefaultMutableTreeNode) location
					.getPath().getLastPathComponent();

			VEachDir eDir = (VEachDir) newParent.getUserObject();
			System.out.println("The drage after NewParent DirName:"
					+ eDir.getDirName() + ",DirID:" + eDir.getDirId());

			for (DefaultMutableTreeNode node : nodes) {
				eDir = (VEachDir) node.getUserObject();
				System.out.println("Before Drag the Node DirName:"
						+ eDir.getDirName());
				model.removeNodeFromParent(node);
				model.insertNodeInto(node, newParent, newParent.getChildCount());
			}
		} catch (UnsupportedFlavorException e) {
			e.printStackTrace();
			return false;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
}

class JTreeTransferable implements Transferable {
	public static DataFlavor FLAVOR = null;
	private List<DefaultMutableTreeNode> nodes;

	public JTreeTransferable(ArrayList<DefaultMutableTreeNode> nodes) {
		try {
			FLAVOR = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType
					+ ";class=\"" + ArrayList.class.getName() + "\"");
			this.nodes = nodes;
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	public Object getTransferData(DataFlavor flavor)
			throws UnsupportedFlavorException, IOException {
		return nodes;
	}

	public DataFlavor[] getTransferDataFlavors() {
		return new DataFlavor[] { FLAVOR };
	}

	public boolean isDataFlavorSupported(DataFlavor flv) {
		return FLAVOR.equals(flv);
	}
}



其中里面用到的制造数据的DocsMgtRmi类,和里面用到的两个POJO对象VEachDir和VEachFile。

package test;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.swing.tree.DefaultMutableTreeNode;
import org.apache.log4j.Logger;

public class DocsMgtRmi {

	private final Logger logger = Logger.getLogger(DocsMgtRmi.class);
	private static DocsMgtRmi rmi = null;

	public static DocsMgtRmi getINS() {
		if (rmi == null) {
			synchronized (DocsMgtRmi.class) {
				if (rmi == null) {
					rmi = new DocsMgtRmi();
				}
			}
		}
		return rmi;
	}

	private DocsMgtRmi() {
		
	}

	public List<DefaultMutableTreeNode> getFirstLevelDirs() {

		ArrayList<DefaultMutableTreeNode> nodes = new ArrayList<DefaultMutableTreeNode>();

		DefaultMutableTreeNode fstnode = null;
		for (int i = 0; i < 10; i++) {
			VEachDir fstLevelDir = new VEachDir(i, "200" + i + "年以前规章", 0);
			fstnode = new DefaultMutableTreeNode(fstLevelDir);
			nodes.add(fstnode);
		}

		for (int i = 0; i < 10; i++) {
			VEachDir secLevelDir = new VEachDir(i, "2009年投诉建议-卷" + i, 9);
			DefaultMutableTreeNode secNode = new DefaultMutableTreeNode(
					secLevelDir);
			fstnode.add(secNode);
		}

		return nodes;
	}

	public List<VEachFile> getFilesViaDirid(int dirId) {

		ArrayList<VEachFile> files = new ArrayList<VEachFile>();
		for (int i = 0; i < 97; i++) {
			VEachFile one = new VEachFile(dirId, "天上星,亮晶晶,那是" + i + "双双眼睛.txt",
					1000, new Date(), "张为山", "one->two-" + i + "-<>");
			files.add(one);
		}
		return files;

	}

	public boolean saveDirChanged(List<VEachDir> dirs) {

		return true;
	}

}

两个实体类VEachFile和VEachDir


package test;
import java.util.Date;

public class VEachFile {
	private int dirId;
	private String fileName;
	private int fileSize;
	private Date fileDate;
	private String fileAuthor;
	private String filePath;

	public VEachFile(int dirId, String fileName, int fileSize, Date fileDate,
			String fileAuthor, String filePath) {
		super();
		this.dirId = dirId;
		this.fileName = fileName;
		this.fileSize = fileSize;
		this.fileDate = fileDate;
		this.fileAuthor = fileAuthor;
		this.filePath = filePath;
	}

	public int getDirId() {
		return dirId;
	}
	public void setDirId(int dirId) {
		this.dirId = dirId;
	}
	public String getFileName() {
		return fileName;
	}
	public void setFileName(String fileName) {
		this.fileName = fileName;
	}

	public int getFileSize() {
		return fileSize;
	}

	public void setFileSize(int fileSize) {
		this.fileSize = fileSize;
	}

	public Date getFileDate() {
		return fileDate;
	}

	public void setFileDate(Date fileDate) {
		this.fileDate = fileDate;
	}

	public String getFileAuthor() {
		return fileAuthor;
	}

	public void setFileAuthor(String fileAuthor) {
		this.fileAuthor = fileAuthor;
	}

	public String getFilePath() {
		return filePath;
	}

	public void setFilePath(String filePath) {
		this.filePath = filePath;
	}

}

package test;
public class VEachDir {

	private int dirId;
	private String dirName;
	private int parentDirId;

	public VEachDir(int dirId, String dirName, int parentDirId) {
		super();
		this.dirId = dirId;
		this.dirName = dirName;
		this.parentDirId = parentDirId;
	}

	public int getDirId() {
		return dirId;
	}

	public void setDirId(int dirId) {
		this.dirId = dirId;
	}

	public String getDirName() {
		return dirName;
	}

	public void setDirName(String dirName) {
		this.dirName = dirName;
	}

	public int getParentDirId() {
		return parentDirId;
	}

	public void setParentDirId(int parentDirId) {
		this.parentDirId = parentDirId;
	}

	public String toString() {

		return this.dirName;
	}

}







目录 目录 1 () Spring 开发 Swing GUI 简介——依赖注入和富客户机 5 关于本教程 5 前提条件 6 Spring 和依赖注入概述 7 什么是 Spring 框架? 7 什么是依赖注入? 7 环境设置 7 选择编译环境 7 设置 Ant 8 通过 Ant 自动下载依赖软件 10 设置 Maven 10 通过 Maven 自动下载依赖软件 12 设置 Eclipse 13 下载依赖的 JAR 文件并在 Eclipse 的 classpath 中定义这种依赖性 15 创建 to-do 表:基本的 Swing 和 Spring 应用程序设置 17 创建 MainFrame、Launcher 和 ToDo 类 17 创建 Spring app-context.xml bean 定义文件 19 运行应用程序 20 定义 bean 属性 21 创建 to-do 表:创建一个可重用组件并在表中显示数据 23 创建一个可重用的面板 23 将 bean 组合在一起 24 添加一个表并重用这个面板 26 定义表模型 28 显示表中的项 29 创建 to-do 表:完成 —— 按钮和监听程序 31 创建按钮和监听程序 32 组合按钮和监听程序 35 Spring Rich Client Project 37 Spring Rich Client Project 概述 37 结束语 38 () 适用于各类Swing应用的通用数据验证模块 39 项目创建好后,加入类库: 41 然后写一个persistence bean: 41 Java代码 41 我称这个类为HibernateValidationUI,代码如下: 43 Java代码 43 类中用到的Java2DIconFactory代码如下: 47 Java代码 47 Factory类 49 Java代码 49 最后,我们可以编写一个Demo application来看看效果如何,代码如下: 51 Java代码 51 总结: 55 ()JTree从创建到使用详解 56 () JTree的使用方法 57 JTreeDemo.java源程序 57 经验汇总 60 1. 初始化 60 2. 三个经常使用的取值函数 60 3. 根据node得到path: 60 4. 根据Path展开到该节点 60 5. 根据path设定该节点选定 61 6. 选中节点的方法 61 7. 滚动到可见位置 61 8. 给JTree添加右键弹出菜单 61 9. 关于JTree的展开 61 10. 如何遍历JTree 62 () JTree右键菜单实现编辑、添加、删除节点 63 Test.java源代码 63 () 功能齐全的JTree例子 66 TreeEditTest.java源代码 66 () JTree控件的使用 70 构造函数: 70 TreeModel接口 70 DefaultTreeModel缺省版本 71 TreeNode接口 71 TreeExpansionListener接口 71 TreeCellRenderer 72 例子: 73 () 如何为JTree添加右键菜单? 75 () 如何使JTextArea随着窗体的变化自动调整大小 76 TextAreaTest源代码 76 () JAVA swing编程JTree实现系统目录 77 FileTree1.java源代码 77 (十一) Java Swing中的JTree模型 85 Swing.tree包中的主要类名称实现 85 1. 构建树模型 86 2. 树结点 86 树结构详细类图 86 2.1 TreeNode接口 86 2.2 MutableTreeNode接口 87 2.3 DefaultMutableTreeNode类 88 3. 编辑树 88 3.1获得结点路径 88 3.2编辑结点 88 3.3视图显示 89 4. 查找树 89 5. 绘制结点 90 (十二) JTree鼠标左键的双击事件选用那个监听器 91 MouseDemo.java源代码 92 (十三) JTree 92 JTree的构造函数: 93 JTreeDefaultDemo.java源代码 93 (十四) JTree 应用 96 Frame1.java源代码 96 MyDefaultTreeCellRenderer.java源代码 98 (十五) JTree控件 100 树和节点的基本概念 100 有关树JTree的类和接口 100 代码实例:构建一棵树 101 相关语句解释 101 (十六) JTree应用示例——文件路径 103 AnimatedIconTreeExample.java源代码 103 //内部类NodeImageObserver.java源代码 105 //IconNodeRenderer.java源代码 106 //IconNode.java源代码 107 (十七) Swing 学习笔记 108 Swing API 包括18个公共包: 108 例程1.1 HelloWorldSwing.java 109 例程2.2 HelloWorldJFrame.java 110 (十八) 动态加载文件树的java程序 111 FileSystemTree.java源代码 112 //内部类 TreeWillExpandListenerImp.java 114 (十九) 向 Java 应用程序伸出援助之手——用 JavaHelp 2.0 构建下一个 Java 应用程序的帮助系统 115 入门 116 使用 HelpSet 117 HelpSet 数据文件 118 helpset 文件 118 maps 部分 119 view 部分 119 presentation 部分 120 implementation 部分 121 map 文件 121 导航文件 121 TOC 122 Index 122 Glossary 123 Favorites 123 主题文件 123 在 Java 应用程序中调用 JavaHelp 124 自定义外观 125 配置图标 125 基于文字的标签还是基于图像的标签? 125 要工具栏还是不要工具栏? 125 设置字体 126 使用展示窗口 127 <object> 标签 128 四种 activator 129 添加内容敏感的帮助 130 窗口级帮助 131 字段级帮助 131 屏幕级帮助 133 添加嵌入帮助 135 添加搜索功能 136 停用词 137 自定义停用词表 137 合并 helpset 138 静态和动态合并 139 添加轻量级组件 141 基于服务器的帮助 144 设置 144 JavaHelp 服务器 bean 144 JavaScript 文件 145 JSP 文件 145 测试服务器端帮助 148 结束语 149
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值