2007年08月27日

Delphiで、フォルダ選択ダイアログを自作する際に参考になるサイト

エントリ「Delphiで、フォルダ(ディレクトリ)の選択ダイアログを表示するには」で結局Delphi6ではフォルダ選択ダイアログは自作しないといまいち、といった事を書きましたが、では実際に自作しようとすると下記のサイトが役に立ちます。

「フォルダの参照」ダイアログを表示する
http://homepage1.nifty.com/MADIA/delphi/Win32API/SHopenFolder.htm
まずはここ。Delphiのサンプルで、余計なことはしていないので、SHBrowseForFolder関数を使うための全体の流れが把握できます。

フォルダを選択するダイアログ(前編)
http://www.kab-studio.biz/Programing/Codian/ShellExtension/02.html
フォルダを選択するダイアログ(後編)
http://www.kab-studio.biz/Programing/Codian/ShellExtension/04.html
Delphiの解説ではありませんが、フラグの種類、コールバック関数で処理すべきメッセージなど、詳しく解説されているのでSHBrowseForFolder全体の仕組みが非常によく分かります。

フォルダ選択ダイアログクラス
http://rararahp.cool.ne.jp/vc/class/browseFolderDialog.htm
こちらにも、フラグの解説が簡単にですが一通り載っているので、役に立つかも。

というわけで、大体以上のサイトを見ておけばSHBrowseForFolder関数を使うために必要な知識がすっかり手に入ります。感謝。

2007年04月14日

Quadruple Dをコンポーネントとしてインストールせずに使うには

DirectXを使ったソフトを作ろうと思ってVisual C#とManaged DirectXに挑戦してみたんですが、結局時代遅れのDelphi6に戻ってしまいました。DirectXが直接対応しているという点でC#は有利なんですが、やっぱり新しく言語を覚えるってのは手間ですね。しかもVisual C# 2005 Express Editionはいちいち重いし……(Delphi6のIDEが今となってはちょっ速過ぎるのですが)。

で、DelphiでDirectXと言ったらQuadruple Dなんですが、コンポーネントのインストールは便利な反面、環境を変えるたびにインストールし直さなければならず面倒です。そこでQuadruple Dをコンポーネントとしてインストールせずにライブラリとして使う方法を調べてみると、有用なブログが見つかりました。
Delphi6 PersonalやTurbo Delphiはコンポーネントのインストールができないのでこの方法しかないですし、自分のように普通のDelphiでもインストールせずに使いたいということはあるかと思います。Quadruple Dに限らず使える方法ですし。

続きを読む

2006年07月20日

Delphiで、フォルダ(ディレクトリ)の選択ダイアログを表示するには

【7/21追記】
コメントを頂きました。Delphi2006の環境では、画面の中央に表示したり、選択されているフォルダのパスを表示したりと言ったことが出来るそうです。いいなぁ……
というわけで、この記事はDelphi6の場合ということでお読み下さい。

Delphiで、フォルダ(ディレクトリ)の選択ダイアログを表示する方法ですが、Delphiにはお手軽に使える同名の関数が2つ用意されています。SelectDirectory関数です。FileCtrlユニットにあるので、uses節に追加すれば使えます。

function SelectDirectory(var Directory: string; Options: TSelectDirOpts;
  HelpCtx: Longint): Boolean; overload;

SelectDirectory関数その1 まずこちらの定義ですが、これで表示されるダイアログはこんな感じになります。古いウィンドウズのスタイルで、デスクトップやマイドキュメントといった概念はなく、ネットワークフォルダも選択できません。あんまり使えないですね。

function SelectDirectory(const Caption: string; const Root: WideString;
  out Directory: string): Boolean; overload;

SelectDirectory関数その2 もう一つの定義で表示するとこうなります。これはSHBrowseForFolderを使った、正しい(?)フォルダ選択ダイアログです。ただ、この関数はシンプルな代わりにいくつか弊害があります。まず、表示される位置が不思議です。常にスクリーンの左下付近に現れます。また、現在選択されているフォルダをラベルに表示したり、選択できるフォルダを指定したりといったことができません。

というわけで、結局SHBrowseForFolderを使って関数を自作しないとダメかもです。

タグ:Delphi

2006年07月19日

OleCheckって何だ!?

