フォルダからMP3ファイルを検索してListBox1に表示するには?


pic  2004-04-15 02:33:11  No: 8353

MP3プレイヤーを作っているのですが、わからないことがあるので質問します。
SHBrowserForFolder APIを使ってフォルダ選択のダイアログを表示するまではできたのですが、選択したフォルダからMP3ファイルを検索してListBox1に曲名を表示する方法が分かりません。
ListBox1には下記のように表示したいと思います。
よろしくお願いします。
01 ***.mp3
02 ***.mp3
03 ***.mp3


るるとん@K  2004-04-15 03:10:49  No: 8354

TFileListBoxは?


jok  2004-04-15 05:48:56  No: 8355

あるディレクトリのなかの特定の拡張子をもったファイルを列挙するには
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

のように表示します。


るるとん@K  2004-04-15 06:53:44  No: 8356

それを自動でやってくれるのがTFileListBoxでは?


Mr.XRAY  URL  2004-04-15 07:04:31  No: 8357

疑問に思った時は,ヘルプで調べたり,実際にやってみるといいかも知れません.


jok  2004-04-15 07:05:32  No: 8358

> それを自動でやってくれるのがTFileListBoxでは?

そうですか? どうやって

01 ***.mp3
02 ***.mp3
03 ***.mp3

のように表示するのですか?


Mr.XRAY  URL  2004-04-15 07:07:58  No: 8359

TFileListBoxの場合は,Maskプロパティの設定ですね.
ただ,FindFirst FindNext FindClose を利用する方法は,いろいろ
応用がききますので便利です.


Mr,XRAY  URL  2004-04-15 07:09:39  No: 8360

>01 ***.mp3
>02 ***.mp3
>03 ***.mp3

こうなると,FileListBoxではお手上げですね.


pic  2004-04-16 03:13:49  No: 8361

レスありがとうございます。
TFileListBoxを使うことで解決することができました。
そこでもう一つ質問したいのですが、FileListBoxで上から何番目が選択されていることをLabel1に表示したいのですが、どのようにすればいいのでしょうか?


んぽ  2004-04-16 03:20:38  No: 8362

ItemIndex


るるとん@K  2004-04-16 04:29:13  No: 8363

表示するならIntToStr(FileListBox1.ItemIndex+1)ですね


Mr.XRAY  URL  2004-04-16 06:04:03  No: 8364

>TFileListBoxを使うことで解決することができました

質問は,

>01 ***.mp3
>02 ***.mp3
>03 ***.mp3

のように,左端に番号みたいのを表示するわけですよね.
TFileListBoxを使ってどうやって解決したのか,差支えなかったら教えて
いただけますか.私だけが(jokさんも?)知らないのかしら.
イベントなんかを使用するのですか.


るるとん@K  2004-04-16 06:18:19  No: 8365

Items[i]:=inttostr(i)+Items[i]とかじゃ無理でしょうね
やってないんじゃないですか?


take  2004-04-16 21:54:52  No: 8366

>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;


take  2004-04-16 22:07:35  No: 8367

気になって色々やってみていますが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;


つっか  2004-04-16 23:40:20  No: 8368

> ちょっとは考えてからアドバイスしてあげたらどうですか?

質問を素直に読めば FileListBox を使うより、FindFirst FindNext FindClose
をつかって ListBox に列挙するのが普通だと思います。


take  2004-04-17 00:16:08  No: 8369

>質問を素直に読めば FileListBox を使うより、FindFirst FindNext FindClose
>をつかって ListBox に列挙するのが普通だと思います。

質問者のpicさんに対してはそれで解決だと思いますが
Mr.XRAYさんの便乗質問として

>TFileListBoxを使ってどうやって解決したのか,差支えなかったら教えて
>いただけますか.私だけが(jokさんも?)知らないのかしら.

とあったので誰か答えるかと思ったら
>Items[i]:=inttostr(i)+Items[i]
という意味不明な回答があったのが目につき指定して方法を記述して
答えたのですが・・・


Mr.XRAY  URL  2004-04-17 03:04:54  No: 8370

私の変な発言でお騒がせしてスミマセン.

takeさんどうも.
>DrawItemをオーバーライドすることはできるようです。

なるほど,継承元のTCustomListBoxのprotectedにDrawItemが一応あるん
ですね.提示コードをコピペして実行してみました.
もちろん,私自身もファイルのリスト表示にはFindfirstを使いますが,
takeさんのコードも大変勉強になります.

