我想在Delphi / Pascal中为自己的音乐播放器添加播放列表。
我认为使用带有MP3文件路径的TStringList是最好的解决方案 - 另外 - 带有歌曲名称的TListBox。两个列表中的匹配字符串必须位于相同的位置。因此,如果用户在TListBox中选择第5项,我只需要获取TStringList中第5位的路径。
这很好用。
但现在我需要一个包含两列的播放列表:“艺术家”和“歌曲名称”。您应该能够按艺术家(升序和降序)以及歌曲标题(升序和降序)对播放列表进行排序 - 当然,按字母顺序排序。
我怎么能这样做?有两个TStringList对象 - 一个按艺术家排序,一个按歌曲标题排序?
答案 0 :(得分:4)
我会做一个至少包含Artist和Title属性的TSong类,以及一个使用正确的排序字段提供一个或多个排序方法(可以是通用的)的TSongList(s。
当然不会维护你必须管理的2个单独的StringLists,在排序时保持同步和重新洗牌......
一种廉价的实现方法,可能是在内存中使用包含艺术家和路径的记录的DataSet显示在网格中,您可以在不同的列上排序。
当前行将直接提供两种信息。
答案 1 :(得分:2)
一个简单的解决方案是将您的歌曲列表/歌曲信息实现为TCollection。
通过使用集合,您可以让VCL处理加载并保存到磁盘。
例如:
请注意这不是功能完整的,我会把它留给你,因为我从头顶写下这个我可能搞砸了。这只是让你入门的一个例子。
{...}
interface
Type
TSongCollectionItem = class(TCollectionItem)
public
constructor create(Owner:TCollection); override;
procedure assign(source : TPersistent); override;
published
property FileName : String read fFileName Write fFileName;
property Artist : string read fArtist write fArtist;
property Title : string read fTitle write fTitle;
{...}
property Album : string read fAlbum write fAlbum;
end;
TSongCollection = class(TOwnedCollection)
private
function GetItem(Index: Integer): TSongCollectionItem;
procedure SetItem(Index: Integer; Value: TSongCollectionItem);
public
constructor Create(AOwner: TPersistent);
function Add: TSongCollectionItem;
property Songs[Index: Integer]: TSongCollectionItem read GetItem write SetItem; default;
end;
procedure SaveSongList(Songs : TSongCollection; FileName:string; Binary:boolean);
procedure LoadSongList(Songs : TSongCollection; FileName:string; Binary:boolean);
{...}
implementation
{...}
type
TSongComponent = class(TComponent)
published
property SongList : TSongCollection read fsonglist write SetSongList;
end;
procedure SaveSongList(Songs : TSongCollection; FileName:string; Binary:boolean);
var
wFile : TFileStream;
wConvert : TMemoryStream;
wSongList : TSongComponent;
begin
RegisterClass(TSongComponent);
Try
wConvert := TMemoryStream.Create;
wFile := TFileStream.Create(filename, fmcreate);
wSongList := TSongComponent.create(nil);
try
wSongList.SongList.Assign(Songs);
if not Binary then
begin
wConvert.WriteComponent(wSongList);
wConvert.Position := 0;
ObjectBinaryToText(wConvert, wFile);
end
else
wFile.WriteComponent(wSongList);
finally
wConvert.Free;
wFile.Free;
wSongList.free;
end;
finally
Unregisterclass(TSongComponent);
end;
end;
procedure LoadSongList(Songs : TSongCollection; FileName:string; Binary:boolean);
var
wFile : TFileStream;
wConvert : TMemoryStream;
wSongList : TSongComponent;
begin
RegisterClass(TSongComponent);
Try
wConvert := TMemoryStream.Create;
wFile := TFileStream.Create(filename, fmOpenRead);
try
if not Binary then
begin
ObjectTextToBinary(wFile, wConvert);
wConvert.Position := 0;
wSongList := TSongComponent(wConvert.ReadComponent(Nil));
end
else
wSongList := TSongComponent(wFile.ReadComponent(Nil));
if assigned(Songs) and assigned(wSongList) then
Songs.Assign(wSongList.Songs);
if assigned(wSongList) then
wSongList.free;
finally
wConvert.Free;
wFile.Free;
end;
finally
Unregisterclass(TSongComponent);
end;
end;
答案 2 :(得分:1)
随着时间的推移,我已经完成了一些这样的“列表”,最后我总是发现让这些类变得相当容易,但是至少可以说,存储并特别是从磁盘读取列表已经证明是“具有挑战性”。
在用户实际使用外部编辑器操作列表的情况下遇到了挑战,因此阅读列表容易出错。
对于普遍接受的播放列表格式(M3U),请查看http://schworak.com/programming/music/playlist_m3u.asp。
Torry的名为“PlayList v.0.5.1”的VCL组件包含多种格式的源代码。 http://www.torry.net/quicksearchd.php?String=PlayList+v.0.5.1&Title=Yes
答案 3 :(得分:1)
如果您不想构建全局对象结构,则可以始终在报告模式下使用TlistView结构。 你有一个列表,子项目。 您可以按列排序,并保存为csv或任何格式。 你可以轻松添加图标等.....
并且您有正确的事件要触发。