Lista de reprodução para Music Player em Delphi / Lista de vários itens de dados
Pergunta
Eu gostaria de ter uma lista de reprodução para meu próprio tocador de música em Delphi / Pascal.
Eu pensei que seria a melhor solução ter uma lista de tstring com o caminho do arquivo MP3 e - adicionalmente - um TlistBox com os nomes das músicas. As cordas correspondentes nas duas listas devem estar na mesma posição. Portanto, se o usuário escolher o item 5 no TlistBox, eu poderá seguir o caminho na posição 5 na lista TString.
Isso funciona bem.
Mas agora eu preciso de uma lista de reprodução com duas colunas: "Artist" e "Song Title". Você deve ser capaz de classificar a lista de reprodução do artista (ascendente e descendente), bem como pelo título da música (ascendente e descendente) - alfabeticamente, é claro.
Como eu poderia fazer isso? Tendo dois objetos da tstringlist - um classificado por artista e um classificado pelo título da música?
Solução
Eu fiz algumas dessas "listas" ao longo do tempo e, no final, sempre achei facilitadas as aulas, mas armazenando e principalmente a leitura das listas do disco provou "desafiador" para dizer o mínimo.
O desafio foi nos casos onde os usuários realmente manipulam as listas com editores externos, tornando a leitura da lista propensa a erros.
Para um formato de lista de reprodução universalmente aceito (M3U), dê uma olhada http://schworak.com/programming/music/playlist_m3u.asp.
Um componente VCL com fonte que lê vários formatos está disponível na Torry, chamada "Playlist v.0.5.1". http://www.torry.net/quicksearchd.php?string=playList+v.0.5.1&title=yes
Outras dicas
Eu faria uma classe Tsong contendo pelo menos as propriedades do artista e do título, e uma tsonglist fornecendo 1 ou mais métodos de classificação (pode ser genérico) usando o campo de classificação adequado (s.
Certamente não mantendo 2 listas de strings separadas que você precisa gerenciar, mantenha -se sincronizado e remodelando ao classificar ...
Uma maneira barata de implementar isso pode ser ter um conjunto de dados na memória com um registro contendo artista e caminho exibido em uma grade que você pode classificar em diferentes colunas.
A linha atual fornecerá as duas informações diretamente.
Uma solução simples seria implementar sua lista de músicas/informações de músicas como uma tcollection.
Usando coleções, você pode deixar o VCL lidar com o carregamento e a economia no disco.
Por exemplo:
Observe que isso não está funcionalmente completo, deixarei isso para você e, desde que escrevi isso do topo da minha cabeça, eu poderia ter bagunçado algo. É apenas um exemplo para você começar.
{...}
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;
Se você não deseja criar uma estrutura global de objetos, pode sempre usar a estrutura do TLISTView no modo de relatório. Você tem uma lista, com subitems. Você pode classificar por coluna e salvar no CSV ou qualquer formato. você pode facilmente adicionar ícones etc .....
E você tem os eventos certos para acionar.