☆円弧の描画

円弧の描画時に、時計回りなのか、半時計回りなのかを判断して 座標を入れ替えて表示させていましたが、SetArcDirection APIを使うと 処理がすっきりするかも知れませんね。
// SetArcDirectionを使わない処理
if (Enko.m_radEnkoKaku < 0) then
  ACanvas.Arc(P1.X,P1.Y,P2.X,P2.Y,P4.X,P4.Y,P3.X,P3.Y)
else
  ACanvas.Arc(P1.X,P1.Y,P2.X,P2.Y,P3.X,P3.Y,P4.X,P4.Y);


// SetArcDirectionを使った処理
if (Enko.m_radEnkoKaku < 0) then
  SetArcDirection(ACanvas.Handle, AD_CLOCKWISE)          // 時計回り
else
  SetArcDirection(ACanvas.Handle, AD_COUNTERCLOCKWISE);  // 反時計回り

ACanvas.Arc(P1.X,P1.Y,P2.X,P2.Y,P3.X,P3.Y,P4.X,P4.Y)   // 円弧

|

☆グラデーションパネルを作る。

他にも方法があるかも知れませんが、次の3種類について検討してみます。
※色は、clWhiteとclGradientInactiveCaptionを設定しています。

[A] カスタムコンポーネントを作る。
今回、TPanelを拡張したコンポーネントを作ってみました。(最後に、コードを載せています)
一度作ると利用は簡単ですが、いろんなコンポーネントを管理していくのは結構面倒です。

[B] TToolBarの上にTPanelを配置して使う。
左端にラインが表示されますが、とても簡単です。

[C] TPanel+TImage
見た目は問題ないのですが、リサイズ時に少しちらつきます。
リサイズ時の処理だけ書けばよいので、パネルの数が少ない場合には簡単です。
// Image1のグラデーション描画用
uses
  GraphUtil;

procedure TForm1.FormResize(Sender: TObject);
var
  Rect: TRect;
begin
  Image1.Picture := nil;
  Rect := Image1.ClientRect;
  GradientFillCanvas(Image1.Canvas, clWhite, clGradientInactiveCaption,
    Rect, gdVertical);
end;


デザイン時です。

Design



実行するとこんな感じです。

Run



見た目はそう変わらないですね。どれを採用するかはケースバイケースかな? 一度カスタムコンポーネントにしてしまうとそれを使うことが多いんですけど、 きちんと管理していかないと古いバージョンのものを訂正しようとするときに、 ○○コンポーネントがない!って言われて、訂正する気力を失うので、要注意です(笑)

今回作ったグラデーションパネルです。 グラデーションを描くためだけに作っているので、かなり適当です。 というか、TToolBarから必要なものを取ってきてるだけという疑惑もあります(笑)
unit HRGadientPanel;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
  ExtCtrls, GraphUtil, ComCtrls;

type
  THRGadientPanel = class(TPanel)
  private
    FDrawingStyle: TTBDrawingStyle;
    FGradientDirection: TGradientDirection;
    FGradientEndColor: TColor;
    FGradientStartColor: TColor;
    function IsGradientEndColorStored: Boolean;
    procedure SetGradientDirection(Value: TGradientDirection);
    procedure SetGradientEndColor(Value: TColor);
    procedure SetGradientStartColor(Value: TColor);
    procedure SetDrawingStyle(Value: TTBDrawingStyle);
  protected
    procedure Paint; override;
    procedure Resize; override;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property GradientDirection: TGradientDirection read FGradientDirection
      write SetGradientDirection default gdVertical;
    property GradientEndColor: TColor read FGradientEndColor
      write SetGradientEndColor stored IsGradientEndColorStored;
    property GradientStartColor: TColor read FGradientStartColor
      write SetGradientStartColor default clWindow;
    property DrawingStyle: TTBDrawingStyle read FDrawingStyle
      write SetDrawingStyle default dsNormal;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Hiderin', [THRGadientPanel]);
end;

{ THRGadientPanel }

constructor THRGadientPanel.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  GradientStartColor := clWindow;
  GradientEndColor := GetShadowColor(clBtnFace, -25);
  GradientDirection := gdVertical;
end;

procedure THRGadientPanel.Paint;
const
  Alignments: array[TAlignment] of Longint = 
    (DT_LEFT, DT_RIGHT, DT_CENTER);
  VerticalAlignments: array[TVerticalAlignment] of Longint =
    (DT_TOP, DT_BOTTOM, DT_VCENTER);
var
  Rect: TRect;
  Flags: Longint;
begin
  if FDrawingStyle = dsGradient then
  begin
    Rect := GetClientRect;
    GradientFillCanvas(Canvas, FGradientStartColor, FGradientEndColor,
      Rect, GradientDirection);
    with Canvas do
    begin
      Brush.Style := bsClear;
      Font := Self.Font;
      Flags := DT_EXPANDTABS or DT_SINGLELINE or
        VerticalAlignments[VerticalAlignment] or Alignments[Alignment];
      Flags := DrawTextBiDiModeFlags(Flags);
      DrawText(Handle, PChar(Caption), -1, Rect, Flags);
    end;
  end
  else
    inherited;
end;

procedure THRGadientPanel.SetGradientEndColor(Value: TColor);
begin
  if Value <> FGradientEndColor then
  begin
    FGradientEndColor := Value;
    if HandleAllocated then
      Repaint;
  end;
end;