SHGetDesktopFolderだのなんだの、SHが付く関数のDelphi用サンプルに必ずと言っていいほど付いているOleCheck。名前と用途から察するにSH系関数の戻り値をチェックしているであろうことは容易に想像が付くけど、ちゃんとした意味、知らない……検索してみても、それ系のサンプルが見付かるばかりで、OleCheck自体を説明しているものが見付からない。困った、常識なんだろうか。自分は知らない。と思ったら簡潔に解説しているページがありました。

COMオブジェクト
http://www.geocities.co.jp/SiliconValley-SanJose/2560/delphi4/activex/ComObject.htm

なるほど、SH系関数が失敗した時にEOleSysError例外を生成するためのものらしい。ちなみに、DelphiでOleCheckなどはComObjユニットにあります。

Delphiで、SH系のAPIを使うときのお作法

SHGetSpecialFolderLocationだの、SHGetPathFromIDListだの、SHBrowseForFolderだの、SHなんとかという関数を検索していると、サンプルはいっぱい出てくるものの、VBやC++ではメモリの管理がすごく面倒くさそう。Delphiではメモリの管理や解放をどうすればいいのかさっぱり分からなくなってきます。自分のように難しいことはいいからとにかくやりたいことだけやりたい、という場合はなおさらイライラします(笑)
Delphi-MLの過去ログに同じ話題がありました。

[Delphi-ML:80810] SHGetSpecialFolderLocation 使用後のメモリ解放について(長文)
http://www2.big.or.jp/~osamu/Delphi/delphi-browse.cgi?index=080810

とどのつまり、こういう事らしいです。

  • インターフェイス(IMallocとか)はDelphiが解放してくれるので放っておいてよい。
  • PItemIDListとかは解放しないとダメ。

タグ:Delphi

2006年07月17日

Delphiで、タスクバーのボタンを非表示にする

昨日のTip「タスクトレイにアイコンを表示するには」に付随して、アプリケーションがタスクバーに表示されるのを防ぐ方法ですが、SetWindowLongを使う方法の他に、Delphiでは下記の方法もありました。

Application.ShowMainForm := False;

たったこれだけです。設定ダイアログなどを表示した時だけタスクバーにも表示させたい時は、ダイアログを表示する前にTrueにセットし、閉じたらFalseに再設定するだけです。


2006年07月16日

Delphiで、タスクトレイにアイコンを表示するには

タスクトレイにアイコンを表示する方法ですが、フォームにポトリするだけでこの機能を実現するコンポーネントが沢山あるようなので、それらを使えば簡単です。ただ、小さいプログラムのためにわざわざコンポーネントをインストールするのも、ということでそれらを使わずに実現する方法です。すごく簡単で、検索すれば沢山出てきます。

タスクトレイにアイコンを追加する
http://homepage1.nifty.com/MADIA/delphi/Win32API/Tasktray.htm
このページの方法でまずは表示できるようになります。このサイトには他にもDelphiの役立つTipsが沢山。

次に同じウェブサイトのこのTipで、タスクバーにアプリケーションのアイコンをひょじしないように出来ます。タスクトレイにアイコンを表示するソフトは大抵が常駐用のソフトでタスクバーには表示されませんからね。

タスクバーにアイコンを表示させない
http://homepage1.nifty.com/MADIA/delphi/Win32API/AIconNoting.htm

同様のShowWindowLongメソッドがこちらのページにも解説されています。
タスクバーボタンを非表示に :: 謎奈の泉 -Delphi MemoPad-
http://uechoco.s14.xrea.com/delphi/memo0003.html

これで一通り出来るようになりましたが、タスクトレイのアイコンからポップアップメニューを呼び出した時の挙動がちょっとおかしい。メニューが消えないんですよね。これもこちらのページで解説されています。PopupMenu.Popupメソッドの前に、SetForegroundWindowを呼び出すといいらしい。

ポップアップメニューが消えない
http://90h.dip.jp/archives/2005/03/post.html

また、同様の操作はこちらのTipでもちゃんと行われてます。こちらではタスクバーが移動・再構築された時の対処も載っています。試していないのでわかりませんが。

Delphi Tips - アプリケーションを常駐させてタスクトレイに登録したい
http://www2.big.or.jp/~osamu/Delphi/tips.cgi?index=0207.txt

2006年07月13日

画像の拡大縮小その1,ニアレストネイバー法

