[delphi/2006/November]

リストボックスの全選択・全解除 / 2006-11-23 (木)

 ほとんど俺様メモなんですが….

方法

 リストボックスにLB_SETSELメッセージを送る

全選択

SendMessage(ListBox1.Handle, LB_SETSEL, ord(True), -1);

全解除

SendMessage(ListBox1.Handle, LB_SETSEL, ord(False), -1);

利点

 Selectedプロパティを使って1項目ずつ選択する方法に比べて…

現在位置が変わらない
Selectedを使う場合選択した場所に選択位置が動く(場合によってはスクロールする)
速い
選択位置が動くと再描画が増えて処理時間がよけいにかかりますが.特に項目数が何百何千とある時に差が顕著.
コードが短い
説明不要

[delphi]

Delphi:ボーダーのないフォームを最大化して起動する場合の注意点 / 2005-08-05 (金)

問題点

フォームのBorderStyleがbsNoneのとき,設計時にWindowsStateをwsMaximizedすると 実行時に最大化を解除してもWidthとHeightで指定したサイズにならない.

対策

設計時はフォームを最大化せず,実行中最初にフォームを表すときに最大化するとこの問題を回避できます.

type
  TForm1 = class(TForm)
    (※中略)
  private
    FFormInitialized: boolean;
    (※中略)
  end;

procedure TForm1.FormShow(Sender: TObject);
begin
  if not FFormInitialized then
  begin
    WindowsState := wsMaximized;
    FFormInitialized := True;
  end;
end;
ただしこの場合,Positionの値はpoDesignedとなり,最大化を解除すると,
  1. PositionがpoDefault,poDefaultPosOnlyの場合はフォームの左上座標画面の左上に来てしまう.
    このため,タスクバーなどのアプリケーションバーが画面の上又は左に存在するとフォームの一部又は全部が隠れてしまう
  2. それ以外の場合は常に設計時にLeft, Topで指定した座標に表示される.
    poScreenCenter等の指定は無視されてしまう.

この対策は自分で表示位置を修正するしかないようです.

アプリケーションバーと重なっているかどうかを調べる方法

アプリケーションバーについてひとつひとつ調べる必要はありません.SystemParametersInfo APIでアプリケーションバーを除いた領域(ここでは作業領域と呼びます)を簡単に取得できるからです.現在のフォーム領域がこの領域をはみ出ているかどうかを調べれば判定できます.

重なっている場合に重ならないように移動する方法

単純に左にはみ出ていればその分右に移動,上にはみ出ていればその分下に移動.右と下も同様です.ただし左右又は上下ともにはみ出ている場合,つまりフォームの幅や高さが作業領域の幅や高さより大きい場合は幅や高さを縮めるか片方だけ適用します.以下にコードを晒します(※このコードでは幅や高さの縮小はしていません).

コード

※宣言部

function CenterRectOfRect(const aRect, MotherRect: TRect): TRect; 
function DesktopWorkRect: TRect; 
function WidthOfRect(const aRect: TRect): integer; 
function HeightOfRect(const aRect: TRect): integer; 
procedure MoveFormToPosition(Form: TCustomForm; Position: TPosition = poDesigned); 

※実装部

{★指定された領域と同じサイズで別の領域の中央になる領域を返します.}
function CenterRectOfRect(const aRect, MotherRect: TRect): TRect;
begin
  Result.Left := MotherRect.Left + (WidthOfRect(MotherRect) - WidthOfRect(aRect)) div 2;
  Result.Right := aRect.Right + (Result.Left - aRect.Left);
  Result.Top := MotherRect.Top + (HeightOfRect(MotherRect) - HeightOfRect(aRect)) div 2;
  Result.Bottom := aRect.Bottom + (Result.Top - aRect.Top);
end;

{★アプリケーションバーを除いた領域を返す
 (※マルチモニターの場合はプライマリモニターの領域を返します)}
function DesktopWorkRect: TRect;
begin
  Windows.SystemParametersInfo(SPI_GETWORKAREA, 0, @Result, 0)
end;