procedure THRGadientPanel.SetGradientStartColor(Value: TColor);
begin
  if Value <> FGradientStartColor then
  begin
    FGradientStartColor := Value;
    if HandleAllocated then
      Repaint;
  end;
end;

function THRGadientPanel.IsGradientEndColorStored: Boolean;
begin
  Result := FGradientEndColor <> GetShadowColor(clBtnFace, -25);
end;

procedure THRGadientPanel.SetGradientDirection(Value: TGradientDirection);
begin
  if FGradientDirection <> Value then
  begin
    FGradientDirection := Value;
    if HandleAllocated then
      Repaint;
  end;
end;

procedure THRGadientPanel.SetDrawingStyle(Value: TTBDrawingStyle);
begin
  if Value <> FDrawingStyle then
  begin
    FDrawingStyle := Value;
    if HandleAllocated then
      Repaint;
  end;
end;

procedure THRGadientPanel.Resize;
begin
  inherited Resize;
   if (FDrawingStyle = dsGradient) and HandleAllocated then
    Repaint;
end;

end.

|

☆画像ファイルの判別

いろいろな画像形式のファイルが格納されているBlobフィールドから画像ファイルを取り出すとき、その形式を判別する必要がありますね。一つの方法として、登録時、別フィールドに拡張子を保存しておき、その情報を元にして取り出すことも可能ですが、下記サイトのヘッダー判別コードを使えば、拡張子に頼ることなく画像形式を決定することができます。


AWare Systems
Determining the file format from the data
http://www.awaresystems.be/techtalks/001_format_from_data.html

|

☆GDI+を使う。

ニュースグループ borland.public.delphi.graphics の中でGDI+を使うサンプルが紹介されていました。 私は、GDI+を全く使ったことがなく、そのサンプルをコンパイルするだけでも結構大変でした。
ということで、とりあえずGDI+を使えるようにするための手順をメモしておきます。

1.次のサイトからHenri Gourvest氏のGDIPLUSというユニットをダウンロードします。

  progdigy.com
  http://www.progdigy.com/
  (ModulesのGDI+をクリックするとダウンロードのページに移動します)


2.ダウンロードしたファイルを解凍して、gdiplus\pasフォルダをライブラリパスに設定します。


以上で、GDI+を使える環境が整ったので、デモをコンパイルしてみます。
(gdiplus\demos\Getting Started\Drawing a String\GDDITEST9.dproj)
ファイルを開いてコンパイルすると
[DCC エラー] DirectDraw.pas(358): E2154 'IDirectDrawSurface' 型は終了処理が必要です
 - 構造体の可変部に置くことは許されません
というエラーが表示されました。

なんとなくDelphiのバージョンによるエラーっぽいと思い、いろいろ調べてみました。
結果として、次のような処理でコンパイルすることができました。

jedi.incファイルで次のコメントを検索します。
// VERXXX to COMPILERX, DELPHIX and BCBX mappings
そして次の処理を挿入します。(Delphi2007をDelphi7と認識させます。)
//------------------------------------------------------------------------------
// VERXXX to COMPILERX, DELPHIX and BCBX mappings
//------------------------------------------------------------------------------

{$IFDEF VER180}
  {$DEFINE COMPILER7}
  {$IFDEF BCB}
    {$DEFINE BCB7}
    {$DEFINE BCB}
  {$ELSE}
    {$DEFINE DELPHI7}
    {$DEFINE DELPHI}
  {$ENDIF}
{$ENDIF}


これで、無事コンパイルすることができました。


[参考にしたサイト]

MemoNyanDum
http://junki.lix.jp/
Delphiを使った画像処理では知らない人はいないかも知れませんが、今回お世話になったサイトです。 デザインもとっても素敵です。

progdigy.com
http://www.progdigy.com/

About.com Delphi Programming
Delphi Compiler Version Directives

|

■ブログの配色を変えました。

ブログの配色を少し変えました。CSSも手探りで変更するのは面倒ですね。
色を選ぶときに RGBをWeb用の表記に変換するプログラムを書いて作業をしましたので、 そのコードを書いておきますね。
// R=255,G=255,B=255 を #FFFFFF のように変換します。
procedure TForm1.Button1Click(Sender: TObject);
var
  r,g,b: Integer;
begin
  r := StrToInt(Edit1.Text);
  g := StrToInt(Edit2.Text);
  b := StrToInt(Edit3.Text);
  Edit4.Text := Format('#%.2x%.2x%.2x', [r, g, b]);
end;

|

☆グラデーションの描画

GraphUtilユニットの中に縦、横の2種類ですが、グラデーションを描画する手続きを見つけました。

type
  TGradientDirection = (gdHorizontal, gdVertical);

procedure GradientFillCanvas(const ACanvas: TCanvas;
  const AStartColor, AEndColor: TColor; const ARect: TRect;
  const Direction: TGradientDirection);

これを利用すると、ツーバー以外でも自分でバックをグラデーションする?ことができます。

uses
  GraphUtil;

procedure MyDraw(Image: TImage);
var
  Rect: TRect;
begin
  Rect := Image.ClientRect;
  GradientFillCanvas(Image.Canvas,clWhite,clGradientInactiveCaption,Rect,gdVertical);
  SetBkMode(Image.Canvas.Handle, TRANSPARENT);
  Image.Canvas.Font.Color := clBlue;
  Image.Canvas.Font.Style :=[fsBold];
  Image.Canvas.Textout(Rect.Left, Rect.Top, 'グラデーション');
end;

|