Gadgets > ガジェットのカスタマイズ > 手順 1:グラフィカルな外観変更によるガジェットの拡張
 
手順 1:グラフィカルな外観変更によるガジェットの拡張
最初の手順では、既存のガジェットのグラフィカルな外観を変更するために、そのサブクラスを作成する方法を説明します。
この手順では、IlvTreeGadget クラスが拡張されます。その描画を変更して、次の図に示すように、アイテムの子の色を変更できるようにします。
この手順では、次のタスクを実行する方法を紹介します。
*既存ガジェットのサブクラスを作成する
*API を新規ガジェット・クラスへ追加する
*新規ガジェットの描画方法を変更する
*新規ガジェット・クラスのテスト
既存ガジェットのサブクラスを作成する
既存ガジェットの新しいサブクラスの作成は、既存の IlvGraphic クラスのサブクラスの作成に類似しています。IlvGraphic オブジェクトのサブクラスを適切に作成する主要手順をここで紹介します。
サブクラスの宣言
選択したグラフィックのサブクラスとして、サブクラスを宣言します。このチュートリアルでは、IlvTreeGadget は、色付きのアイテムを表示できる新しいオブジェクトを作成するためにサブクラス化されています。このサブクラスは、ColoredTreeGadget と呼ばれます。これは ColoredTreeGadget クラスの宣言です。
class ColoredTreeGadget
: public IlvTreeGadget {
public:
ColoredTreeGadget(IlvDisplay* display,
const IlvRect& rect,
IlvUShort thickness = IlvDefaultGadgetThickness,
IlvPalette* palette = 0);
virtual ~ColoredTreeGadget();
};
この宣言は、ColoredTreeGadget クラスのコンストラクターおよびデストラクターから構成されています。
動的なタイピングおよび永続性を可能にするために ColoredTreeGadget の登録を追加します。
DeclareTypeInfo();
DeclareIOConstructors(ColoredTreeGadget);
DeclareGraphicAccessors();
DeclareGraphicAccessors マクロは、queryValue および applyValue メソッドを宣言して、新しいオブジェクトをスクリプト可能にします。
メソッドの実装
宣言された ColoredTreeGadget メソッドの実装を次に示します。
まず、コンストラクターが次のように実装されます。
ColoredTreeGadget::ColoredTreeGadget(IlvDisplay* display,
const IlvRect& rect,
IlvUShort thickness,
IlvPalette* palette )
: IlvTreeGadget(display, rect, thickness, palette)
{
}
コンストラクターのコピー、DeclareIOContructors マクロによって宣言されています。
ColoredTreeGadget::ColoredTreeGadget(const ColoredTreeGadget& source)
: IlvTreeGadget(source)
{
}
IO コンストラクター、これも DeclareIOConstructors マクロによって宣言されています。
ColoredTreeGadget::ColoredTreeGadget(IlvInputFile& is, IlvPalette* palette)
: IlvTreeGadget(is, palette)
{
}
write メソッド、DeclareTypeInfo マクロによって宣言されています。
void
ColoredTreeGadget::write(IlvOutputFile& os) const
{
IlvTreeGadget::write(os);
}
デストラクター
ColoredTreeGadget::~ColoredTreeGadget()
{
}
アクセサー関連メソッド、DeclareGraphicAccessors マクロによって宣言されています。
IlvValue&
ColoredTreeGadget::queryValue(IlvValue& value) const
{
return IlvTreeGadget::queryValue(value);
}
 
IlvBoolean
ColoredTreeGadget::applyValue(const IlvValue& value)
{
return IlvTreeGadget::applyValue(value);
}
 