{★領域の幅を返す.}
function WidthOfRect(const aRect: TRect): integer;
begin
  Result := abs(aRect.Right - aRect.Left);
end;

{★領域の高さを返す.}
function HeightOfRect(const aRect: TRect): integer;
begin
  Result := abs(aRect.Bottom - aRect.Top);
end;

{★フォームの位置をPositionで指定した場所に移動します.}
procedure MoveFormToPosition(Form: TCustomForm; Position: TPosition);
var
  aDesktopWorkRect, aBoundsRect: TRect;
  NeedToMoveOffsetX, NeedToMoveOffsetY: integer;
begin
  aDesktopWorkRect := DesktopWorkRect;
  aBoundsRect := Form.BoundsRect;

  case Position of
  poDefault, poDefaultPosOnly:
    begin
      { クライアント領域からはみ出しているなら収まるように移動します.}
      if aBoundsRect.Left < aDesktopWorkRect.Left then
        NeedToMoveOffsetX := aDesktopWorkRect.Left - aBoundsRect.Left
      else if aBoundsRect.Right > aDesktopWorkRect.Right then
        NeedToMoveOffsetX := aDesktopWorkRect.Right - aBoundsRect.Right
      else
        NeedToMoveOffsetX := 0;

      if aBoundsRect.Top < aDesktopWorkRect.Top then
        NeedToMoveOffsetY := aDesktopWorkRect.Top - aBoundsRect.Top
      else if aBoundsRect.Bottom > aDesktopWorkRect.Bottom then
        NeedToMoveOffsetY := aDesktopWorkRect.Bottom - aBoundsRect.Bottom
      else
        NeedToMoveOffsetY := 0;

      if (NeedToMoveOffsetX <> 0) or (NeedToMoveOffsetY <> 0) then
      begin
        Windows.OffsetRect(aBoundsRect, NeedToMoveOffsetX , NeedToMoveOffsetY);
        Form.BoundsRect := aBoundsRect;
      end;
    end;
  poScreenCenter:
    Form.BoundsRect := CenterRectOfRect(aBoundsRect, Bounds(0, 0, Screen.Width, Screen.Height));
  poDesktopCenter:
    Form.BoundsRect := CenterRectOfRect(aBoundsRect, DesktopWorkRect);
  poMainFormCenter:
    if Form <> Application.MainForm then
      Form.BoundsRect := CenterRectOfRect(aBoundsRect, Application.MainForm.BoundsRect)
    else
      MoveFormToPosition(Form, poScreenCenter);
  poOwnerFormCenter:
    if Form.Owner is TCustomForm then
      Form.BoundsRect := CenterRectOfRect(aBoundsRect, (Form.Owner as TCustomForm).BoundsRect)
    else
      MoveFormToPosition(Form, poMainFormCenter);
  end;
end;

使い方の例

procedure TForm1.FormShow(Sender: TObject);
begin
  MoveFormToPosition(Form, poDefaultPosOnly);
end;

[delphi]

Delphi 5のCPU使用率が100%になる謎 / 2005-03-18 (金)

 どうしようもなく「おまえの日記はチラシの裏にでも書いておけ!」ネタですが.

 最近,職場のDelphi 5での開発中に統合環境での日本語変換が固まる(金縛りにあったように重くなる)ことが増えてきました.CPUはAthlon64 3000+(*1)なので重くて固まると言うことは考えにくく,ソフトの問題なのは間違いない.

(*1)動作クロックは2GHz.Pentium 4の3GHzより速いらしい.ちなみに自宅はセレロン600MHz

 タスクマネージャを見るとCPU使用率が100%に!,ATOKの不具合かと思いつつ調べてみたらDelphi 5の統合環境がCPUを使いまくっていました.しかもメモリの使用量が300MBを超えていて,さらにぐんぐん増えている!!

 いろいろ調べていてわかったのは,プロジェクトファイルに存在しないユニットファイルがある場合にこの現象が起こるらしいことです.存在しないユニットファイルはプロジェクトに追加することはできませんが,プロジェクトにユニットを追加してからそのユニットを削除したり,名前を変えたり,他のディレクトリに移動した場合に発生するのでしょう.