2025-11-24 10:59:56 +08:00
|
|
|
|
using System;
|
2025-11-24 15:44:37 +08:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.IO;
|
2025-11-24 15:45:15 +08:00
|
|
|
|
using System.Text;
|
2025-11-24 10:59:56 +08:00
|
|
|
|
using System.Drawing;
|
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
|
|
|
|
|
|
|
namespace SlideCombine
|
|
|
|
|
|
{
|
|
|
|
|
|
public partial class Form1 : Form
|
|
|
|
|
|
{
|
|
|
|
|
|
public Form1()
|
|
|
|
|
|
{
|
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
|
|
|
|
|
|
|
// 设置窗体图标 - 使用嵌入资源
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var stream = GetType().Assembly.GetManifestResourceStream("SlideCombine.app.ico");
|
|
|
|
|
|
if (stream != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.Icon = new Icon(stream);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果图标加载失败,使用默认图标
|
|
|
|
|
|
// this.Icon = SystemIcons.Application;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void btnBrowseSource_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
2025-11-24 16:22:05 +08:00
|
|
|
|
string selectedPath = ShowModernFolderBrowser("请选择包含PDF文件夹的路径(含FreePic2Pdf_bkmk.txt文件)", txtSourcePath.Text);
|
|
|
|
|
|
if (!string.IsNullOrEmpty(selectedPath))
|
2025-11-24 10:59:56 +08:00
|
|
|
|
{
|
2025-11-24 16:22:05 +08:00
|
|
|
|
txtSourcePath.Text = selectedPath;
|
|
|
|
|
|
LogInfo($"已选择PDF路径: {selectedPath}");
|
2025-11-24 10:59:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 16:14:05 +08:00
|
|
|
|
private void btnBrowseText_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
2025-11-24 16:22:05 +08:00
|
|
|
|
string selectedPath = ShowModernFolderBrowser("请选择包含元数据TXT文件的路径", txtTextPath.Text);
|
|
|
|
|
|
if (!string.IsNullOrEmpty(selectedPath))
|
2025-11-24 16:14:05 +08:00
|
|
|
|
{
|
2025-11-24 16:22:05 +08:00
|
|
|
|
txtTextPath.Text = selectedPath;
|
|
|
|
|
|
LogInfo($"已选择TXT源路径: {selectedPath}");
|
2025-11-24 16:14:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 10:59:56 +08:00
|
|
|
|
private void btnBrowseOutput_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
2025-11-24 16:22:05 +08:00
|
|
|
|
string selectedPath = ShowModernFolderBrowser("请选择合并后TXT文件的输出路径", txtOutputPath.Text);
|
|
|
|
|
|
if (!string.IsNullOrEmpty(selectedPath))
|
2025-11-24 10:59:56 +08:00
|
|
|
|
{
|
2025-11-24 16:22:05 +08:00
|
|
|
|
txtOutputPath.Text = selectedPath;
|
|
|
|
|
|
LogInfo($"已选择最终输出路径: {selectedPath}");
|
2025-11-24 10:59:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void btnClear_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
txtSourcePath.Clear();
|
2025-11-24 16:14:05 +08:00
|
|
|
|
txtTextPath.Clear();
|
2025-11-24 10:59:56 +08:00
|
|
|
|
txtOutputPath.Clear();
|
|
|
|
|
|
txtLog.Clear();
|
|
|
|
|
|
progressBar.Value = 0;
|
2025-11-24 16:07:29 +08:00
|
|
|
|
LogInfo("界面已清空");
|
2025-11-24 10:59:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void btnExit_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
2025-11-24 16:07:29 +08:00
|
|
|
|
LogInfo("程序即将退出");
|
2025-11-24 10:59:56 +08:00
|
|
|
|
Application.Exit();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void btnMerge_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
2025-11-24 15:44:37 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 验证输入
|
2025-11-24 16:14:05 +08:00
|
|
|
|
if (string.IsNullOrWhiteSpace(txtSourcePath.Text) ||
|
|
|
|
|
|
string.IsNullOrWhiteSpace(txtTextPath.Text) ||
|
|
|
|
|
|
string.IsNullOrWhiteSpace(txtOutputPath.Text))
|
2025-11-24 15:44:37 +08:00
|
|
|
|
{
|
2025-11-24 16:14:05 +08:00
|
|
|
|
MessageBox.Show("请选择所有三个路径:PDF路径、TXT源路径和输出路径", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
2025-11-24 15:44:37 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!Directory.Exists(txtSourcePath.Text))
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("指定的PDF文件夹路径不存在", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 16:14:05 +08:00
|
|
|
|
if (!Directory.Exists(txtTextPath.Text))
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("指定的TXT源文件路径不存在", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 15:44:37 +08:00
|
|
|
|
// 禁用按钮,防止重复点击
|
|
|
|
|
|
btnMerge.Enabled = false;
|
|
|
|
|
|
btnClear.Enabled = false;
|
|
|
|
|
|
|
|
|
|
|
|
// 重置进度条和日志
|
|
|
|
|
|
progressBar.Value = 0;
|
|
|
|
|
|
txtLog.Clear();
|
|
|
|
|
|
Log("开始处理PDF书签文件...");
|
|
|
|
|
|
|
|
|
|
|
|
// 处理文件
|
2025-11-24 16:14:05 +08:00
|
|
|
|
var results = FileMerger.ProcessAllFolders(txtSourcePath.Text, txtTextPath.Text, txtOutputPath.Text);
|
2025-11-24 15:44:37 +08:00
|
|
|
|
|
|
|
|
|
|
// 显示进度
|
|
|
|
|
|
progressBar.Value = 50;
|
|
|
|
|
|
Log($"找到 {results.Count} 个文件组需要处理");
|
|
|
|
|
|
|
|
|
|
|
|
// 保存结果
|
|
|
|
|
|
FileMerger.SaveResults(results, txtOutputPath.Text);
|
|
|
|
|
|
|
|
|
|
|
|
progressBar.Value = 100;
|
|
|
|
|
|
|
|
|
|
|
|
// 统计成功和失败的数量
|
|
|
|
|
|
int successCount = 0;
|
|
|
|
|
|
int failCount = 0;
|
|
|
|
|
|
var sb = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var result in results)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (result.Success)
|
|
|
|
|
|
{
|
|
|
|
|
|
successCount++;
|
|
|
|
|
|
Log($"✓ 成功处理: {result.BaseFileName} (合并了 {result.SourceFiles.Count} 个文件)");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
failCount++;
|
|
|
|
|
|
Log($"✗ 处理失败: {result.ErrorMessage}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Log($"处理完成! 成功: {successCount}, 失败: {failCount}");
|
|
|
|
|
|
|
|
|
|
|
|
if (successCount > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"书签合并完成!\n成功处理 {successCount} 个文件\n输出路径: {txtOutputPath.Text}",
|
|
|
|
|
|
"处理完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("没有成功处理任何文件,请检查输入路径和文件格式。",
|
|
|
|
|
|
"处理失败", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Log($"错误: {ex.Message}");
|
|
|
|
|
|
MessageBox.Show($"处理过程中发生错误:\n{ex.Message}",
|
|
|
|
|
|
"错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
finally
|
|
|
|
|
|
{
|
|
|
|
|
|
// 重新启用按钮
|
|
|
|
|
|
btnMerge.Enabled = true;
|
|
|
|
|
|
btnClear.Enabled = true;
|
|
|
|
|
|
}
|
2025-11-24 10:59:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void Log(string msg)
|
|
|
|
|
|
{
|
2025-11-24 16:07:29 +08:00
|
|
|
|
string timestamp = DateTime.Now.ToString("HH:mm:ss");
|
|
|
|
|
|
txtLog.AppendText($"[{timestamp}] {msg}\r\n");
|
|
|
|
|
|
txtLog.ScrollToCaret();
|
|
|
|
|
|
Application.DoEvents();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void LogSuccess(string msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
string timestamp = DateTime.Now.ToString("HH:mm:ss");
|
|
|
|
|
|
txtLog.SelectionStart = txtLog.TextLength;
|
|
|
|
|
|
txtLog.SelectionColor = Color.Green;
|
|
|
|
|
|
txtLog.AppendText($"[{timestamp}] ✅ {msg}\r\n");
|
|
|
|
|
|
txtLog.SelectionColor = txtLog.ForeColor;
|
|
|
|
|
|
txtLog.ScrollToCaret();
|
|
|
|
|
|
Application.DoEvents();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void LogError(string msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
string timestamp = DateTime.Now.ToString("HH:mm:ss");
|
|
|
|
|
|
txtLog.SelectionStart = txtLog.TextLength;
|
|
|
|
|
|
txtLog.SelectionColor = Color.Red;
|
|
|
|
|
|
txtLog.AppendText($"[{timestamp}] ❌ {msg}\r\n");
|
|
|
|
|
|
txtLog.SelectionColor = txtLog.ForeColor;
|
|
|
|
|
|
txtLog.ScrollToCaret();
|
|
|
|
|
|
Application.DoEvents();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void LogInfo(string msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
string timestamp = DateTime.Now.ToString("HH:mm:ss");
|
|
|
|
|
|
txtLog.SelectionStart = txtLog.TextLength;
|
|
|
|
|
|
txtLog.SelectionColor = Color.Blue;
|
|
|
|
|
|
txtLog.AppendText($"[{timestamp}] ℹ️ {msg}\r\n");
|
|
|
|
|
|
txtLog.SelectionColor = txtLog.ForeColor;
|
2025-11-24 10:59:56 +08:00
|
|
|
|
txtLog.ScrollToCaret();
|
|
|
|
|
|
Application.DoEvents();
|
|
|
|
|
|
}
|
2025-11-24 16:22:05 +08:00
|
|
|
|
|
|
|
|
|
|
private string ShowModernFolderBrowser(string title, string initialPath)
|
|
|
|
|
|
{
|
|
|
|
|
|
using (var form = new Form())
|
|
|
|
|
|
{
|
|
|
|
|
|
form.Text = title;
|
2025-11-24 16:25:31 +08:00
|
|
|
|
form.Size = new Size(800, 600);
|
2025-11-24 16:22:05 +08:00
|
|
|
|
form.StartPosition = FormStartPosition.CenterParent;
|
|
|
|
|
|
form.FormBorderStyle = FormBorderStyle.FixedDialog;
|
|
|
|
|
|
form.MaximizeBox = false;
|
|
|
|
|
|
form.MinimizeBox = false;
|
|
|
|
|
|
form.BackColor = Color.White;
|
|
|
|
|
|
|
2025-11-24 16:25:31 +08:00
|
|
|
|
// 顶部工具栏
|
|
|
|
|
|
var toolbarPanel = new Panel();
|
|
|
|
|
|
toolbarPanel.Location = new Point(0, 0);
|
|
|
|
|
|
toolbarPanel.Size = new Size(800, 60);
|
|
|
|
|
|
toolbarPanel.BackColor = Color.FromArgb(248, 248, 248);
|
|
|
|
|
|
toolbarPanel.BorderStyle = BorderStyle.FixedSingle;
|
|
|
|
|
|
form.Controls.Add(toolbarPanel);
|
|
|
|
|
|
|
|
|
|
|
|
// 路径标签
|
|
|
|
|
|
var pathLabel = new Label();
|
|
|
|
|
|
pathLabel.Text = "路径:";
|
|
|
|
|
|
pathLabel.Location = new Point(15, 20);
|
|
|
|
|
|
pathLabel.Size = new Size(40, 20);
|
|
|
|
|
|
pathLabel.Font = new Font("Microsoft YaHei", 9F);
|
|
|
|
|
|
pathLabel.ForeColor = Color.FromArgb(51, 51, 51);
|
|
|
|
|
|
toolbarPanel.Controls.Add(pathLabel);
|
|
|
|
|
|
|
|
|
|
|
|
// 路径文本框
|
2025-11-24 16:22:05 +08:00
|
|
|
|
var pathTextBox = new TextBox();
|
2025-11-24 16:25:31 +08:00
|
|
|
|
pathTextBox.Location = new Point(60, 18);
|
|
|
|
|
|
pathTextBox.Size = new Size(650, 24);
|
2025-11-24 16:22:05 +08:00
|
|
|
|
pathTextBox.Font = new Font("Microsoft YaHei", 10F);
|
|
|
|
|
|
pathTextBox.Text = initialPath ?? string.Empty;
|
|
|
|
|
|
pathTextBox.BorderStyle = BorderStyle.FixedSingle;
|
2025-11-24 16:25:31 +08:00
|
|
|
|
toolbarPanel.Controls.Add(pathTextBox);
|
2025-11-24 16:22:05 +08:00
|
|
|
|
|
2025-11-24 16:25:31 +08:00
|
|
|
|
// 路径浏览按钮
|
2025-11-24 16:22:05 +08:00
|
|
|
|
var browseButton = new Button();
|
2025-11-24 16:25:31 +08:00
|
|
|
|
browseButton.Text = "...";
|
|
|
|
|
|
browseButton.Location = new Point(720, 17);
|
|
|
|
|
|
browseButton.Size = new Size(30, 24);
|
2025-11-24 16:22:05 +08:00
|
|
|
|
browseButton.Font = new Font("Microsoft YaHei", 9F);
|
|
|
|
|
|
browseButton.BackColor = Color.FromArgb(66, 139, 202);
|
|
|
|
|
|
browseButton.ForeColor = Color.White;
|
|
|
|
|
|
browseButton.FlatStyle = FlatStyle.Flat;
|
|
|
|
|
|
browseButton.FlatAppearance.BorderSize = 0;
|
2025-11-24 16:25:31 +08:00
|
|
|
|
toolbarPanel.Controls.Add(browseButton);
|
|
|
|
|
|
|
|
|
|
|
|
// 左侧文件夹树
|
|
|
|
|
|
var folderTree = new TreeView();
|
|
|
|
|
|
folderTree.Location = new Point(15, 70);
|
|
|
|
|
|
folderTree.Size = new Size(250, 450);
|
|
|
|
|
|
folderTree.Font = new Font("Microsoft YaHei", 9F);
|
|
|
|
|
|
folderTree.BorderStyle = BorderStyle.FixedSingle;
|
|
|
|
|
|
folderTree.ShowLines = true;
|
|
|
|
|
|
folderTree.ShowPlusMinus = true;
|
|
|
|
|
|
folderTree.ShowRootLines = true;
|
|
|
|
|
|
folderTree.FullRowSelect = true;
|
|
|
|
|
|
folderTree.Scrollable = true;
|
|
|
|
|
|
form.Controls.Add(folderTree);
|
|
|
|
|
|
|
|
|
|
|
|
// 右侧文件列表
|
2025-11-24 16:22:05 +08:00
|
|
|
|
var fileList = new ListView();
|
2025-11-24 16:25:31 +08:00
|
|
|
|
fileList.Location = new Point(275, 70);
|
|
|
|
|
|
fileList.Size = new Size(510, 450);
|
2025-11-24 16:22:05 +08:00
|
|
|
|
fileList.View = View.Details;
|
|
|
|
|
|
fileList.FullRowSelect = true;
|
|
|
|
|
|
fileList.GridLines = true;
|
|
|
|
|
|
fileList.Font = new Font("Microsoft YaHei", 9F);
|
|
|
|
|
|
fileList.BorderStyle = BorderStyle.FixedSingle;
|
2025-11-24 16:25:31 +08:00
|
|
|
|
fileList.Columns.Add("名称", 200);
|
|
|
|
|
|
fileList.Columns.Add("修改日期", 150);
|
2025-11-24 16:22:05 +08:00
|
|
|
|
fileList.Columns.Add("类型", 80);
|
2025-11-24 16:25:31 +08:00
|
|
|
|
fileList.Columns.Add("大小", 80);
|
2025-11-24 16:22:05 +08:00
|
|
|
|
form.Controls.Add(fileList);
|
|
|
|
|
|
|
2025-11-24 16:25:31 +08:00
|
|
|
|
// 底部状态栏
|
|
|
|
|
|
var statusPanel = new Panel();
|
|
|
|
|
|
statusPanel.Location = new Point(0, 530);
|
|
|
|
|
|
statusPanel.Size = new Size(800, 30);
|
|
|
|
|
|
statusPanel.BackColor = Color.FromArgb(240, 240, 240);
|
|
|
|
|
|
statusPanel.BorderStyle = BorderStyle.FixedSingle;
|
|
|
|
|
|
form.Controls.Add(statusPanel);
|
|
|
|
|
|
|
2025-11-24 16:22:05 +08:00
|
|
|
|
var statusLabel = new Label();
|
2025-11-24 16:25:31 +08:00
|
|
|
|
statusLabel.Text = "就绪";
|
|
|
|
|
|
statusLabel.Location = new Point(10, 5);
|
|
|
|
|
|
statusLabel.Size = new Size(780, 20);
|
2025-11-24 16:22:05 +08:00
|
|
|
|
statusLabel.Font = new Font("Microsoft YaHei", 9F);
|
|
|
|
|
|
statusLabel.ForeColor = Color.FromArgb(102, 102, 102);
|
2025-11-24 16:25:31 +08:00
|
|
|
|
statusPanel.Controls.Add(statusLabel);
|
2025-11-24 16:22:05 +08:00
|
|
|
|
|
2025-11-24 16:25:31 +08:00
|
|
|
|
// 底部按钮
|
2025-11-24 16:22:05 +08:00
|
|
|
|
var okButton = new Button();
|
|
|
|
|
|
okButton.Text = "确定";
|
2025-11-24 16:25:31 +08:00
|
|
|
|
okButton.Location = new Point(620, 20);
|
2025-11-24 16:22:05 +08:00
|
|
|
|
okButton.Size = new Size(80, 35);
|
|
|
|
|
|
okButton.Font = new Font("Microsoft YaHei", 10F, FontStyle.Bold);
|
|
|
|
|
|
okButton.BackColor = Color.FromArgb(92, 184, 92);
|
|
|
|
|
|
okButton.ForeColor = Color.White;
|
|
|
|
|
|
okButton.FlatStyle = FlatStyle.Flat;
|
|
|
|
|
|
okButton.FlatAppearance.BorderSize = 0;
|
|
|
|
|
|
form.AcceptButton = okButton;
|
|
|
|
|
|
form.Controls.Add(okButton);
|
|
|
|
|
|
|
|
|
|
|
|
var cancelButton = new Button();
|
|
|
|
|
|
cancelButton.Text = "取消";
|
2025-11-24 16:25:31 +08:00
|
|
|
|
cancelButton.Location = new Point(710, 20);
|
2025-11-24 16:22:05 +08:00
|
|
|
|
cancelButton.Size = new Size(80, 35);
|
|
|
|
|
|
cancelButton.Font = new Font("Microsoft YaHei", 10F);
|
|
|
|
|
|
cancelButton.BackColor = Color.FromArgb(217, 83, 79);
|
|
|
|
|
|
cancelButton.ForeColor = Color.White;
|
|
|
|
|
|
cancelButton.FlatStyle = FlatStyle.Flat;
|
|
|
|
|
|
cancelButton.FlatAppearance.BorderSize = 0;
|
2025-11-24 16:22:53 +08:00
|
|
|
|
form.CancelButton = cancelButton;
|
2025-11-24 16:22:05 +08:00
|
|
|
|
form.Controls.Add(cancelButton);
|
|
|
|
|
|
|
|
|
|
|
|
// 当前路径
|
|
|
|
|
|
string currentPath = string.IsNullOrEmpty(initialPath) ?
|
|
|
|
|
|
Environment.GetFolderPath(Environment.SpecialFolder.Desktop) : initialPath;
|
|
|
|
|
|
|
2025-11-24 16:25:31 +08:00
|
|
|
|
// 加载文件夹树
|
|
|
|
|
|
void LoadFolderTree()
|
2025-11-24 16:22:05 +08:00
|
|
|
|
{
|
2025-11-24 16:25:31 +08:00
|
|
|
|
folderTree.Nodes.Clear();
|
|
|
|
|
|
folderTree.BeginUpdate();
|
|
|
|
|
|
|
2025-11-24 16:22:05 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-11-24 16:25:31 +08:00
|
|
|
|
// 获取所有逻辑驱动器
|
|
|
|
|
|
foreach (var drive in DriveInfo.GetDrives())
|
|
|
|
|
|
{
|
|
|
|
|
|
var driveNode = new TreeNode();
|
2025-11-24 16:26:11 +08:00
|
|
|
|
driveNode.Text = $"{drive.Name} ({drive.VolumeLabel})";
|
2025-11-24 16:25:31 +08:00
|
|
|
|
driveNode.Tag = drive.Name;
|
|
|
|
|
|
|
|
|
|
|
|
if (drive.IsReady)
|
|
|
|
|
|
{
|
|
|
|
|
|
driveNode.Nodes.Add(new TreeNode()); // 占位节点
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
driveNode.ImageIndex = 0;
|
|
|
|
|
|
driveNode.SelectedImageIndex = 0;
|
|
|
|
|
|
folderTree.Nodes.Add(driveNode);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
statusLabel.Text = $"加载驱动器时出错: {ex.Message}";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
folderTree.EndUpdate();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 展开节点时加载子文件夹
|
|
|
|
|
|
void LoadSubFolders(TreeNode parentNode)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (parentNode.Nodes.Count == 1 && parentNode.Nodes[0].Text == "")
|
|
|
|
|
|
{
|
|
|
|
|
|
parentNode.Nodes.Clear();
|
2025-11-24 16:22:05 +08:00
|
|
|
|
|
2025-11-24 16:25:31 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var path = parentNode.Tag as string;
|
|
|
|
|
|
if (Directory.Exists(path))
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var dir in Directory.GetDirectories(path))
|
|
|
|
|
|
{
|
|
|
|
|
|
var dirInfo = new DirectoryInfo(dir);
|
|
|
|
|
|
var node = new TreeNode(dirInfo.Name);
|
|
|
|
|
|
node.Tag = dirInfo.FullName;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 检查是否有子文件夹
|
|
|
|
|
|
if (Directory.GetDirectories(dir).Length > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
node.Nodes.Add(new TreeNode()); // 占位节点
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
// 无权限访问子文件夹
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
parentNode.Nodes.Add(node);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
statusLabel.Text = $"加载子文件夹时出错: {ex.Message}";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 加载文件列表
|
|
|
|
|
|
void LoadFileList(string path)
|
|
|
|
|
|
{
|
|
|
|
|
|
fileList.Items.Clear();
|
|
|
|
|
|
fileList.BeginUpdate();
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Directory.Exists(path))
|
2025-11-24 16:22:05 +08:00
|
|
|
|
{
|
|
|
|
|
|
// 添加返回上级目录
|
2025-11-24 16:25:31 +08:00
|
|
|
|
var parentPath = Path.GetDirectoryName(path);
|
|
|
|
|
|
if (!string.IsNullOrEmpty(parentPath))
|
2025-11-24 16:22:05 +08:00
|
|
|
|
{
|
2025-11-24 16:25:31 +08:00
|
|
|
|
var parentItem = new ListViewItem(new[] { "..", "", "文件夹", "" });
|
|
|
|
|
|
parentItem.Tag = parentPath;
|
2025-11-24 16:22:05 +08:00
|
|
|
|
parentItem.ForeColor = Color.FromArgb(66, 139, 202);
|
|
|
|
|
|
fileList.Items.Add(parentItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 16:25:31 +08:00
|
|
|
|
// 添加文件夹
|
2025-11-24 16:22:05 +08:00
|
|
|
|
foreach (var dir in Directory.GetDirectories(path))
|
|
|
|
|
|
{
|
|
|
|
|
|
var dirInfo = new DirectoryInfo(dir);
|
|
|
|
|
|
var item = new ListViewItem(new[]
|
|
|
|
|
|
{
|
|
|
|
|
|
dirInfo.Name,
|
|
|
|
|
|
dirInfo.LastWriteTime.ToString("yyyy-MM-dd HH:mm"),
|
2025-11-24 16:25:31 +08:00
|
|
|
|
"文件夹",
|
|
|
|
|
|
""
|
2025-11-24 16:22:05 +08:00
|
|
|
|
});
|
|
|
|
|
|
item.Tag = dirInfo.FullName;
|
|
|
|
|
|
item.ForeColor = Color.FromArgb(51, 51, 51);
|
|
|
|
|
|
fileList.Items.Add(item);
|
|
|
|
|
|
}
|
2025-11-24 16:25:31 +08:00
|
|
|
|
|
|
|
|
|
|
// 添加文件
|
|
|
|
|
|
foreach (var file in Directory.GetFiles(path))
|
|
|
|
|
|
{
|
|
|
|
|
|
var fileInfo = new FileInfo(file);
|
|
|
|
|
|
var item = new ListViewItem(new[]
|
|
|
|
|
|
{
|
|
|
|
|
|
fileInfo.Name,
|
|
|
|
|
|
fileInfo.LastWriteTime.ToString("yyyy-MM-dd HH:mm"),
|
|
|
|
|
|
GetFileType(fileInfo.Extension),
|
|
|
|
|
|
FormatFileSize(fileInfo.Length)
|
|
|
|
|
|
});
|
|
|
|
|
|
item.Tag = fileInfo.FullName;
|
|
|
|
|
|
item.ForeColor = Color.FromArgb(102, 102, 102);
|
|
|
|
|
|
fileList.Items.Add(item);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
statusLabel.Text = $"{Directory.GetDirectories(path).Length} 个文件夹, {Directory.GetFiles(path).Length} 个文件";
|
2025-11-24 16:22:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
2025-11-24 16:25:31 +08:00
|
|
|
|
statusLabel.Text = $"加载文件列表时出错: {ex.Message}";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fileList.EndUpdate();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string GetFileType(string extension)
|
|
|
|
|
|
{
|
|
|
|
|
|
extension = extension.ToLower();
|
|
|
|
|
|
switch (extension)
|
|
|
|
|
|
{
|
|
|
|
|
|
case ".txt": return "文本文件";
|
|
|
|
|
|
case ".pdf": return "PDF文档";
|
|
|
|
|
|
case ".doc": case ".docx": return "Word文档";
|
|
|
|
|
|
case ".xls": case ".xlsx": return "Excel表格";
|
|
|
|
|
|
default: return $"{extension}文件";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string FormatFileSize(long bytes)
|
|
|
|
|
|
{
|
|
|
|
|
|
string[] sizes = { "B", "KB", "MB", "GB" };
|
|
|
|
|
|
double len = bytes;
|
|
|
|
|
|
int order = 0;
|
|
|
|
|
|
while (len >= 1024 && order < sizes.Length - 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
order++;
|
|
|
|
|
|
len = len / 1024;
|
2025-11-24 16:22:05 +08:00
|
|
|
|
}
|
2025-11-24 16:25:31 +08:00
|
|
|
|
return $"{len:0.##} {sizes[order]}";
|
2025-11-24 16:22:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 16:25:31 +08:00
|
|
|
|
// 事件处理
|
|
|
|
|
|
folderTree.BeforeExpand += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
LoadSubFolders(e.Node);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
folderTree.AfterSelect += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (e.Node.Tag is string path && Directory.Exists(path))
|
|
|
|
|
|
{
|
|
|
|
|
|
currentPath = path;
|
|
|
|
|
|
pathTextBox.Text = currentPath;
|
|
|
|
|
|
LoadFileList(currentPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
fileList.DoubleClick += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (fileList.SelectedItems.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
var selectedItem = fileList.SelectedItems[0];
|
|
|
|
|
|
if (selectedItem.Tag is string selectedPath && Directory.Exists(selectedPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
currentPath = selectedPath;
|
|
|
|
|
|
pathTextBox.Text = currentPath;
|
|
|
|
|
|
LoadFileList(currentPath);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新树选择
|
|
|
|
|
|
var nodes = folderTree.Nodes.Find(GetNodeText(selectedPath), true);
|
|
|
|
|
|
if (nodes.Length > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
folderTree.SelectedNode = nodes[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-24 16:22:05 +08:00
|
|
|
|
browseButton.Click += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
using (var dialog = new FolderBrowserDialog())
|
|
|
|
|
|
{
|
|
|
|
|
|
dialog.Description = title;
|
2025-11-24 16:25:31 +08:00
|
|
|
|
dialog.SelectedPath = currentPath;
|
2025-11-24 16:22:05 +08:00
|
|
|
|
|
|
|
|
|
|
if (dialog.ShowDialog() == DialogResult.OK)
|
|
|
|
|
|
{
|
|
|
|
|
|
currentPath = dialog.SelectedPath;
|
|
|
|
|
|
pathTextBox.Text = currentPath;
|
2025-11-24 16:25:31 +08:00
|
|
|
|
LoadFileList(currentPath);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新树选择
|
|
|
|
|
|
var nodes = folderTree.Nodes.Find(GetNodeText(currentPath), true);
|
|
|
|
|
|
if (nodes.Length > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
folderTree.SelectedNode = nodes[0];
|
|
|
|
|
|
}
|
2025-11-24 16:22:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-24 16:25:31 +08:00
|
|
|
|
pathTextBox.KeyDown += (s, e) =>
|
2025-11-24 16:22:05 +08:00
|
|
|
|
{
|
2025-11-24 16:25:31 +08:00
|
|
|
|
if (e.KeyCode == Keys.Enter)
|
2025-11-24 16:22:05 +08:00
|
|
|
|
{
|
2025-11-24 16:25:31 +08:00
|
|
|
|
if (Directory.Exists(pathTextBox.Text))
|
2025-11-24 16:22:05 +08:00
|
|
|
|
{
|
2025-11-24 16:25:31 +08:00
|
|
|
|
currentPath = pathTextBox.Text;
|
|
|
|
|
|
LoadFileList(currentPath);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新树选择
|
|
|
|
|
|
var nodes = folderTree.Nodes.Find(GetNodeText(currentPath), true);
|
|
|
|
|
|
if (nodes.Length > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
folderTree.SelectedNode = nodes[0];
|
|
|
|
|
|
}
|
2025-11-24 16:22:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-24 16:25:31 +08:00
|
|
|
|
string GetNodeText(string fullPath)
|
|
|
|
|
|
{
|
|
|
|
|
|
return new DirectoryInfo(fullPath).Name;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 16:22:05 +08:00
|
|
|
|
okButton.Click += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Directory.Exists(pathTextBox.Text))
|
|
|
|
|
|
{
|
|
|
|
|
|
form.DialogResult = DialogResult.OK;
|
|
|
|
|
|
form.Close();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("请输入有效的文件夹路径", "提示",
|
|
|
|
|
|
MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
cancelButton.Click += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
form.DialogResult = DialogResult.Cancel;
|
|
|
|
|
|
form.Close();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-24 16:25:31 +08:00
|
|
|
|
// 初始化
|
|
|
|
|
|
LoadFolderTree();
|
|
|
|
|
|
LoadFileList(currentPath);
|
2025-11-24 16:22:05 +08:00
|
|
|
|
|
|
|
|
|
|
// 显示对话框
|
|
|
|
|
|
if (form.ShowDialog() == DialogResult.OK)
|
|
|
|
|
|
{
|
|
|
|
|
|
return pathTextBox.Text;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
2025-11-24 10:59:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|