void
ColoredTreeGadget::GetAccessors(const IlvSymbol* const** a,
const IlvValueTypeClass* const** t,
IlvUInt& c)
{
}
それから、copy および read メソッドの実装が IlvPredefinedIOMembers マクロによって与えられます。
IlvPredefinedIOMembers(ColoredTreeGadget)
最後に、クラスは IlvTreeGadget クラスのサブクラスとして登録されます。
IlvRegisterClass(ColoredTreeGadget, IlvTreeGadget);
これらのアイテムは、ColoredTreeGadget クラスを適切に登録するために必要です。これらのメソッドの多くは空ですが、次の手順でデータを埋めます。
API を新規ガジェット・クラスへ追加する
ColoredTreeGadget クラスの宣言は、coltree.h ファイルにあり、その実装は coltree.cpp ファイルにあります。
ColoredTreeGadget クラスは、以下を必要とします。
*ツリー・アイテムを特定の色に関連付ける方法。この色は、このアイテムの子の背景を描くのに使用されます。
*ツリー・アイテムの色塗りを有効/無効にする方法。
*アクセサーをこれに追加する。
アイテムを色に関連付ける
ツリー・アイテムを色に関連付けるために、setChildrenBackground メソッドが追加されました。これは、色を保存するためにツリー・アイテムでプロパティー・セットを使用します。
void
ColoredTreeGadget::setChildrenBackground(IlvTreeGadgetItem* item,
IlvColor* color,
IlvBoolean redraw)
{
// Retrieve the old color.
IlvPalette* oldPalette =
(IlvPalette*)item->getProperty(GetChildrenBackgroundSymbol());
// Compute the new color.
IlvPalette* palette = color
? getDisplay()->getPalette(0, color)
: 0;
// Lock it.
if (palette)
palette->lock();
// Unlock the old one.
if (oldPalette)
oldPalette->unLock();
// Set the property to the item.
item->setProperty(GetChildrenBackgroundSymbol(), (IlvAny)palette);
// Redraw if asked.
if (redraw)
reDraw();
}
GetChildrenBackgroundSymbol スタティック・メソッドはアイテム上のプロパティー・セットを識別する記号を返します。その定義は簡単です。
static IlvSymbol*
GetChildrenBackgroundSymbol()
{
// This symbol is used to connect a tree gadget item to the color of its
// children.
static IlvSymbol* symbol = IlvGetSymbol("ChildrenBackground");
return symbol;
}
getChildrenBackground メソッドは、任意のツリー・アイテムに関連付けられている色を返します。
IlvColor*
ColoredTreeGadget::getChildrenBackground(const IlvTreeGadgetItem* item) const
{
// Returns the color stored in the property list of the specified item.
IlvPalette* palette =
(IlvPalette*)item->getProperty(GetChildrenBackgroundSymbol());
return palette
? palette->getForeground()
: 0;
}
色塗りを有効/無効にする
ツリー・アイテムの色塗りを有効/無効にできるようにするコードを実装します。これを行うために、保護されたメンバー変数を ColoredTreeGadget クラスに追加します。
protected:
IlvBoolean _drawChildrenBg;
デフォルトで、このブール型値は IlvTrue へのコンストラクターによって初期化されます。これらは _drawChildrenBg メンバー変数へのアクセスを付加するメンバー関数です。
IlvBoolean isDrawingChildrenBackground() const;
void drawChildrenBackground(IlvBoolean value,
IlvBoolean redraw = IlvTrue);
_drawChildrenBg メンバー変数は保存する必要があるため、IO コンストラクターおよび write メソッドの両方を変更しなくてはなりません。
ColoredTreeGadget::ColoredTreeGadget(IlvInputFile& is, IlvPalette* palette)
: IlvTreeGadget(is, palette),
_drawChildrenBg(IlvTrue)
{
// Read the _drawChildrenBg flag.
int drawChildrenBg;
is.getStream() >> drawChildrenBg;
_drawChildrenBg = (IlvBoolean)drawChildrenBg;
}
 
