MP3プレイヤーを作っているのですが、わからないことがあるので質問します。
SHBrowserForFolder APIを使ってフォルダ選択のダイアログを表示するまではできたのですが、選択したフォルダからMP3ファイルを検索してListBox1に曲名を表示する方法が分かりません。
ListBox1には下記のように表示したいと思います。
よろしくお願いします。
01 ***.mp3
02 ***.mp3
03 ***.mp3
TFileListBoxは?
あるディレクトリのなかの特定の拡張子をもったファイルを列挙するには
FindFirst FindNext FindClose を使います。ヘルプで調べてください。
procedure TForm1.Button1Click(Sender: TObject);
var
sr:TSearchRec;
ret,cnt:integer;
begin
cnt := 0;
ret := FindFirst('C:\*.txt',faAnyFile,sr);
while ret = 0 do
begin
Inc(cnt);
ListBox1.Items.Add(Format('%.2d %s',[cnt,sr.FindData.cFileName]));
ret := FindNext(sr);
end;
FindClose(sr);
end;
このコードでは、C\ ディレクトリの *.txt ファイルを列挙して ListBox1 に
01 test.txt
02 readme.txt
のように表示します。
それを自動でやってくれるのがTFileListBoxでは?
疑問に思った時は,ヘルプで調べたり,実際にやってみるといいかも知れません.
> それを自動でやってくれるのがTFileListBoxでは?
そうですか? どうやって
01 ***.mp3
02 ***.mp3
03 ***.mp3
のように表示するのですか?
TFileListBoxの場合は,Maskプロパティの設定ですね.
ただ,FindFirst FindNext FindClose を利用する方法は,いろいろ
応用がききますので便利です.
>01 ***.mp3
>02 ***.mp3
>03 ***.mp3
こうなると,FileListBoxではお手上げですね.
レスありがとうございます。
TFileListBoxを使うことで解決することができました。
そこでもう一つ質問したいのですが、FileListBoxで上から何番目が選択されていることをLabel1に表示したいのですが、どのようにすればいいのでしょうか?
ItemIndex
表示するならIntToStr(FileListBox1.ItemIndex+1)ですね
>TFileListBoxを使うことで解決することができました
質問は,
>01 ***.mp3
>02 ***.mp3
>03 ***.mp3
のように,左端に番号みたいのを表示するわけですよね.
TFileListBoxを使ってどうやって解決したのか,差支えなかったら教えて
いただけますか.私だけが(jokさんも?)知らないのかしら.
イベントなんかを使用するのですか.
Items[i]:=inttostr(i)+Items[i]とかじゃ無理でしょうね
やってないんじゃないですか?
>Items[i]:=inttostr(i)+Items[i]とかじゃ無理でしょうね
>やってないんじゃないですか?
はぁ?Item[i]に直接番号追加したら永久ループして
最悪はオーバーフローするでしょ?
ちょっとは考えてからアドバイスしてあげたらどうですか?
TFileListBoxがTCustomListBoxからの派生クラスのため
OnDrawItemが使えないか試してみましたが
TFileListBox内ですでにOnDrawItemを使用しているせいか
描画処理を奪えませんでした。
ソースをお持ちであればTFileListBoxを参考にTCustomListBoxから
派生させて作成するぐらいしかないようです。
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, FileCtrl;
type
TFileListBoxEx = class(TFileListBox)
private
{ Private 宣言 }
procedure OnDrawItemEventEx(Control: TWinControl; Index: Integer;Rect: TRect; State: TOwnerDrawState);
public
{ Public 宣言 }
constructor Create(AOwner: TComponent); override;
end;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private 宣言 }
FFileListBoxEx : TFileListBoxEx;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
{ TFileListBoxEx }
constructor TFileListBoxEx.Create(AOwner: TComponent);
begin
inherited;
OnDrawItem := OnDrawItemEventEx;
Style := lbOwnerDrawVariable;
end;
procedure TFileListBoxEx.OnDrawItemEventEx(Control: TWinControl;
Index: Integer; Rect: TRect; State: TOwnerDrawState);
begin
// 64ドット右に移動させようとしたけど処理がここには来ない
Canvas.TextOut(Rect.Left + 64, Rect.Top, (Control as TListBox).Items[Index])
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FFileListBoxEx := TFileListBoxEx.Create(Self);
FFileListBoxEx.Parent := Self;
FFileListBoxEx.Align := alClient;
end;
気になって色々やってみていますがOnDrawItemは使えないけど
DrawItemをオーバーライドすることはできるようです。
これで
>01 ***.mp3
>02 ***.mp3
>03 ***.mp3
のような表示も可能ではないでしょうか?
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, FileCtrl;
type
TFileListBoxEx = class(TFileListBox)
private
{ Private 宣言 }
public
{ Public 宣言 }
procedure DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState); override;
end;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private 宣言 }
FFileListBoxEx : TFileListBoxEx;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
{ TFileListBoxEx }
procedure TForm1.FormCreate(Sender: TObject);
begin
FFileListBoxEx := TFileListBoxEx.Create(Self);
FFileListBoxEx.Parent := Self;
FFileListBoxEx.Align := alClient;
end;
procedure TFileListBoxEx.DrawItem(Index: Integer; Rect: TRect;
State: TOwnerDrawState);
begin
Canvas.TextOut(Rect.Left + 2, Rect.Top,Format('%2.2d ',[Index + 1]) + Items[Index])
end;
> ちょっとは考えてからアドバイスしてあげたらどうですか?
質問を素直に読めば FileListBox を使うより、FindFirst FindNext FindClose
をつかって ListBox に列挙するのが普通だと思います。
>質問を素直に読めば FileListBox を使うより、FindFirst FindNext FindClose
>をつかって ListBox に列挙するのが普通だと思います。
質問者のpicさんに対してはそれで解決だと思いますが
Mr.XRAYさんの便乗質問として
>TFileListBoxを使ってどうやって解決したのか,差支えなかったら教えて
>いただけますか.私だけが(jokさんも?)知らないのかしら.
とあったので誰か答えるかと思ったら
>Items[i]:=inttostr(i)+Items[i]
という意味不明な回答があったのが目につき指定して方法を記述して
答えたのですが・・・
私の変な発言でお騒がせしてスミマセン.
takeさんどうも.
>DrawItemをオーバーライドすることはできるようです。
なるほど,継承元のTCustomListBoxのprotectedにDrawItemが一応あるん
ですね.提示コードをコピペして実行してみました.
もちろん,私自身もファイルのリスト表示にはFindfirstを使いますが,
takeさんのコードも大変勉強になります.
質問者がTFileListBoxを使用して解決した,というので,思わず,
「えっ,どうやって」
と勢いで発言してしまいましたが,思わぬ拾い物をしました.
ふーむ、思わぬ展開になってますね(笑い
るるとんさんは、書き込むまえに、一度立ち止まって、3分くらい考えたほうが
いいかも。質問者の方は、ListBox の使い方にも慣れていらっしゃらないようなので
なるべくコードを書かかなくてもいい方を選んだんでしょうね。多少の仕様は犠牲に
して。
jokさんが書いたからという訳でもないのですが,
質問される方は,不明なことがあって,中には,ようやっとこの掲示板
にたどりついて,という方もいるかも知れません.
必死の思いで質問している方をまどわしてしまうと,ちょっとかわいそうで
すよね.
もちろん,いろいろなアイディアや考え方を提示するのは,いいことだとは
思います.
FileNameは狂いますが
var
i:integer;
s:string;
begin
for i:=0 to f.Count-1 do
begin
s:=inttostr(i);
if Length(s)=1 then s:=s+' ';
FileListBox1.Items[i]:=s+' '+FileListBox1.Items[i];
end;
end;
ではどうでしょう?
>はぁ?Item[i]に直接番号追加したら永久ループして
永久ループ!?それは大変
ごめんなさい間違えた
var
i:integer;
s:string;
begin
for i:=0 to FileListBox1.Count-1 do
begin
s:=inttostr(i);
if Length(s)=1 then s:='0'+s;
FileListBox1.Items[i]:=s+' '+FileListBox1.Items[i];
end;
end;
でした
> 永久ループ!?それは大変
えーとですね、コードは簡単なんですが、それをどのタイミングで実行する
のですか? まさかボタンを押すわけではないでしょ。ディレクトリを代えるたびに
ユーザにボタンを押させるのは変でしょ。自動で実行させるためには、どのイベント
でそのコードを実行させたらいいと思いますか? 永久ループを避けるのはどうしたら
いいでしょうか?
>ごめんなさい間違えた
ちょっといじめちゃおうかな.
るるとん@Kさん,もちろん,初心者がまよわない様に,ご自分で,動作確認
済みですよね?.
jokさんやtakeさんのコードも試してみましたか?
(コピペするだけで動作します.もちろんイベントはオブジェクト・インス
ペクタで選択する必要があります)
OnChangeです
ディレクトリ一覧も使って試しましたよ
procedure TForm1.FileListBox1Change(Sender: TObject);
var
i:integer;
s:string;
begin
for i:=0 to FileListBox1.Count-1 do
begin
s:=inttostr(i);
if Length(s)=1 then s:='0'+s;
FileListBox1.Items[i]:=s+' '+FileListBox1.Items[i];
end;
end;
私には何が永久ループなのかわかりません
>OnChangeです
>ディレクトリ一覧も使って試しましたよ
ディレクトリ変更した時には ちゃんと表示されるにゃ〜
にゃ〜も、ファイル一覧が表示されてる時に FileListBox1 を
クリックしてみなかったんかにゃ〜?
クリックしてファイル選択すると面白いことが起こるにゃ〜
選択してから↑↓キー押しても面白いにゃ〜、コレどうするにゃ〜
function CSRight(BString,CWord:String):String;
begin
result:=RightStr(BString,Length(BString)
-AnsiPos(CWord,BString)-Length(CWord)+1);
end;
procedure TForm1.FileListBox1Change(Sender: TObject);
var
i:integer;
s,t:string;
begin
for i:=0 to FileListBox1.Count-1 do
begin
s:=inttostr(i);
if Length(s)=1 then s:='0'+s;
t:=FileListBox1.Items[i];
if ansipos(' ',t)>0 then t:=CSRight(t,' ');
FileListBox1.Items[i]:=s+' '+t;
end;
end;
画面がちらつく ※要StrUtils
すみません
ansipos(' ',t)>0
ではファイル名もひっかかりますね、、
FileListBoxのディレクトリを変える処理で実行すればどうでしょう?SHBrowserForFolder APIを使ってフォルダ選択のダイアログを表示する処理でやればよいのでは?
> FileListBoxのディレクトリを変える処理で実行すればどうでしょう?
そうですね。FileListBox にディレクトリをセットして、それから、コードを
実行してみてください。項目がセットされるタイミングの後、一回だけ実行
実行できるといいのですね。是非試してみてください。
るるとん@Kさんのコードを試しましたが選択したファイル名を取得しようと
FileNameプロパティを読み込むと番号も返ってきますね。
ここからまた番号を取り除く処理をする必要もありそうですね。
上記で永久ループの恐れがあると書いたのはプロパティを変更すると
OnChangeイベントが発生するコンポーネントもあるからです。
そのコンポーネントの場合にOnChange内で変更処理をしてしまうと再度OnChange
が発生してしまいオーバーフローすることがあるからです。
この場合はItemsに対してなので大丈夫ですが表示イベントや変更通知イベント内で
自身の値の変更を行うことは極力さけるべきでしょう。
TFileListBoxってWin3.1のタブにあるので心配で使わなかったけど
結構面白いですね。勉強になりました。
ツイート | ![]() |