画像の拡大縮小(リサンプリング Resamplling とも)アルゴリズムはPhotoshopがそうであるように、代表的なものが3つあります。
ニアレストネイバー法、バイリニア法、バイキュービック法です。普通はバイキュービック法で処理してしまえば特に問題ないんですが、バイキュービック法(バイリニア法も)は補間されてしまう為、ドット絵やアイコンなど、拡大時に元のドットをそのまま拡大したいような場合はニアレストネイバー法が適しています。
そもそも拡大時の補間はそこに本来無かったものを想像で作り出すということになるので、写実的というか、事実に忠実な拡大というのはニアレストネイバー法なんじゃないかという気がします。
ニアレストネイバー法は最近傍画素法とも言われるように、単純に縮小先のピクセルを縮小元でどこになるか計算し、それに一番近いピクセルの色を採用します。

前置きが長くなりましたがそのニアレストネイバー法のアルゴリズムをDelphiで実現した関数です。

// =============================================================================
// TBitmapをニアレストネイバー、最近傍画素法(一番近いピクセルから取得)でリサイズします。
// pf8bit, pf24bit, pf32bitのピクセルフォーマットのみ処理できます。
// 処理は速いですが品質はあまりよくありません。
// 拡大時にモザイク上の方がいい場合はこれが方が適しています。
// コピー元ピクセル値の決定時には四捨五入(Round関数)を使っています。
//
// MakeProgressEvent
//   プログレスイベントを発生させる場合、Trueを指定します。
//   イベントはSrcのOnProgressEventを介して発生します。従ってSrc.OnProgressが
//   設定されていない場合、Trueを指定しても何も起こりません。
//
// 成功の場合、新しいビットマップを生成して返します。失敗ならnilを返します。
// =============================================================================
function KIBResizeNearest(Src: TBitmap; const NewWidth, NewHeight: Integer;
  MakeProgressEvent: Boolean = False): TBitmap;
const
  // プログレスイベントで使用するメッセージ
  MSG = 'サイズ変更(ニアレストネイバー法)';
  // プログレスイベントで使用するゼロ矩形
  ZERO_RECT: TRect = (Left: 0; Top: 0; Right: 0; Bottom: 0);
var
  Dst: TBitmap;
  PixelFormat: TPixelFormat;
  SrcWidth, SrcHeight, OnePixelSize: Integer;
  SrcScanLineBuffer, DstScanLineBuffer: array of Pointer;
  x, y: Integer;
  pDst, pSrc: PByte;
  SrcX, SrcY: Integer;
begin
  // 少しでも速くするため、元画像の大きさとピクセルフォーマットを取得
  PixelFormat := Src.PixelFormat;
  SrcWidth := Src.Width;
  SrcHeight := Src.Height;

  // ピクセルフォーマットのチェック
  if not (PixelFormat in [pf8bit, pf24bit, pf32bit]) then
    raise Exception.Create('未対応のピクセルフォーマットです');

  // ピクセルフォーマットから1ピクセルの大きさを取得
  // コンパイラの警告を避ける為にとりあえず1を設定しておく
  OnePixelSize := 1;
  case PixelFormat of
    pf8bit: OnePixelSize := 1;
    pf24bit: OnePixelSize := 3;
    pf32bit: OnePixelSize := 4;
  end;

  // プログレスイベントが発生可能かどうかをチェック
  MakeProgressEvent := MakeProgressEvent and Assigned(Src.OnProgress);

  // 開始イベントを発生
  if MakeProgressEvent then
    Src.OnProgress(Src, psStarting, 0, False, ZERO_RECT, MSG);

  Dst := TBitmap.Create;
  try
    // pf8bitの場合、パレットをコピーする必要がある
    if PixelFormat = pf8bit then Dst.Assign(Src);

    // 新しい画像の大きさとピクセルフォーマットを設定する
    Dst.PixelFormat := PixelFormat;
    Dst.Width := NewWidth;
    Dst.Height := NewHeight;

    // スキャンラインの結果をバッファに(この方が速いらしい)
    SetLength(SrcScanLineBuffer, Src.Height);
    for x := 0 to Src.Height - 1 do SrcScanLineBuffer[x] := Src.ScanLine[x];
    SetLength(DstScanLineBuffer, Dst.Height);
    for x := 0 to Dst.Height - 1 do DstScanLineBuffer[x] := Dst.ScanLine[x];

    // ピクセル毎に処理
    for y := 0 to NewHeight - 1 do
    begin
      // コピー先のスキャンラインをバッファから取得
      pDst := DstScanLineBuffer[y];

      for x := 0 to NewWidth - 1 do
      begin
        // コピー元の座標を取得する
        SrcX := Round(x / NewWidth * SrcWidth);
        SrcY := Round(y / NewHeight * SrcHeight);

        // 座標がオーバーしている場合への対応
        if SrcX < 0 then SrcX := 0;
        if SrcY < 0 then SrcY := 0;
        if SrcX >= SrcWidth then SrcX := SrcWidth - 1;
        if SrcY >= SrcHeight then SrcY := SrcHeight - 1;

        // コピー元を取得
        pSrc := SrcScanLineBuffer[SrcY];
        Inc(pSrc, SrcX * OnePixelSize);

        // コピー
        CopyMemory(pDst, pSrc, OnePixelSize);

        // 次のピクセルへ
        Inc(pDst, OnePixelSize);
      end;

      // 一行終わる毎に処理中イベントを発生
      if MakeProgressEvent then
        Src.OnProgress(
          Src, psRunning, y * 100 div NewHeight, False, ZERO_RECT, MSG);
    end;

    // 完了イベントを発生
    if MakeProgressEvent then
      Src.OnProgress(Src, psEnding, 100, False, ZERO_RECT, MSG);

    // ここまで来れば処理は成功
    Result := Dst;
  except
    Dst.Free;
    raise; // 例外を再生成
  end;