void
ColoredTreeGadget::write(IlvOutputFile& os) const
{
IlvTreeGadget::write(os);
// Write the _drawChildrenBg flag.
os.getStream() << IlvSpc() << (int)_drawChildrenBg << IlvSpc();
}
アクセサーの追加
オブジェクトにアクセサーを追加すると、これらをスクリプトに利用できるようになります。以下の記述は、_drawChildrenBg メンバー変数へのアクセサーの例を表しています。
まず、この変数にアクセスするために使用される記号を定義します。これは、スタティック関数 GetDrawChildrenBackgroundSymbol によって行われます。
static IlvSymbol*
GetDrawChildrenBackgroundSymbol()
{
// This symbol is used to access to drawChildrenBackground accessor of
// the colored tree gadget.
static IlvSymbol* symbol = IlvGetSymbol("drawChildrenBackground");
return symbol;
}
次に、新しいアクセサーが GetAccessors に登録されます。
void
ColoredTreeGadget::GetAccessors(const IlvSymbol* const** a,
const IlvValueTypeClass* const** t,
IlvUInt& c)
{
DeclareAccessor(GetDrawChildrenBackgroundSymbol(),
IlvValueBooleanType,
a,
t,
c);
}
queryValue メソッドは、アクセサーの値に問い合わせが行われたときに呼び出されます。
IlvValue&
ColoredTreeGadget::queryValue(IlvValue& value) const
{
if (value.getName() == GetDrawChildrenBackgroundSymbol())
return value = isDrawingChildrenBackground();
else
return IlvTreeGadget::queryValue(value);
}
applyValue メソッドは、アクセサーの値が変更されたときに呼び出されます。
IlvBoolean
ColoredTreeGadget::applyValue(const IlvValue& value)
{
if (value.getName() == GetDrawChildrenBackgroundSymbol()) {
drawChildrenBackground((IlvBoolean)value, IlvFalse);
return IlvTrue;
} else
return IlvTreeGadget::applyValue(value);
}
新規ガジェットの描画方法を変更する
次の手順は、ColoredTreeGadget の描画方法を変更することです。グラフィカル・オブジェクトの描画を変更する標準的な方法は、IlvGraphic レベルで定義されているその draw メソッドをオーバーライドすることです。
virtual void draw(IlvPort* dst,
const IlvTransformer* t = 0,
const IlvRegion* clip = 0) const = 0;
ただし、IlvTreeGadget は複雑なオブジェクトで、その描画のカスタマイズに役立つその他のメソッドが複数あります。各アイテムが描画される前に背景を描画するとします。IlvGadgetItemHolder::drawGadgetItem メソッドを使用することができます。これは、各アイテムを描画するためにツリーが呼び出します。
void
ColoredTreeGadget::drawGadgetItem(const IlvGadgetItem* item,
IlvPort* port,
const IlvRect& rect,
const IlvTransformer* t,
const IlvRegion* clip) const
{
if (isDrawingChildrenBackground()) {
// Check if the item being drawn has a special palette.
IlvPalette* palette = getBackgroundPalette((IlvTreeGadgetItem*)item);
if (palette) {
// Compute the visible bounding box.
IlvRect bbox;
visibleBBox(bbox, t);
// Move and resize it to match the item bounding box.
bbox.y(rect.y());
bbox.h(rect.h());
if (clip)
palette->setClip(clip);
port->fillRectangle(palette, bbox);
if (clip)
palette->setClip();
}
}
// Draw the item.
IlvTreeGadget::drawGadgetItem(item, port, rect, t, clip);
}
getBackgroundPalette メソッドは、ツリー・アイテムの背景を描画するために使用されたパレットの取得に使用されます。
IlvPalette*
ColoredTreeGadget::getBackgroundPalette(const IlvTreeGadgetItem* item) const
{
// Returns the palette that will be used to draw the background of ?item?
// This information is stored in its parent
if (item->getParent()) {
IlvPalette* palette = (IlvPalette*)
item->getParent()->getProperty(GetChildrenBackgroundSymbol());
if (!palette)
palette = getBackgroundPalette(item->getParent());
return palette;
} else
return 0;
}
getBackgroundPalette メソッドは、背景パレットとして設定されている「アイテム」の最初の親を見つけようとします。これは、ツリー・アイテムはその色を親から継承することを意味します。アイテムの背景色を変更すると、その子の背景色を変えるだけでなく、その孫などの背景色も変えることになります。
新規ガジェット・クラスのテスト
ファイル main.cppは、ColoredTreeGadget クラスをテストするコードを含んでいます。これは、ColoredTreeGadget インスタンスの記述を含むファイル coltree.ilv を読み込み、レベルに応じて全アイテムの色を変更します。
// Read the file that contains the colored tree.
container->readFile("../doc/gadgets/tutorials/custgad/data/coltree.ilv");
 
// Retrieve the tree.
ColoredTreeGadget* tree = (ColoredTreeGadget*)container->getObject("Tree");
 
// Set the background of the tree to gray.
// This color will be used as the reference color to compute the children
// colors.
tree->setBackground(display->getColor("gray"));
 
// Now change the color of each level of items.
tree->applyToItems(ChangeColor, (IlvAny)tree);
applyToItems メソッドは、ツリーの全アイテムに ChangeColor 関数を適用します。これは、ColoredTreeGadget::setChildrenBackground メソッドを呼び出すこの ChangeColor 関数の記述です。
static IlvBoolean
ChangeColor(IlvGadgetItem* item, IlvAny arg)
{
// The argument is a pointer to the ColoredTreeGadget instance.
ColoredTreeGadget* tree = (ColoredTreeGadget*)arg;
// Change the background of the children of ?item?.
tree->setChildrenBackground((IlvTreeGadgetItem*)item,
GetChildrenColor((IlvTreeGadgetItem*)item,
tree->getBackground()),
IlvFalse);
// Continue.
return IlvTrue;
}
別のスタティック関数を使って、ツリー・アイテムおよび基準色を使用して色を計算します。
static IlvColor*
GetChildrenColor(IlvTreeGadgetItem* item, IlvColor* color)
{
// Get the item level to choose the right color.
IlvUInt level = item->getLevel();
// Compute the HSV components of the reference color.
IlvFloat h, s, v;
color->getHSV(h, s, v);
// Increase the V component.
v = (IlvFloat)IlvMin((IlvFloat)1., (IlvFloat)(v + level*.08));
// Return the new color.
return color->getDisplay()->getColor(h, s, v);
}
この関数は、アイテムのレベルおよび指定された基準色を使用して、新しい色を計算します。この新しい色は HSV モデルの基準色の V コンポーネントを変更して計算されます。
これで手順 1 は完了です。テスト・プログラムは、次のように見えるはずです。

Version 6.0
Copyright © 2015, Rogue Wave Software, Inc. All Rights Reserved.