JAVA课设的时候,网上百度没有完全符合以下要求的帖子,在拼凑完成课设后,发出来给大家分享
必做需求:①左侧以树形结构列出本机文件系统,根为“我的电脑”;②点击左侧结点,右侧 以表格展示其下文件/文件夹,包含文件名、大小、修改日期、文件类型等列;③单击右侧表头可按该列升降排序;④右侧文件/文件夹支持右键菜单,以完成常用的文件/文件夹管理功能(复制、粘贴、删除、剪切、重命名等)。选做需求:支持常用文件类型(文本、图片等)的预览
运行截图:
可以右侧表头升降序排列
源代码:
为了方便伙伴们使用,特地截图代码的包目录分布:
1、节点渲染器类 FolderRenderer .javapackage CLASS;
import java.awt.Component;
import javax.swing.Icon;
import javax.swing.JTree;
import javax.swing.filechooser.FileSystemView;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
public class FolderRenderer extends DefaultTreeCellRenderer { //自定义渲染器类,以描述节点的显示细节,此处的主要作用是渲染图片
private static FileSystemView fsView;
private static final long serialVersionUID = 1L;
//重写父类方法
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean sel, boolean expanded, boolean leaf, int row,
boolean hasFocus) {//将当前树单元格的值设置为 value。如果 selected 为 true,则将单元格作为已选择的单元格进行绘制。
//如果 expanded 为 true,则当前扩展该节点,如果 leaf 为 true,则该节点表示叶节点,如果 hasFocus 为 true,则该节点当前拥有焦点。tree 是为其配置接收者的 JTree。返回渲染器用来绘制值的 Component。
fsView = FileSystemView.getFileSystemView();//获取FileSystemView的实例
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) value;//获取当前节点
NodeData data = (NodeData) selectedNode.getUserObject();//取得节点的用户对象
Icon icon = fsView.getSystemIcon(data.f);//Icon为图片
setLeafIcon(icon);//用于显示叶节点的图标
setOpenIcon(icon);//用于显示扩展的非叶节点的图标
setClosedIcon(icon);//设置用于显示无扩展的非叶节点的图标
return super.getTreeCellRendererComponent(tree, value, sel, expanded,
leaf, row, hasFocus);
}
}
2、文件节点类
package CLASS;
import java.io.File;
public class NodeData//文件节点类
{
public File f;
public String Name;
public NodeData(File f,String Name)
{
this.f = f;
this.Name = Name;
}
public String toString()
{
return Name;
}
public void ChangeString(String s)
{
Name = s;
}
public NodeData(File file) {
this.f = file;
}
}
3、GUI窗口创建和各项处理事件代码
package ui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.MenuItem;
import java.awt.Panel;
import java.awt.PopupMenu;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Date;
import java.text.SimpleDateFormat;
//
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.filechooser.FileSystemView;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import CLASS.FolderRenderer;
import CLASS.NodeData;
@SuppressWarnings("unused")
public class MyTree
{
TreePath copyPath;
JFrame jf;
JTree tree;//树结构
JTable table;//表格
Object[][] list = { {} };
DefaultTableModel tableModel;//表格模型
DefaultMutableTreeNode parent;
DefaultTreeModel model;//声明树状视图模型 以指定的模型创建一棵树,DefaultTreeModel自行查阅API
PopupMenu pop = new PopupMenu();//右键弹出菜单
MenuItem deleteItem = new MenuItem("删除");
MenuItem renameItem = new MenuItem("重命名");
MenuItem natrueItem = new MenuItem("属性");
MenuItem copyItem=new MenuItem("复制");
MenuItem pasteItem=new MenuItem("粘贴");
DefaultMutableTreeNode root = new DefaultMutableTreeNode(new NodeData(null,"我的电脑"));//自定义一个名为root的节点,后面作为根节点创建一棵树 NodeData是自定义节点类。
//用于重命名时生成一个原节点的克隆体
DefaultMutableTreeNode aClone;
public void init()
{
jf = new JFrame("文件资源管理器");
jf.setSize(600, 600);
File[] roots = File.listRoots();//获得系统根目录文件 需要获取磁盘中所有的盘符路径:jdk6中一个方法搞定
for(int i = 0;i < roots.length;i++)
{
DefaultMutableTreeNode node = new DefaultMutableTreeNode(new NodeData(roots[i],roots[i].getAbsolutePath()));//NodeDate自定义节点类
root.add(node);//从父节点删除 newChild并将其添加到该节点的子数组的末尾,使其成为该节点的子节点
}
tree = new JTree(root);//以指定的自定义的节点(root)作为根节点创建一棵树
model = (DefaultTreeModel) tree.getModel();//获取Jtree对应的TreeModel的对象,即获取树的数据模型
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);//一次只能选中一个节点先返回树的选择模型才能设置树的选择模型 contiguous连续的
// getSelectionModel()返回模型进行选择 setSelectionMode设置树的选择模型 。
tree.setCellRenderer(new FolderRenderer());//设置使用定制的节点绘制器
String[] row = { "文件名", "类型","最后修改日期", "大小" };
tableModel = new DefaultTableModel(list, row);
table = new JTable(tableModel);
//表格升降序
TableRowSorter sorter = new TableRowSorter(tableModel);
table.setRowSorter(sorter);
JScrollPane scrollTable = new JScrollPane(table);//显示区为table表格的可滚动面板
scrollTable.setPreferredSize(new Dimension(500, 500));
jf.add(BorderLayout.CENTER,scrollTable);//使用边界布局
//e.path() 返回已更改节点的父节点的路径。
//e.childIndices() 返回更改节点的索引。
//当用户完成一个节点的编辑时,这个 model 产生一个 tree model 事件,它会告诉所有监听者(包括 Jtree ):树节点被改变了。注意:尽管 DefaultMutableTreeNode 拥有改变一个节点内容的方法,但是改变还是需要通过 DefaultTreeModel 上面的方法。否则, tree model 事件就不能产生,事件的监听者(例如 tree )就不能知道这些更新。
//为了通知“节点改变”,我们可以实现一个 TreeModelListener 。这里有一个关于 tree model 监听器的例子,当用户为一个树节点输入一个新名字时,事件会被检测到。
model.addTreeModelListener(new TreeModelListener()
{
public void treeNodesChanged(TreeModelEvent e)//当树的节点改变时就调用这个方法
{
//获得编辑后的节点的父节点
DefaultMutableTreeNode parent = (DefaultMutableTreeNode)(e.getTreePath().getLastPathComponent());//返回从根节点到该节点的路径,在找到树种最后一个选中的节点
DefaultMutableTreeNode node;
try
{
int []index = e.getChildIndices();//返回目前修改点的索引值
node = (DefaultMutableTreeNode)(parent.getChildAt(index[0]));//getChildAt()方法取得修改的節點對象.
//System.out.println(aClone.toString());
//克隆体更新名称,file不变
((NodeData)aClone.getUserObject()).ChangeString(node.toString());
//删除选定节点且要求该节点存在父节点
model.removeNodeFromParent(node);
//添加克隆体
model.insertNodeInto(aClone,parent,index[0]);//在父节点的子节点中的 index 处插入aClone
}
catch (NullPointerException exc) //點選的節點為root node,則getChildIndices()的返回值為null,root node產生的NullPointerException問題.
{
System.out.println("model error");
}
//系统实现改名
NodeData data = (NodeData) aClone.getUserObject();
String tt = data.f.getParent() + "//";
tt = tt + aClone.toString();
File newfile = new File(tt);
data.f.renameTo(newfile);//将文件改名为 指定的名字
data.f = newfile;
return;
}
public void treeStructureChanged(TreeModelEvent e){} //当树的结构改变时就调用这个方法
public void treeNodesRemoved(TreeModelEvent e){} // 当属的节点删除时就调用这个方法
public void treeNodesInserted(TreeModelEvent e){} //当树的节点添加时就调用这个方法
});
//为pop添加菜单项
pop.add(deleteItem);
pop.addSeparator();
pop.add(renameItem);
pop.addSeparator();
pop.add(copyItem);
pop.addSeparator();
pop.add(pasteItem);
pop.addSeparator();
pop.add(natrueItem);
//属性功能
natrueItem.addActionListener(new ActionListener()
{ //属性功能
public void actionPerformed(ActionEvent event){
JDialog subDialog;
subDialog=new JDialog(jf,"属性");
subDialog.setVisible(true);
subDialog.setSize(400,400);
JTextArea text=new JTextArea();
subDialog.getContentPane().add(text);
TreePath tp=tree.getSelectionPath();//得到树状视图的被选择节点路径
String fullPath="";//得到被选择节点对应文件的完整路径信息
for(Object obj:tp.getPath())
{
String str=obj.toString();
if(str.endsWith("\\"))//处理盘符根目录问题
str=str.substring(0,str.length()-1);
if(fullPath.equals(""))
fullPath+=str;
else
fullPath+="\\"+str;
}
int n=fullPath.indexOf("脑");
String sp=fullPath.substring(n+2);
File currentFile=new File(sp);
StringBuffer sb=new StringBuffer();
if(currentFile.isDirectory())
sb.append("文件夹路径:"+currentFile.getAbsolutePath()+"\n");
else
sb.append("文件路径:"+currentFile.getAbsolutePath()+"\n");
sb.append("是否可读"+currentFile.canRead()+"\n");
sb.append("是否可写"+currentFile.canWrite()+"\n");
if(!currentFile.isDirectory())
sb.append("文件的长度:"+currentFile.length()/(1024*1024)+"M\n");
SimpleDateFormat s=new SimpleDateFormat("yyyy年MM年dd日HH小时mm分钟ss秒");
sb.append("文件上次修改的时间:"+s.format(new Date(currentFile.lastModified()))+"\n");
sb.append("文件是否被隐藏:"+currentFile.isHidden()+"\n");
text.setText(sb.toString());
}
});
//菜单项deleteItem的动作侦听器
deleteItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
//获取选中节点
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
if(selectedNode == null)
return;
//获得节点数据
NodeData data = (NodeData) selectedNode.getUserObject();
//显示是否删除的确认对话框
int n = JOptionPane.showConfirmDialog(tree,"确认删除吗?","确认对话框",JOptionPane.YES_NO_OPTION);
if(n == JOptionPane.NO_OPTION)
return;
//如果该节点是文件
if(selectedNode == root)
{
JOptionPane.showMessageDialog(tree,"本地磁盘不能被删除","警告对话框",JOptionPane.WARNING_MESSAGE);
return;
}
else if(data.f.isFile())
{
//删除文件
delFile(data.f.getAbsolutePath());
}
else if(data.f.isDirectory())
{
//删除文件夹
if(selectedNode.getParent() != root)
delFolder(data.f.getAbsolutePath());
else
{
JOptionPane.showMessageDialog(tree,"本地磁盘不能被删除","警告对话框",JOptionPane.WARNING_MESSAGE);
return;
}
}
//处理树节点的删除
model.removeNodeFromParent(selectedNode);
}
});
//菜单项renameItem的动作监控器
renameItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
//设置可编辑
tree.setEditable(true);
//获取选中节点
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
TreePath editPath = tree.getSelectionPath();//得到被选择节点的路径
if(selectedNode == null)
return;
//开始编辑
tree.startEditingAtPath(editPath);//选择路径中的最后一个项并试着编辑它
//修改节点监控器,保存节点新名字
aClone = (DefaultMutableTreeNode) selectedNode.clone();
}
});
//菜单项copyItem的动作监听器
copyItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//设置可编辑
tree.setEditable(true);
//获取选中节点
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
copyPath = tree.getSelectionPath();//得到被复制节点的路径
}
});
final Panel p = new Panel();
//向窗口添加PopupMenu对象
jf.add(pop);
//节点的鼠标事件监视器
MouseListener ml = new MouseAdapter()
{
public void mousePressed(MouseEvent e)//单右键单击时,也选中
{
TreePath tp = tree.getPathForLocation(e.getX(),e.getY()); //返回指定节点的完整的信息
if(tp == null)
return;
tree.setSelectionPath(tp); //选中节点选择指定路径标识的节点
//如果是右键点击,则不必考虑展开
if(SwingUtilities.isRightMouseButton(e))
return;
//如果是左键点击,就展开或者合上
if(tree.isExpanded(tp))//由Path所确定的节点被展开,则返回true
{
tree.collapsePath(tp);//将Path所确定的节点收缩,并保证可见
}
else
{
tree.expandPath(tp); //将Path所确定的节点展开,并保证可见
}
}
public void mouseClicked(MouseEvent e)
{
if(e.getClickCount() >= 2)//如果连击
{
TreePath tp = tree.getPathForLocation(e.getX(),e.getY());
if(tp != null)
{
DefaultMutableTreeNode temp = (DefaultMutableTreeNode) tp.getLastPathComponent();//获得选中节点
if(temp == null)
return;
//如果节点名被改变了,节点数据自动被改成String型的,而不再是NodeData型的
if(temp.getUserObject() == temp.getUserObject().toString())
{
System.out.println("Object of getUserObject() has been changed");
return;
}
NodeData data = (NodeData) temp.getUserObject();//获得数据节点
if(tp != null && data.f.isFile())//如果是可执行文件
{
try
{
//调用具体命令行功能的程序,根据命令行格式加上文件名
Runtime ce = Runtime.getRuntime();
String Temp = new String(data.f.getParent());
Temp = Temp + "//";
Temp = Temp + data.f.getName();
String cmdarray = "cmd /c start " + Temp;
ce.exec(cmdarray);
}
catch(Exception ee)
{
System.out.println(ee);
}
}
}
}
}
public void mouseReleased(MouseEvent e)//鼠标松开时,如果是右击,则显示右击菜单
{
if(e.isPopupTrigger())//测试是否这个事件将引起一个弹出式菜单在平台中探出
{
TreePath tp = tree.getPathForLocation(e.getX(),e.getY());
//如果右击节点
if(tp == null)
return;
pop.show(tree,e.getX(),e.getY());
}
}
};
tree.addMouseListener(ml);
//节点选中事件监视器 事件监听器作为匿名内部类
tree.addTreeSelectionListener(new TreeSelectionListener()//节点选中事件监视器 添加 TreeSelection事件的监听器。
{
//重写接口方法valueChanged 每当选择的值更改时调用
public void valueChanged(TreeSelectionEvent e)
{
TreePath movepath = (TreePath)e.getNewLeadSelectionPath();//返回当前前导路径
//如果节点被菜单选项deleteItem删除了,就会返回null,此时什么都不做,返回即可
if(movepath == null)
return;
DefaultMutableTreeNode temp = (DefaultMutableTreeNode) movepath.getLastPathComponent();//获得选中节点
if(temp == null)
return;
//---------------------非常关键的一个判断--------------------
//如果节点名被改变了,节点数据自动被改成String型的,而不再是NodeData型的
if(temp.getUserObject() == temp.getUserObject().toString())
{
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
//测试是否进来
System.out.println(aClone.toString());
DefaultMutableTreeNode parent = (DefaultMutableTreeNode) selectedNode.getParent();
int selectedIndex = parent.getIndex(selectedNode);
System.out.println("Object of getUserObject() has been changed");
//克隆体更新名称,file不变
((NodeData)aClone.getUserObject()).ChangeString(selectedNode.toString());
//删除选定节点
model.removeNodeFromParent(selectedNode);
//添加克隆体
model.insertNodeInto(aClone,parent,selectedIndex + 1);
//系统实现改名
NodeData data = (NodeData) aClone.getUserObject();
String tt = data.f.getParent() + "//";
tt = tt + aClone.toString();
data.f.renameTo(new File(tt));
//设置选中节点,避免重复触发该控制流
tree.setSelectionRow(selectedIndex + 1);
return;
}
NodeData data = (NodeData) temp.getUserObject();//获得数据节点
if(data.f != null)
{
//处理初次选中后快速添加新子节点代表新的文件
if(data.f.isDirectory() && temp.isLeaf())//如果是目录,但目前还是叶节点,那么就添加
{
File[] RRoots = data.f.listFiles();
for(int j = 0;j < RRoots.length;j ++)
{
DefaultMutableTreeNode NNode = new DefaultMutableTreeNode(new NodeData(RRoots[j],RRoots[j].getName()));
model.insertNodeInto(NNode,temp,temp.getChildCount());//添加新节点并自动刷新
}
//实时表格构造
tableModel.setRowCount(0);
list = fu(RRoots);//在fu方法中进行表格list的赋值
for (int i = 0; i < RRoots.length; i++) {
tableModel.addRow(list[i]);
}
}
else if(data.f.isFile())//如果是文件
{}
}
else
{
System.out.println("无法获得选中的节点");
}
}
});
JScrollPane scrollTree = new JScrollPane(tree);//显示区为table表格的可滚动面板
scrollTree.setPreferredSize(new Dimension(200, 300));
jf.add(BorderLayout.WEST,scrollTree);//显示区为tree的可滚动面板
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setVisible(true);
}
//**************************************************************************************************************************************************************************
//读取所选节点,获取子节点
public void readfiles(File file, DefaultMutableTreeNode node) {
File list[] = file.listFiles();
if (list == null)
return;
for (int i = 0; i < list.length; i++) {
File file_inlist = list[i];
// String filename = file_inlist.getName();
if (file_inlist.isDirectory()) {
parent = new DefaultMutableTreeNode(new NodeData(file_inlist));
// 添加空白文件夹节点 使子节点显示为文件夹
File stubadd = null;
DefaultMutableTreeNode stub = new DefaultMutableTreeNode(
stubadd);
parent.add(stub);
node.add(parent);
} else {
DefaultMutableTreeNode son = new DefaultMutableTreeNode(
new NodeData(file_inlist));
node.add(son);
}
}
}
//读取文件的大小
public String size(File file) throws IOException {
// FileInputStream fileLength = new FileInputStream(file);
String sizefile = file.length() + "字节";
return sizefile;
}
// 取得最后一次修改的时间
public Date lastTime(File file) {
long lastModified = file.lastModified();
Date date = new Date(lastModified);
date.setTime(lastModified);
return date;
}
public Object[][] fu(File[] file) {
Object[][] m = new Object[file.length][4];
for (int i = 0; i < file.length; i++) {
m[i][0] = file[i].getName();
// 这里有问题,如果是目录,怎么取大小?所以要用if
// m[i][1] = size(file[i]);
if (file[i].isDirectory()) {
m[i][1] = "文件夹";
} else {
String fileName = file[i].getName();
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
m[i][1] = fileType;
}
//文件最后修改时间
m[i][2] = lastTime(file[i]);
//文件大小
try {
// 这里有问题,如果是目录,怎么取大小?所以要用if
// m[i][1] = size(file[i]);
if (file[i].isDirectory()) {
m[i][3] = "文件夹类型大小待定";
} else {
m[i][3] = size(file[i]);
}
} catch (IOException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
}
return m;
}
public void delFile(String filePathAndName) { //删除文件
try
{
String filePath = filePathAndName;
filePath = filePath.toString();
java.io.File myDelFile = new java.io.File(filePath);
myDelFile.delete();
}
catch (Exception e)
{
System.out.println("删除文件操作出错");
}
}
public void delFolder(String folderPath) { //删除文件夹
try
{
delAllFile(folderPath); //删除完里面所有内容
String filePath = folderPath;
filePath = filePath.toString();
java.io.File myFilePath = new java.io.File(filePath);
myFilePath.delete(); //删除空文件夹
}
catch (Exception e) {
System.out.println("删除文件夹操作出错");
//e.printStackTrace();
}
}
public void delAllFile(String path) { //删除文件夹里面的所有文件
File file = new File(path);
if (!file.exists()) {
return;
}
if (!file.isDirectory()) {
return;
}
String[] tempList = file.list();
File temp = null;
for (int i = 0; i < tempList.length; i++) {
if (path.endsWith(File.separator)) {
temp = new File(path + tempList[i]);
}
else
{
temp = new File(path + File.separator + tempList[i]);
}
if (temp.isFile()) {
temp.delete();
}
if (temp.isDirectory()) {
delAllFile(path+"/"+ tempList[i]);//先删除文件夹里面的文件
delFolder(path+"/"+ tempList[i]);//再删除空文件夹
}
}
}
public void copyfile(String source,String dest)//文件复制方法
{
try{
File in=new File(source);
File out=new File(dest);
FileInputStream inFile=new FileInputStream(in);
FileOutputStream outFile=new FileOutputStream(out);
byte[] buffere=new byte[1024];
int i=0;
while((i=inFile.read(buffere))!=-1)
{
outFile.write(buffere,0,i);
}
inFile.close();
outFile.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void copyDict(String source,String dest)
{
String source1;String dest1;
File[] file=(new File(source).listFiles());
for(int i=0;i