2005年07月30日

バブルソート

隣どうしの要素だけ比較し、逆順ならば交換する。これを、交換が不要になるまで繰り返す。いろいろな変形が可能である(Sedgewickの教科書にあるものは一見エレガントだが間違っている)。次のものは最後に交換が起きた場所を覚えておく方式のものである。
バブルソートは多くの本で取り上げられている割にはこれといった長所のないアルゴリズムである。

参考文献(ってか丸写しです。この本廃刊になっちゃってるので)
コンピュータアルゴリズム辞典 技術評論社
著者:奥村晴彦

procedure BubbleSort;
var
  I, J, Hi, Temp: Integer;
begin
  Hi := N
  repeat
    J := 0;
    for I := 2 to Hi do
      if A[I - 1] > A[I] then
      begin
        J := I - 1;
        Temp := A[J];
        A[J] := A[I];
        A[I] := Temp;
      end;
    High := J;
  until J = 0;
end;

'03.10.23

2005年03月21日

Delphiで、ドラッグ&ドロップを受け入れる

WMDropFilesメッセージでエクスプローラからのドラッグ&ドロップを処理できます。
まずフォームの生成時にDragAcceptFiles APIでファイルの受け取りを許可します。ただし、普通にOnCreateにDragAcceptFiles(Handle, True)するよりも、CreateParamsをオーバーライドした方がいいみたいです。理由なんか知りません(笑)。
そしてWMDropFilesの処理の中で、DragQueryFile APIを使ってファイルの受け取りを行います。二番目の引数がドロップされたファイルのインデックスになります。$FFFFFFFFを指定すればドロップされたファイルの総数がわかります。

uses
  ShellApi; // ShellApiをusesするのを忘れずに

type
  TForm1 = class(TForm)
  private
    { Private 宣言 }
    procedure CreateParams(var Params: TCreateParams); override;
    procedure WMDropFiles(var Msg: TWMDROPFILES); message WM_DROPFILES;
  end;

implementation

procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  // ファイルドロップの許可
  Params.ExStyle := Params.EXStyle or WS_EX_ACCEPTFILES;
end;

procedure TForm1.WMDropFiles(var Msg: TWMDropFiles);
var
  FileName: array[0..MAX_PATH] of Char;
  i, Count: Integer;
begin
  // まずファイルがいくつドロップされたか調べて
  Count := DragQueryFile(Msg.Drop, $FFFFFFFF, nil, 0);
  // for文でリストボックスへ追加すると
  for i := 0 to Count - 1 do
  begin
    DragQueryFile(Msg.Drop, i, FileName, SizeOf(FileName));
    ListBox1.Items.Add(FileName);
  end;
  DragFinish(Msg.Drop); // 忘れないように
end;

'03.10.15

広告


この広告は60日以上更新がないブログに表示がされております。

以下のいずれかの方法で非表示にすることが可能です。

・記事の投稿、編集をおこなう
・マイブログの【設定】 > 【広告設定】 より、「60日間更新が無い場合」 の 「広告を表示しない」にチェックを入れて保存する。