TurboC++では、VCLを利用することで比較的簡単にグラフィックの描画を行うことができます。
しかしながら、右の画像のように半透明処理やアンチエイリアシングなどの
高度なグラフィック処理を実現するためには、必要な処理を自分で用意する必要がありました。
GDI+はベクタベースのクラスライブラリで、
あまり高速なグラフィック処理を行うことはできませんが、
このような処理を簡単に実現することができます。
また、GDI+はDLLとして用意されているため、アプリケーションとリンクさせる必要があるほか、
開始・終了処理を行う必要があります。以下にGDI+をTurboC++で利用するために必要な処理を示していきます。
なお、WindowsXP以降ではGDI+がDLLとしてOSに組み込まれているため、 特にアプリケーションを実行するために必要なものはありませんが、 Windows2000以前のOSではgdiplus.dllをMicrosoftのホームページからダウンロードして、 アプリケーションと同じディレクトリにおいておく必要があります。
TurboC++で新規VCLプロジェクトを作成すると、<プロジェクト名>.cppという ファイルが作成されているはずです。そこで、gdiplus.libをリンクします。
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
//---------------------------------------------------------------------------
USEFORM("Unit1.cpp", Form1);
//---------------------------------------------------------------------------
//gdiplus.libをリンク
#pragma link "gdiplus.lib"
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
Application->Initialize();
Application->CreateForm(__classid(TForm1), &Form1);
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
catch (...)
{
try
{
throw Exception("");
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
}
return 0;
}
//---------------------------------------------------------------------------
GDI+の使用前、使用後には、それぞれ初期化処理と終了処理を行う必要があります。 また、すべてのGDI+オブジェクトは初期化処理と終了処理の間で使用しなければなりません。 今回はメインフォームのコンストラクタで初期化処理を、 デストラクタで終了処理を行っています。
GDI+を初期化するために必要なgdiplusTokenおよび、 gdiplusStartupInputを用意します。 以下の例では、メインフォームのメンバ変数として用意していますが、 グローバル変数として宣言してもよいです。
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE 管理のコンポーネント
void __fastcall FormPaint(TObject *Sender);
private: // ユーザー宣言
//GDI+の初期化に必要なオブジェクト
ULONG_PTR gdiplusToken;
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
public: // ユーザー宣言
//コンストラクタとデストラクタ
__fastcall TForm1(TComponent* Owner);
__fastcall ~TForm1();
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
GDI+の初期化処理と終了処理を以下に示します。 いずれも1行程度の簡単な処理です。
//コンストラクタ
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
//GDIPLUSの初期化
Gdiplus::GdiplusStartup( &gdiplusToken, &gdiplusStartupInput, NULL );
}
//---------------------------------------------------------------------------
//デストラクタ
__fastcall TForm1::~TForm1()
{
//GDIPLUSの開放
Gdiplus::GdiplusShutdown( gdiplusToken );
}
//---------------------------------------------------------------------------
GDI+を使うための準備が整ったので、あとは描画処理を記述するだけです。 以下にサンプルプログラムを置いておきます。 実行するとおよそ右の画像のような結果が得られるはずです。
ソースファイルの先頭で、GDI+を使用するためにgdiplus.hをインクルードします。 また、ハンドルの識別を行うためにSTRICTを定義しておきます。
//---------------------------------------------------------------------------
#define STRICT
#include <vcl.h>
#pragma hdrstop
#include <gdiplus.h>
#include "Unit1.h"
//---------------------------------------------------------------------------
あとは、任意にGDI+を使用して描画処理を行います。 今回は、フォームのOnPaintイベントで描画処理を行いました。 GDI+の描画処理は、すべてGdiplus::Graphicsオブジェクトを介して行われます。 また、Graphicsオブジェクトはデバイスコンテキストを引数に生成されます。
//描画リクエスト
void __fastcall TForm1::FormPaint(TObject *Sender)
{
//変換行列の生成
Gdiplus::Matrix mx;
mx.RotateAt(30, Gdiplus::PointF(50, 50), Gdiplus::MatrixOrderAppend);
//キャンバスを作って、塗りつぶします
Gdiplus::Graphics g(Canvas->Handle);
g.SetTransform(&mx);
g.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality);
g.Clear(Gdiplus::Color(255, 255, 255));
//指定のペンで線を描画します
Gdiplus::Pen pen(Gdiplus::Color(100, 100, 255), 2.0f);
g.DrawLine(&pen, 100, 0, 100, 300);
pen.SetColor(Gdiplus::Color(100, 255, 100, 100));
pen.SetWidth(8.0f);
g.DrawLine(&pen, 30, 30, 300, 30);
//指定のブラシで楕円を描画します
Gdiplus::SolidBrush brush(Gdiplus::Color(120, 100, 255, 100));
g.FillEllipse(&brush, 50, 0, 150, 100);
}
//---------------------------------------------------------------------------