【问题标题】:Playlist for music player in Delphi / List of multiple data itemsDelphi中音乐播放器的播放列表/多个数据项列表
【发布时间】:2010-02-13 23:30:05
【问题描述】:

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

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

这很好用。

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

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

【问题讨论】:

  • 这个问题的更好的标题是指问题 - 多个数据项的列表 - 而不是专门针对音乐播放器的播放列表。这将使它可以被其他用户搜索。
  • 我已将此添加到标题中。

标签: delphi string sorting pascal playlist


【解决方案1】:

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

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

【讨论】:

  • Dataset 选项无论如何都值得研究,因为保留歌曲信息是个好主意。
  • 我不能使用 TDataSet(Delphi 不知道!?)但第一段非常有帮助。谢谢!
【解决方案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;

【讨论】:

  • 非常感谢,我可以使用您的代码的几个部分:) 非常有帮助!
【解决方案3】:

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

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

有关普遍接受的播放列表格式 (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

【讨论】:

  • 谢谢,有趣的链接 :) 但我没有寻找导入播放列表文件的方法。相反,我正在寻找一种方法来处理我的程序中的播放列表(存储、排序等)。
  • 一种方法是使用 TMyPlaylist = class(Tlist) 对象来处理列表本身,然后每个条目可以是 TMyPlaylistEntry = class(TObject)。对于排序等,您需要编写自己的比较代码。有关详细信息,请查看delphi.about.com/od/adptips2003/a/bltip1103_3.htm
  • 非常感谢!不过,关于 M3U 的链接不是我想要的,但很有趣。而你的评论正是我现在所做的。
【解决方案4】:

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

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

【讨论】:

  • TListView 有一些有趣的方法和选项,谢谢!
猜你喜欢
  • 2012-06-19
  • 2021-07-26
  • 1970-01-01
  • 1970-01-01
  • 2014-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多