1

我想在 Delphi / Pascal 中有一个我自己的音乐播放器的播放列表。

我认为拥有一个带有 MP3 文件路径的 TStringList 以及 - 另外 - 一个带有歌曲名称的 TListBox 将是最好的解决方案。两个列表中的匹配字符串必须位于相同的位置。因此,如果用户在 TListBox 中选择第 5 项,我可以在 TStringList 中的位置 5 处获取路径。

这工作正常。

但现在我需要一个包含两列的播放列表:“艺术家”和“歌曲名称”。您应该能够按艺术家(升序和降序)以及歌曲标题(升序和降序)对播放列表进行排序 - 当然是按字母顺序。

我怎么能这样做?有两个 TStringList 对象 - 一个按艺术家排序,一个按歌曲名称排序?

4

4 回答 4

4

我会做一个 TSong 类,其中至少包含 Artist 和 Title 属性,以及一个 TSongList 使用正确的排序字段提供 1 个或多个排序方法(可以是通用的)。
当然不维护你必须管理的 2 个单独的 StringList,保留排序时同步和重新洗牌......

实现这一点的一种廉价方法可能是在内存中创建一个 DataSet,其中包含一个包含 Artist 和 Path 的记录,显示在一个网格中,您可以在不同的列上进行排序。
当前行将直接提供这两个信息。

于 2010-02-14T00:03:29.537 回答
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;
于 2010-02-14T15:11:31.737 回答
1

随着时间的推移,我已经完成了一些这样的“列表”,最后我总是发现让这些类变得相当容易,但是至少可以说,从磁盘存储,尤其是从磁盘读取列表已经被证明是“具有挑战性的”。

挑战在于,如果用户实际使用外部编辑器操作列表,从而使阅读列表容易出错。

有关普遍接受的播放列表格式 (M3U),请查看http://schworak.com/programming/music/playlist_m3u.asp

Torry 提供了一个 VCL 组件,其源代码可以读取多种格式,名为“PlayList v.0.5.1”。http://www.torry.net/quicksearchd.php?String=PlayList+v.0.5.1&Title=Yes

于 2010-02-14T08:01:03.900 回答
1

如果不想构建全局对象结构,可以在报表模式下始终使用 TlistView 结构。你有一个带有子项目的列表。您可以按列排序,并保存为 csv 或任何格式。您可以轻松添加图标等......

并且您可以触发正确的事件。

于 2010-02-14T13:54:53.013 回答