歌词存档器





5.00/5 (4投票s)
Windows Forms .NET Core 应用程序可用于在 7z 存档中显示、搜索、编辑和存储歌词
引言
如果您是一位严肃、极其重要的应用程序开发人员,请直接获取代码,跳过此介绍。
我 11 岁那年,姑姑送了我一个崭新闪亮的德国手风琴(当时我叔叔在东德当军官)。附近音乐学校的人提出,如果我们用俄语版的“巴扬”代替这个漂亮的手风琴,就可以免费上课。我的父母照做了,我学习了近 2 年的和声和器乐技巧。那时,“西方”风气以及一些朋友在我耳边低语,说弹奏民间乐器不酷。更好的选择是钢琴、萨克斯或鼓。于是我停止了练习。我那时对音乐练习对大脑整体发育的巨大影响知之甚少。证据就是我的孙子 Ivan。我女儿(他妈妈)在他 2.5 岁时就给他买了一把小提琴(难以置信!)。
所以到了 15 岁,我惊讶地发现自己爱上了爵士乐。起初是声乐(Peggy Lee、Ella Fitzgerald、Sarah Vaughan...),然后是器乐(Cannonbal Adderley、Charley Parker、Miles Davis...)。我的朋友们完全无法理解或容忍器乐爵士乐(除了 Louis Prima 或 Ray Charles 的一些罕见即兴演奏)。你要么狂热地热爱爵士乐,要么就讨厌它,除了 Fausto Papetti、Chris Botti 等一些甜美的艺术家,他们受到钦佩或仅仅是容忍。
听着爵士歌曲却无法理解歌词,这是一种真正的折磨,能激发学习的动力。我相信学习英语的最佳方式是听各种爵士歌曲并分析歌词。
本项目特色
本应用 Lyrics
是我即将发布的一个更大项目的一部分。目前的 Windows Forms .NET Core 应用程序允许用户将文本存储在 SevenZipSharp 存档中,读取这些文本片段,进行编辑、添加、删除,并搜索用户指定的文本片段。
下一个 WpfPlayer
项目(不是当前项目)允许用户处理包含音乐(mp3、flac、ogg)、文本和图像文件的存储。它允许:
- 选择表演者
- 选择他的/她的专辑
- 收听选定的曲目
- 在嵌入的 WebBrowser 控件中搜索选定艺术家的网络信息,阅读该艺术家的信息
- 读取当前曲目/专辑信息:评论、人员或歌词(如果找到在 Lyrics.7z 文件中)
- 观看专辑和艺术家的图片(定时操作)
所有这些都显示在主窗口的不同 WPF 控件中。假设用户事先已指定了他的音乐(及其他)文件的存储文件夹。
编码细节
回到当前项目。存档歌曲的标题显示在 DataGridView grid
中。这个控件比 ListBox
更灵活。歌词显示在 PaddedRichTextBox
控件中。我从 CodeProject 上 Tony Zackin 的文章中借用了它的 DLL。我非常赞赏那些敢于重写 WndProc
并使用低级实体(如 Windows 消息(WM_NCCALCSIZE
等))进行工作的人的贡献。
很久以前,我花了好几年时间在(第一台苏联机器)的低级编码上。它甚至比机器代码级别还低。那些实体被称为基本操作,例如 RegA
→RegB
(将值从寄存器 A 传输到寄存器 B)。但很快,一些愚蠢的政治家在冷战中投降,毁掉了所有本土计算机的工业。70 年代中期,我们只有 ES EVM 机器(苏联 IBM 原型)。真正的苏联计算机器(如 BESM-6 或其他几台)在那时已经奄奄一息。现在我能清楚地想象出从事低级代码工作所需的资质水平和工作量。这些人可以克服任何问题。
大部分精力都花在了实现搜索功能上。循环搜索在标题和歌词文本中都进行。以下方法实现了循环搜索算法。我相信代码本身就说明了一切。这里使用了两个类变量:titleFound
(一个布尔标志)和 what
—要查找的文本片段。
void Search()
{
while (true) // For all the titles
{
var row = GetNextRow(); // Song title is here
if (row == null)
{
new FormMsg("Reached the end of collection", 2000); // Close after 2 seconds
searchRowId = -1;
return;
}
if (titleFound) // Class variable
{
SelectRow(row);
return;
}
else
{
while (true) // Search through all lyrics texts
{
var o = row.Cells[0].Value;
string s = File.ReadAllText($"{pathLyric}{o}.txt");
if (FindPos(s, 0) != -1 || titleFound)
{
SelectRow(row);
return;
}
row = GetNextRow();
if (row == null)
break;
}
}
}
}
DataGridViewRow GetNextRow()
{
int
count = grid.Rows.Count - 1,
next = searchRowId + 1;
if (next > count - 1) // Consider that last row in a grid is always empty,
// and counting from zero.
return null;
searchRowId = next % count; // circular search
var row = grid.Rows[searchRowId];
var o = row.Cells[0].Value;
titleFound = $"{o}".Contains(what, StringComparison.InvariantCultureIgnoreCase);
return row;
}
int FindPos(string s, int start)
{
return s.IndexOf(what, start, StringComparison.InvariantCultureIgnoreCase);
}
网格中的最后一行(始终存在且为空)用于添加新标题。大多数任务(除了搜索)都放在事件处理方法中。我的意思是用户生成的事件,例如:grid.SelectionChanged
、grid.UserDeletingRow
和 RichTextBox.Leave
(焦点)。例如,分析处理 grid.UserDeletingRow
事件的逻辑。
void Grid_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
{
var o = e.Row.Cells[0].Value;
if (o != null)
{
var fn = $"{pathLyric}{o}.txt";
var dlg = new FormMsgBox(this, $"Confirm Deleting Song: '{o}'") { Visible = false };
if (dlg.ShowDialog() == DialogResult.Yes)
{
File.Delete(fn);
UpdateCount();
}
else
e.Cancel = true;
}
}
创建了两个单独的窗体:FormMsg
和 FormMsgBox
来重写单调乏味的 Microsoft MessageBox
。对于简单的窗体,没有必要使用 Visual Studio Designer。代码比 Studio 自动生成的代码更具信息量且易于阅读。这是一个 FormMsg
窗体的示例,该窗体在给定时间内显示一条消息,然后消失。但是,通过单击鼠标左键,用户可以(按需)保留消息并仔细阅读其(尤其是冗长的)文本。通过单击鼠标右键,用户可以将消息复制到 Clipboard
对象。请注意,代码不需要 Visual Studio Designer 功能和资源文件。
public class FormMsg : Form
{
bool stay;
public FormMsg(string msg, int interval)
{
var text = Kit.FormatMsg(msg);
var timer = new Timer { Interval = interval };
timer.Tick += (s, e) =>
{
if (!stay)
Dispose();
};
var lbl = new Label
{
Font = new Font("Trebuchet MS", 11.0F),
ForeColor = Color.Yellow,
Padding = new Padding(16),
Text = text.ToString(),
AutoSize = true
};
lbl.Paint += (s, e) => { e.Graphics.DrawRectangle
(Pens.Yellow, 5, 5, lbl.Width - 7, lbl.Height - 10); };
lbl.MouseDown += (s, e) =>
{
if (e.Button == MouseButtons.Right)
{
Clipboard.Clear();
Clipboard.SetText(lbl.Text);
}
stay = !stay;
if (!stay)
Dispose();
};
Controls.Add(lbl);
BackColor = Color.Black;
FormBorderStyle = FormBorderStyle.None;
AutoSize = true;
AutoSizeMode = AutoSizeMode.GrowAndShrink;
TopMost = true;
Load += (s, e) =>
{
var form = Application.OpenForms[0];
Left = form.Left + 230;
Top = form.Top + 200;
timer.Start();
};
Show();
Update();
}
}
要在 C# 中重命名文件,Microsoft 提供了 File.Move
方法,该方法看起来(并且工作起来)相当奇怪。我认为更好的方法是使用 stdio.h 中的 InteropServices
和 rename
函数。
Using the Code
当您找到喜欢的歌词并准备将其存储在您的存档(默认情况下为 Lyrics.7z)中时:
- 按 Ctrl+End 将最后一个空网格行显示到视图中。
- 输入歌曲标题并按 Enter — 将创建一个临时文件,名为 title.txt。
- 按 向上箭头键查看文件的占位符文本。
- 在
RichTextBox
中选择占位符文本。 - 按 Ctrl+V 粘贴歌词,并在
PaddedRichTextBox
中进行编辑(如有必要)。
当焦点离开 PaddedRichTextBox
时,您当前的歌词文本将被保存在一个临时文件中(稍后将存档在 Lyrics.7z 中)。当您退出应用程序或单击 ToolStrip
上的 Save 按钮时,这会自动发生。当您关闭窗体时,Lyrics/Data/Tmp 文件夹中的所有临时文件也将被删除。您的存档已更新,可以供更复杂的应用程序使用。我将在打磨好以满足 CodeProject 要求后发布这样一个应用程序 WpfPlayer
。
Public static
类 Kit
用于保存所有有用的全局函数(或 C# 中的 static
方法),任何开发人员一生都会收集这些函数。这里,该类只包含四个方法,用于重新格式化、剥离、修剪文本片段以及搜索包含数据和库文件的文件夹。
好了,各位!感谢阅读。
历史
- 2020 年 9 月 2 日:初始版本