質問者がTFileListBoxを使用して解決した,というので,思わず,
「えっ,どうやって」
と勢いで発言してしまいましたが,思わぬ拾い物をしました.


jok  2004-04-17 08:17:03  No: 8371

ふーむ、思わぬ展開になってますね(笑い

るるとんさんは、書き込むまえに、一度立ち止まって、3分くらい考えたほうが
いいかも。質問者の方は、ListBox の使い方にも慣れていらっしゃらないようなので
なるべくコードを書かかなくてもいい方を選んだんでしょうね。多少の仕様は犠牲に
して。


Mr.XRAY  URL  2004-04-17 09:02:30  No: 8372

jokさんが書いたからという訳でもないのですが,

質問される方は,不明なことがあって,中には,ようやっとこの掲示板
にたどりついて,という方もいるかも知れません.
必死の思いで質問している方をまどわしてしまうと,ちょっとかわいそうで
すよね.

もちろん,いろいろなアイディアや考え方を提示するのは,いいことだとは
思います.


るるとん@K  2004-04-17 17:37:37  No: 8373

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]に直接番号追加したら永久ループして
永久ループ!?それは大変


るるとん@K  2004-04-17 17:39:31  No: 8374

ごめんなさい間違えた
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;
でした


jok  2004-04-17 20:01:01  No: 8375

> 永久ループ!?それは大変

えーとですね、コードは簡単なんですが、それをどのタイミングで実行する
のですか? まさかボタンを押すわけではないでしょ。ディレクトリを代えるたびに
ユーザにボタンを押させるのは変でしょ。自動で実行させるためには、どのイベント
でそのコードを実行させたらいいと思いますか? 永久ループを避けるのはどうしたら
いいでしょうか?


Mr.XRAY  URL  2004-04-17 20:08:28  No: 8376

>ごめんなさい間違えた

ちょっといじめちゃおうかな.
るるとん@Kさん,もちろん,初心者がまよわない様に,ご自分で,動作確認
済みですよね?.
jokさんやtakeさんのコードも試してみましたか?
(コピペするだけで動作します.もちろんイベントはオブジェクト・インス
ペクタで選択する必要があります)


るるとん@K  2004-04-17 20:52:50  No: 8377

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;


るるとん@K  2004-04-17 20:56:14  No: 8378

私には何が永久ループなのかわかりません


にゃ〜  2004-04-17 21:37:19  No: 8379

>OnChangeです
>ディレクトリ一覧も使って試しましたよ

ディレクトリ変更した時には ちゃんと表示されるにゃ〜
にゃ〜も、ファイル一覧が表示されてる時に FileListBox1 を
クリックしてみなかったんかにゃ〜?
クリックしてファイル選択すると面白いことが起こるにゃ〜
選択してから↑↓キー押しても面白いにゃ〜、コレどうするにゃ〜


るるとん@K  2004-04-17 23:58:56  No: 8380

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


るるとん@K  2004-04-18 00:00:12  No: 8381

すみません
ansipos(' ',t)>0
ではファイル名もひっかかりますね、、


るるとん@K  2004-04-18 00:01:41  No: 8382

FileListBoxのディレクトリを変える処理で実行すればどうでしょう?SHBrowserForFolder APIを使ってフォルダ選択のダイアログを表示する処理でやればよいのでは?


jok  2004-04-18 01:15:38  No: 8383

> FileListBoxのディレクトリを変える処理で実行すればどうでしょう?

そうですね。FileListBox にディレクトリをセットして、それから、コードを
実行してみてください。項目がセットされるタイミングの後、一回だけ実行
実行できるといいのですね。是非試してみてください。


take  2004-04-19 18:13:53  No: 8384

るるとん@Kさんのコードを試しましたが選択したファイル名を取得しようと
FileNameプロパティを読み込むと番号も返ってきますね。
ここからまた番号を取り除く処理をする必要もありそうですね。

上記で永久ループの恐れがあると書いたのはプロパティを変更すると
OnChangeイベントが発生するコンポーネントもあるからです。
そのコンポーネントの場合にOnChange内で変更処理をしてしまうと再度OnChange
が発生してしまいオーバーフローすることがあるからです。
この場合はItemsに対してなので大丈夫ですが表示イベントや変更通知イベント内で
自身の値の変更を行うことは極力さけるべきでしょう。

TFileListBoxってWin3.1のタブにあるので心配で使わなかったけど
結構面白いですね。勉強になりました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加