Playlist for music player in Delphi / List of multiple data items
I would like to have a playlist for my own music player开发者_运维知识库 in Delphi / Pascal.
I thought that it would be the best solution to have a TStringList with the path of the MP3 file and - additionally - a TListBox with the song names. The matching strings in both lists must be at the same position. So if the user chooses item 5 in TListBox I can just take the path at position 5 in the TStringList.
This works fine.
But now I need a playlist with two columns: "artist" and "song title". You should be able to sort the playlist by artist (ascending and descending) as well as by song title (ascending and descending) - alphabetically, of course.
How could I do this? Having two objects of TStringList - one sorted by artist and one sorted by song title?
I would do a TSong class containing at least the Artist and Title properties, and a TSongList providing 1 or more sort methods (can be generic) using the proper sort Field(s.
Certainly not maintaining 2 separate StringLists that you have to manage, keep in sync and reshuffle when sorting...
One cheap way to kinda implement that, could be to have an in memory DataSet with a record containing Artist and Path displayed in a grid that you can sort on different columns.
The current row will give both informations directly.
One simple solution would be to implement your song list/song information as a TCollection.
By using collections you can let the VCL handle the loading and saving to disk.
For example:
Please note this is not functionally complete, I'll leave that up to you, and since I wrote this from the top of my head I might have messed something up. It is only an example to get you started.
{...}
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;
I've done a few of these "lists" over time and in the end I've always found making the classes rather easy, but storing and especially reading the lists from disk has proven "challenging" to say the least.
The challenge has been in cases were users actually manipulate the lists with external editors, thus making reading the lists error prone.
For a universally accepted playlist format (M3U) have a look at http://schworak.com/programming/music/playlist_m3u.asp.
A VCL component with source that reads multiple formats is available at Torry's called "PlayList v.0.5.1". http://www.torry.net/quicksearchd.php?String=PlayList+v.0.5.1&Title=Yes
If you don't want to build an global object structure, you can allways use TlistView structure in report mode. You have there a list, with subitems. You can sort by column, and save to csv or whatever format. you can easily add icons etc.....
and you have the right events to trigger.
精彩评论