- ResourceSave関数の働き・役割
- ResourceSave関数の引数について
- ResourceSave関数の戻り値について
- ResourceSave関数を使う際の注意点
- ResourceSave関数を使ったサンプルコード
- サンプルコード解説1:グローバル領域部分
- サンプルコード解説2:OnStart関数部分その1
- サンプルコード解説3:OnStart関数部分その2
- サンプルコード解説4:OnStart関数部分その3
- サンプルコード解説5:OnStart関数部分その4
- サンプルコード解説6:OnStart関数部分その5
- サンプルコード解説7:OnStart関数部分その6
- サンプルコード解説8:OnStart関数部分その7
- サンプルコード解説9:Update関数(オリジナル関数)
- サンプルコード解説10:LineVertical関数その1(オリジナル関数)
- サンプルコード解説11:LineVertical関数その2(オリジナル関数)
- サンプルコード解説12:LineHorizontal関数その1(オリジナル関数)
- サンプルコード解説13:LineHorizontal関数その2(オリジナル関数)
ResourceSave関数の働き・役割
ResourceSave関数は、指定されたリソースをファイルに保存するために使用されます。リソースとは、例えばグラフィックデータやビットマップ画像のようなデータを指し、この関数を使用することで、これらのリソースを保存して後で再利用したり、他のアプリケーションで使用できるファイルとして保存することが可能です。
リソースの保存は、特定の名前を持つファイルとして、MQL5のデフォルトフォルダである MQL5\Files 内に相対パス(指定されたフォルダからの位置を示すパス)で行われます。この保存は上書き形式で行われ、必要な場合には中間ディレクトリ(途中に作成されるフォルダ)も自動的に作成されます。
ResourceSave関数の引数について
bool ResourceSave(
const string resource_name // リソース名
const string file_name // ファイル名
);
ResourceSave関数は、2つの引数を取ります。
第1引数: resource_name
- 種類: 文字列型(string)
- 説明: 保存するリソースの名前を指定します。リソース名は必ず「::」から始まる形式で指定する必要があります。例えば、グラフィックリソース名が “MyResource” の場合、”::MyResource” という形式で指定します。
第2引数: file_name
- 種類: 文字列型(string)
- 説明: 保存するファイルの名前を指定します。このファイル名は、MQL5\Files フォルダからの相対パス(指定されたフォルダからの位置を示すパス)で指定します。ファイル名を指定する際には、必要な中間ディレクトリ(途中に作成されるフォルダ)も自動的に作成されます。例えば、”MyFolder\image.bmp” という形式で指定すると、MQL5\Files\MyFolder フォルダに image.bmp ファイルが保存されます。
ResourceSave関数の戻り値について
ResourceSave関数の戻り値は、ブール型です。この関数は、処理が成功した場合に true を返し、失敗した場合は false を返します。
処理が失敗した場合には、GetLastError関数を使用してエラーの詳細情報を取得することが可能です。例えば、ファイルの保存先パスが不正であったり、ディスクの書き込みに失敗した場合など、さまざまなエラーが考えられます。
ResourceSave関数を使う際の注意点
ResourceSave関数を使用する際は、ファイルが既に存在する場合、必ず上書きされるため、データの損失に注意する必要があります。
ファイルの保存先パスは相対パスで指定しますが、パスの誤りやディスクの書き込み権限がない場合、ファイルの保存に失敗します。中間ディレクトリは必要に応じて自動的に作成されますが、パスの誤りがあるとエラーとなります。
リソース名は「::」で始める必要があります。この形式に従わないと、正しくリソースを保存できません。
関数の実行が失敗した場合には、GetLastError関数を用いてエラーコードを確認し、原因を特定することが重要です。
ResourceSave関数を使ったサンプルコード
//--- グラフィックリソースパラメータの設定
string ExtResName = "Resource"; // リソース名
int ExtResWidth = 100; // リソースの幅(ピクセル)
int ExtResHeight = 100; // リソースの高さ(ピクセル)
uint ExtResData[]; // ピクセルデータを格納する配列
int ExtResSize = ExtResWidth * ExtResHeight; // ピクセル配列の総サイズ
//+------------------------------------------------------------------+
//| スクリプトプログラム開始関数 |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 最後のエラーをリセットする
ResetLastError();
//--- ピクセル配列のサイズをリサイズする
if (ArrayResize(ExtResData, ExtResSize) != ExtResSize)
{
Print("ArrayResize() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
return; // エラーが発生したため、処理を終了する
}
//--- ピクセル配列を透明色で初期化し、グラフィックリソースを作成する
ArrayInitialize(ExtResData, 0x00FFFFFF); // 透明色(白に透明度)でピクセルを初期化
if (!ResourceCreate(ExtResName, ExtResData, ExtResWidth, ExtResHeight, 0, 0, 0, COLOR_FORMAT_ARGB_NORMALIZE))
{
Print("ResourceCreate() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
return; // エラーが発生したため、処理を終了する
}
Print("Size of created resource array: ", ExtResData.Size()); // 作成されたリソースのサイズを出力
//--- 現在のティックデータ(価格と時間)を取得する
MqlTick tick = {}; // MqlTick構造体でティックデータを格納
if (!SymbolInfoTick(Symbol(), tick))
{
Print("SymbolInfoTick() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
return; // エラーが発生したため、処理を終了する
}
//--- ティックデータに基づいてビットマップオブジェクトを作成する
string obj_name = "Bitmap"; // ビットマップオブジェクトの名前
if (!ObjectCreate(0, obj_name, OBJ_BITMAP, 0, tick.time, tick.bid))
{
Print("ObjectCreate() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
return; // エラーが発生したため、処理を終了する
}
//--- ビットマップオブジェクトのサイズとアンカーポイントを設定する
ObjectSetInteger(0, obj_name, OBJPROP_XSIZE, ExtResWidth); // 幅を設定
ObjectSetInteger(0, obj_name, OBJPROP_YSIZE, ExtResHeight); // 高さを設定
ObjectSetInteger(0, obj_name, OBJPROP_ANCHOR, ANCHOR_CENTER); // 中心をアンカーポイントに設定
//--- グラフィックリソースをビットマップオブジェクトに関連付ける
ObjectSetString(0, obj_name, OBJPROP_BMPFILE, "::" + ExtResName); // 「::」を付けてリソース名を指定
//--- ビットマップの色をGreenYellowに設定し、透明度200で表示
uint clr = ColorToARGB(clrGreenYellow, 200); // ARGB形式で色を指定(透明度200)
ArrayInitialize(ExtResData, clr); // ピクセル配列全体を指定された色で初期化
//--- DodgerBlue色を使用してグリッドを描画する
for (int x = 0; x < ExtResWidth; x += 9)
LineVertical(x, 0, ExtResHeight, ColorToARGB(clrDodgerBlue, 200)); // 垂直線を描画
for (int y = 0; y < ExtResHeight; y += 9)
LineHorizontal(0, ExtResWidth, y, ColorToARGB(clrDodgerBlue, 200)); // 水平線を描画
//--- グラフィックリソースデータを更新する
Update(ExtResName, ExtResData, ExtResWidth, ExtResHeight, true);
//--- リソースとオブジェクトを削除する前に3秒待機
Print("Wait 3 seconds before deleting the resource and graphic object");
Sleep(3000); // 3秒待機
//--- リソースをファイルに保存する
ResetLastError(); // エラーリセット
if (!ResourceSave("::" + ExtResName, "ResourceSave\\" + ExtResName + ".bmp"))
{
Print("ResourceSave() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
return; // エラーが発生したため、処理を終了する
}
//--- リソースとグラフィックオブジェクトを削除する
if (!ResourceFree("::" + ExtResName))
{
Print("ResourceFree() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
return; // エラーが発生したため、処理を終了する
}
if (!ObjectDelete(0, obj_name))
{
Print("ObjectDelete() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
return; // エラーが発生したため、処理を終了する
}
//--- 最後のティック価格と時刻に基づいて新しいグラフィックラベルオブジェクトを作成する
int x = 0, y = 0;
if (!ChartTimePriceToXY(0, 0, tick.time, tick.bid, x, y))
{
Print("ChartTimePriceToXY() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
return; // エラーが発生したため、処理を終了する
}
obj_name = "BitmapLabel"; // 新しいグラフィックラベルオブジェクト名
if (!ObjectCreate(0, obj_name, OBJ_BITMAP_LABEL, 0, 0, 0))
{
Print("ObjectCreate() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
return; // エラーが発生したため、処理を終了する
}
//--- ラベルオブジェクトのアンカーポイントを中心に設定
ObjectSetInteger(0, obj_name, OBJPROP_ANCHOR, ANCHOR_CENTER);
//--- 座標を調整して、画像の幅だけ左にシフトして設定
ObjectSetInteger(0, obj_name, OBJPROP_XDISTANCE, x - ExtResWidth);
ObjectSetInteger(0, obj_name, OBJPROP_YDISTANCE, y);
//--- 先に保存したbmp画像ファイルをリソースとして指定
ObjectSetString(0, obj_name, OBJPROP_BMPFILE, "\\Files\\ResourceSave\\" + ExtResName + ".bmp");
//--- チャートを更新
ChartRedraw();
//--- グラフィックラベルオブジェクトを削除する前に3秒待機
Print("Wait 3 seconds before deleting the new graphic object");
Sleep(3000); // 3秒待機
if (!ObjectDelete(0, obj_name))
Print("ObjectDelete() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
}
//+------------------------------------------------------------------+
//| グラフィックリソースデータを更新する関数 |
//+------------------------------------------------------------------+
void Update(const string res_name, const uint &pixel_data[], const uint width, const uint height, const bool redraw)
{
//--- ゼロ次元が渡された場合は終了する
if (width == 0 || height == 0)
return;
//--- リソースデータを更新し、必要ならチャートを再描画する
if (ResourceCreate(res_name, pixel_data, width, height, 0, 0, 0, COLOR_FORMAT_ARGB_NORMALIZE) && redraw)
ChartRedraw();
}
//+------------------------------------------------------------------+
//| 垂直線を描画する関数 |
//+------------------------------------------------------------------+
void LineVertical(int x, int y1, int y2, const uint clr)
{
int tmp;
//--- y座標を並べ替える
if (y1 > y2)
{
tmp = y1;
y1 = y2;
y2 = tmp;
}
//--- 画像の境界外の場合は描画しない
if (y2 < 0 || y1 >= ExtResHeight || x < 0 || x >= ExtResWidth)
return;
//--- 画像内に収まるように調整する
if (y1 < 0)
y1 = 0;
if (y2 >= ExtResHeight)
y2 = ExtResHeight - 1;
//--- 垂直線を描画
int index = y1 * ExtResWidth + x;
for (int i = y1; i <= y2; i++, index += ExtResWidth)
ExtResData[index] = clr;
}
//+------------------------------------------------------------------+
//| 水平線を描画する関数 |
//+------------------------------------------------------------------+
void LineHorizontal(int x1, int x2, int y, const uint clr)
{
int tmp;
//--- x座標を並べ替える
if (x1 > x2)
{
tmp = x1;
x1 = x2;
x2 = tmp;
}
//--- 画像の境界外の場合は描画しない
if (x2 < 0 || x1 >= ExtResWidth || y < 0 || y >= ExtResHeight)
return;
//--- 画像内に収まるように調整する
if (x1 < 0)
x1 = 0;
if (x2 >= ExtResWidth)
x2 = ExtResWidth - 1;
//--- 水平線を描画
ArrayFill(ExtResData, y * ExtResWidth + x1, (x2 - x1) + 1, clr);
}
サンプルコード解説1:グローバル領域部分
//--- グラフィックリソースパラメータの設定
string ExtResName = "Resource"; // リソース名
int ExtResWidth = 100; // リソースの幅(ピクセル)
int ExtResHeight = 100; // リソースの高さ(ピクセル)
uint ExtResData[]; // ピクセルデータを格納する配列
int ExtResSize = ExtResWidth * ExtResHeight; // ピクセル配列の総サイズ
このコードでは、グローバル領域においてグラフィックリソースを扱うためのパラメータが定義されています。グローバル領域とは、スクリプト全体からアクセス可能な変数やデータを定義する場所で、これらの変数はスクリプト全体のさまざまな関数で使用されます。
ExtResName
ExtResName は、作成されるリソースの名前を表す文字列型の変数です。このリソースは後にビットマップオブジェクトなどで使用され、ファイルに保存される際の識別子となります。ここでは、リソース名として “Resource” が指定されています。
ExtResWidth と ExtResHeight
ExtResWidth と ExtResHeight は、それぞれリソースの幅と高さをピクセル単位で指定するための変数です。グラフィックリソースを画像として扱う場合、その画像のサイズを決定する重要な要素です。この例では、幅も高さも 100 ピクセルに設定されています。
ExtResData
ExtResData は、ピクセルデータを格納するための配列です。この配列はリソースのピクセルごとの色データを保持し、各ピクセルの色情報を扱います。後にリソースを描画したり保存したりする際に、この配列内のデータが使用されます。
ExtResSize
ExtResSize は、リソースの総ピクセル数を計算した値です。これは、幅と高さの積により計算され、ピクセル配列ExtResData のサイズと一致します。このサイズを元にして、ピクセルデータを効率的に処理することが可能となります。
サンプルコード解説2:OnStart関数部分その1
//+------------------------------------------------------------------+
//| スクリプトプログラム開始関数 |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 最後のエラーをリセットする
ResetLastError();
//--- ピクセル配列のサイズをリサイズする
if (ArrayResize(ExtResData, ExtResSize) != ExtResSize)
{
Print("ArrayResize() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
return; // エラーが発生したため、処理を終了する
}
//--- ピクセル配列を透明色で初期化し、グラフィックリソースを作成する
ArrayInitialize(ExtResData, 0x00FFFFFF); // 透明色(白に透明度)でピクセルを初期化
if (!ResourceCreate(ExtResName, ExtResData, ExtResWidth, ExtResHeight, 0, 0, 0, COLOR_FORMAT_ARGB_NORMALIZE))
{
Print("ResourceCreate() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
return; // エラーが発生したため、処理を終了する
}
Print("Size of created resource array: ", ExtResData.Size()); // 作成されたリソースのサイズを出力
この部分では、スクリプトのエントリーポイントである OnStart関数が定義されています。OnStart関数は、スクリプトの実行が開始されると自動的に呼び出され、ここでグラフィックリソースを初期化し、作成する処理が行われます。
ResetLastError関数の呼び出し
関数の最初で ResetLastError関数が呼ばれています。これは、以前に発生したエラー情報をリセットするための処理です。これにより、後で発生したエラーが正しく取得できるように準備しています。
ArrayResize関数によるピクセル配列のリサイズ
次に、ArrayResize関数を使用して、ピクセルデータを格納する配列のサイズを設定しています。ここで、リソースの幅と高さに基づいた総ピクセル数に合わせて配列をリサイズします。この処理が失敗した場合は、エラーがエキスパートログに出力され、スクリプトの実行が終了します。
ArrayInitialize関数によるピクセル配列の初期化
ピクセル配列のサイズが正しく設定された後、ArrayInitialize関数を使って、配列全体を透明色で初期化します。ここでは 0x00FFFFFF という色コードが指定されており、白色に透明度が設定された色となっています。
ResourceCreate関数によるグラフィックリソースの作成
初期化されたピクセル配列を基に、ResourceCreate関数を使用してグラフィックリソースを作成します。この関数は、リソースの名前、ピクセルデータ、リソースの幅、高さなどを引数に取り、正常にリソースが作成されれば次の処理へ進みます。失敗した場合は、エラー情報がエキスパートログに出力され、スクリプトの実行が終了します。
リソースのサイズを出力
最後に、作成されたリソースのピクセル配列のサイズをログに出力しています。これはデバッグ目的で、リソースが期待通りに作成されたか確認するために使用されます。
サンプルコード解説3:OnStart関数部分その2
//--- 現在のティックデータ(価格と時間)を取得する
MqlTick tick = {}; // MqlTick構造体でティックデータを格納
if (!SymbolInfoTick(Symbol(), tick))
{
Print("SymbolInfoTick() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
return; // エラーが発生したため、処理を終了する
}
//--- ティックデータに基づいてビットマップオブジェクトを作成する
string obj_name = "Bitmap"; // ビットマップオブジェクトの名前
if (!ObjectCreate(0, obj_name, OBJ_BITMAP, 0, tick.time, tick.bid))
{
Print("ObjectCreate() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
return; // エラーが発生したため、処理を終了する
}
この部分では、ティックデータを取得し、それを基にビットマップオブジェクトを作成する処理が行われています。ティックデータとは、シンボル(通貨ペアや株式など)の最新の価格情報を示すデータです。
SymbolInfoTick関数によるティックデータの取得
まず、MqlTick構造体を使用してティックデータを格納するための変数tick
が定義されています。MqlTick構造体は、シンボルの価格や時間などの情報を持つデータ型です。
次に、SymbolInfoTick関数を使って、現在のシンボルの最新ティックデータを取得します。この関数は、シンボル名(ここではSymbol関数で取得)と MqlTick構造体を引数として取り、ティックデータを構造体に格納します。関数が失敗した場合は、エラーコードがエキスパートログに出力され、スクリプトの実行が終了します。
ObjectCreate関数によるビットマップオブジェクトの作成
取得したティックデータに基づいて、ObjectCreate関数を使用してビットマップオブジェクトを作成します。オブジェクト名として obj_name という文字列が定義されており、ここでは “Bitmap” という名前を付けています。
ObjectCreate関数は、チャート上にオブジェクトを作成するための関数で、引数としてチャートID(ここでは0)、オブジェクト名、オブジェクトタイプ(OBJ_BITMAP)、時間、価格を指定します。時間と価格には、取得したティックデータの時刻と価格(tick.time と tick.bid)が使用されています。
この関数が失敗した場合も、エラーコードがエキスパートログに出力され、スクリプトの実行が終了します。
これにより、ティックデータに基づいてビットマップオブジェクトが作成され、後続の処理でこのオブジェクトを操作していきます。
サンプルコード解説4:OnStart関数部分その3
//--- ビットマップオブジェクトのサイズとアンカーポイントを設定する
ObjectSetInteger(0, obj_name, OBJPROP_XSIZE, ExtResWidth); // 幅を設定
ObjectSetInteger(0, obj_name, OBJPROP_YSIZE, ExtResHeight); // 高さを設定
ObjectSetInteger(0, obj_name, OBJPROP_ANCHOR, ANCHOR_CENTER); // 中心をアンカーポイントに設定
//--- グラフィックリソースをビットマップオブジェクトに関連付ける
ObjectSetString(0, obj_name, OBJPROP_BMPFILE, "::" + ExtResName); // 「::」を付けてリソース名を指定
//--- ビットマップの色をGreenYellowに設定し、透明度200で表示
uint clr = ColorToARGB(clrGreenYellow, 200); // ARGB形式で色を指定(透明度200)
ArrayInitialize(ExtResData, clr); // ピクセル配列全体を指定された色で初期化
この部分では、ビットマップオブジェクトのサイズとアンカーポイントの設定、グラフィックリソースの関連付け、およびビットマップの色設定に関する処理が行われています。
ObjectSetInteger関数によるビットマップオブジェクトの設定
まず、ObjectSetInteger関数を使って、ビットマップオブジェクトのサイズ(幅と高さ)およびアンカーポイントを設定しています。各引数に以下の内容が指定されています。
- 第1引数にはチャートID(0)が指定されています。これは、現在のチャートを対象にすることを意味します。
- 第2引数にはオブジェクト名(ここでは obj_name)を指定しています。
- 第3引数には設定するプロパティが指定され、OBJPROP_XSIZEで幅、OBJPROP_YSIZEで高さを指定しています。
- 幅と高さは、それぞれリソースの幅(ExtResWidth)と高さ(ExtResHeight)に設定されています。
- OBJPROP_ANCHORプロパティを ANCHOR_CENTER に設定することで、ビットマップオブジェクトのアンカーポイントが中央に設定されます。アンカーポイントは、オブジェクトの基準位置をどこにするかを示す設定です。
ObjectSetString関数によるグラフィックリソースの関連付け
次に、ObjectSetString関数を使って、ビットマップオブジェクトにグラフィックリソースを関連付けています。プロパティ OBJPROP_BMPFILE を使用し、グラフィックリソース名を指定しています。リソース名の前には「::」を付ける必要があるため、指定されたリソース名 ExtResName に「::」を追加しています。これにより、ビットマップオブジェクトに対して、先に作成されたグラフィックリソースが適用されます。
ArrayInitialize関数によるビットマップの色設定
次に、ビットマップの全体の色を設定しています。ColorToARGB関数を使って、GreenYellow色を透明度200の状態でARGB形式に変換し、これを変数clr に格納しています。この色情報を使って、ArrayInitialize関数でピクセル配列全体を指定された色で初期化しています。これにより、ビットマップオブジェクト全体が指定された色で表示されます。
サンプルコード解説5:OnStart関数部分その4
//--- DodgerBlue色を使用してグリッドを描画する
for (int x = 0; x < ExtResWidth; x += 9)
LineVertical(x, 0, ExtResHeight, ColorToARGB(clrDodgerBlue, 200)); // 垂直線を描画
for (int y = 0; y < ExtResHeight; y += 9)
LineHorizontal(0, ExtResWidth, y, ColorToARGB(clrDodgerBlue, 200)); // 水平線を描画
//--- グラフィックリソースデータを更新する
Update(ExtResName, ExtResData, ExtResWidth, ExtResHeight, true);
この部分では、ビットマップにグリッドを描画し、描画内容をグラフィックリソースに更新する処理が行われています。
DodgerBlue色のグリッド描画
まず、DodgerBlue色を使用して、ビットマップ上にグリッドを描画します。グリッドは、垂直線と水平線を描画することで構成されます。
垂直線の描画
最初の forループでは、ビットマップの幅に沿って、垂直線が描かれます。ループ内では、9ピクセル間隔で LineVertical関数を呼び出し、x座標に線を描画しています。
ColorToARGB関数を使用して、DodgerBlue色を透明度200でARGB形式に変換し、描画色として渡しています。
水平線の描画
次の forループでは、ビットマップの高さに沿って、水平線が描かれます。これも9ピクセル間隔で LineHorizontal関数を呼び出し、y座標に線を描画しています。描画の色は、同様に ColorToARGB関数で変換したDodgerBlue色が使用されています。
これらの処理により、9ピクセルごとに縦と横に線が描かれ、グリッドパターンがビットマップに表示されます。
グラフィックリソースの更新
グリッドが描かれた後、Update関数を使用してグラフィックリソースを更新しています。Update関数は、リソース名、ピクセルデータ、リソースの幅、高さ、そしてリソースを更新した後にチャートを再描画するかどうかを引数に取ります。ここでは、チャートの再描画を行うために true が指定されています。
これにより、ビットマップ上に描かれたグリッドがグラフィックリソースに反映され、即座に更新されます。
サンプルコード解説6:OnStart関数部分その5
//--- リソースとオブジェクトを削除する前に3秒待機
Print("Wait 3 seconds before deleting the resource and graphic object");
Sleep(3000); // 3秒待機
//--- リソースをファイルに保存する
ResetLastError(); // エラーリセット
if (!ResourceSave("::" + ExtResName, "ResourceSave\\" + ExtResName + ".bmp"))
{
Print("ResourceSave() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
return; // エラーが発生したため、処理を終了する
}
//--- リソースとグラフィックオブジェクトを削除する
if (!ResourceFree("::" + ExtResName))
{
Print("ResourceFree() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
return; // エラーが発生したため、処理を終了する
}
if (!ObjectDelete(0, obj_name))
{
Print("ObjectDelete() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
return; // エラーが発生したため、処理を終了する
}
この部分では、リソースやオブジェクトを削除する前の待機処理、リソースの保存、そしてリソースおよびグラフィックオブジェクトの削除が行われています。
リソースとオブジェクトの削除前に3秒待機
まず、リソースとオブジェクトを削除する前に3秒間の待機処理が行われます。Print関数でログにメッセージを出力し、Sleep関数を使用して3秒間スクリプトの実行を停止します。この待機は、ユーザーにリソースが削除されることを通知し、操作を一時的に停止するためのものです。
ResourceSave関数によるリソースの保存
次に、ResourceSave関数を使用して、グラフィックリソースをファイルに保存します。まず、ResetLastError関数を呼び出して、エラー情報をリセットします。ResourceSave関数は、リソース名と保存先のファイル名を指定します。ここでは、リソース名には「::」を付けたリソース名を指定し、ファイル名には “ResourceSave\” のフォルダ内にリソース名と同じ名前のビットマップファイルを指定しています。
もしリソースの保存が失敗した場合は、Print関数を使ってエラーコードをログに出力し、スクリプトを終了させます。
ResourceFree関数とObjectDelete関数による削除
その後、ResourceFree関数を使って、指定されたリソースをメモリから解放します。リソースの解放に失敗した場合も、エラーコードがログに出力され、スクリプトが終了します。
続いて、ObjectDelete関数を使用して、ビットマップオブジェクトを削除します。こちらも削除が失敗した場合には、エラーコードがログに出力され、処理が終了します。
これにより、メモリとチャート上に表示されたリソースやオブジェクトが適切に解放され、リソースの保存と管理が安全に行われます。
サンプルコード解説7:OnStart関数部分その6
//--- 最後のティック価格と時刻に基づいて新しいグラフィックラベルオブジェクトを作成する
int x = 0, y = 0;
if (!ChartTimePriceToXY(0, 0, tick.time, tick.bid, x, y))
{
Print("ChartTimePriceToXY() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
return; // エラーが発生したため、処理を終了する
}
obj_name = "BitmapLabel"; // 新しいグラフィックラベルオブジェクト名
if (!ObjectCreate(0, obj_name, OBJ_BITMAP_LABEL, 0, 0, 0))
{
Print("ObjectCreate() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
return; // エラーが発生したため、処理を終了する
}
この部分では、最新のティックデータを基に新しいグラフィックラベルオブジェクトを作成する処理が行われています。
ChartTimePriceToXY関数による座標変換
まず、ティックデータの時間と価格を基に、チャート上の座標を取得しています。ChartTimePriceToXY関数は、指定された時間と価格をピクセル座標に変換します。この関数の引数として、チャートID(ここでは0)、時間、価格、そして変換された後のX座標とY座標を受け取る変数(x、y)が指定されています。
もしこの関数が失敗した場合には、エラーコードがエキスパートログに出力され、スクリプトの実行が終了します。これにより、ティックデータに基づいて適切に座標を取得できなかった場合のエラー処理が行われます。
ObjectCreate関数によるグラフィックラベルオブジェクトの作成
次に、新しいグラフィックラベルオブジェクトを作成します。ObjectCreate関数を使用して、チャート上にグラフィックラベルオブジェクトを作成します。このオブジェクトは、OBJ_BITMAP_LABEL というタイプで、ビットマップ画像として表示されるラベルです。
作成するオブジェクトの名前として obj_name に “BitmapLabel” を指定しています。関数が失敗した場合には、エラーコードがエキスパートログに出力され、スクリプトの実行が終了します。これにより、グラフィックラベルオブジェクトの作成に失敗した場合でも、エラー処理が適切に行われます。
この処理によって、最新のティックデータに基づいた座標に、グラフィックラベルオブジェクトが表示されるようになります。
サンプルコード解説8:OnStart関数部分その7
//--- ラベルオブジェクトのアンカーポイントを中心に設定
ObjectSetInteger(0, obj_name, OBJPROP_ANCHOR, ANCHOR_CENTER);
//--- 座標を調整して、画像の幅だけ左にシフトして設定
ObjectSetInteger(0, obj_name, OBJPROP_XDISTANCE, x - ExtResWidth);
ObjectSetInteger(0, obj_name, OBJPROP_YDISTANCE, y);
//--- 先に保存したbmp画像ファイルをリソースとして指定
ObjectSetString(0, obj_name, OBJPROP_BMPFILE, "\\Files\\ResourceSave\\" + ExtResName + ".bmp");
//--- チャートを更新
ChartRedraw();
//--- グラフィックラベルオブジェクトを削除する前に3秒待機
Print("Wait 3 seconds before deleting the new graphic object");
Sleep(3000); // 3秒待機
if (!ObjectDelete(0, obj_name))
Print("ObjectDelete() failed. Error code: ", GetLastError()); // エラー発生時にエキスパートログに出力
}
この部分では、グラフィックラベルオブジェクトのアンカーポイントの設定、座標の調整、ビットマップファイルの指定、そしてチャートの更新とオブジェクト削除が行われています。
ObjectSetInteger関数によるアンカーポイントの設定
最初に、ObjectSetInteger関数を使って、グラフィックラベルオブジェクトのアンカーポイントを設定しています。アンカーポイントとは、オブジェクトの基準となる位置を指します。ここでは、アンカーポイントを中央に設定するために、プロパティOBJPROP_ANCHORに対して値ANCHOR_CENTERが指定されています。これにより、オブジェクトの中央が基準となって配置されます。
ObjectSetInteger関数による座標の調整
次に、オブジェクトのX座標とY座標を調整しています。X座標は、取得した座標xからリソースの幅を引いた値に設定し、Y座標はそのままyの値を使用しています。これにより、オブジェクトが画像の幅だけ左にシフトされて表示されます。
ObjectSetString関数によるビットマップファイルの指定
その後、ObjectSetString関数を使って、先に保存されたビットマップファイルをグラフィックラベルオブジェクトに関連付けています。ここでは、OBJPROP_BMPFILEというプロパティを使用し、ファイルパスとしてMQL5のFilesフォルダ内に保存されたビットマップファイルを指定しています。このビットマップファイルは、以前にResourceSave関数で保存されたものです。
チャートの更新
ObjectSetString関数を使ってビットマップファイルを指定した後、ChartRedraw関数を呼び出してチャート全体を再描画しています。これにより、設定した内容が即座にチャートに反映されます。
オブジェクトの削除と待機
次に、Print関数で「3秒待機する」旨のメッセージをログに出力し、Sleep関数で3秒間待機します。その後、ObjectDelete関数を使って、作成したグラフィックラベルオブジェクトを削除します。もし削除に失敗した場合は、エラーコードがエキスパートログに出力されます。
この処理によって、グラフィックラベルオブジェクトが一時的に表示され、その後削除されることが実現されます。
サンプルコード解説9:Update関数(オリジナル関数)
//+------------------------------------------------------------------+
//| グラフィックリソースデータを更新する関数 |
//+------------------------------------------------------------------+
void Update(const string res_name, const uint &pixel_data[], const uint width, const uint height, const bool redraw)
{
//--- ゼロ次元が渡された場合は終了する
if (width == 0 || height == 0)
return;
//--- リソースデータを更新し、必要ならチャートを再描画する
if (ResourceCreate(res_name, pixel_data, width, height, 0, 0, 0, COLOR_FORMAT_ARGB_NORMALIZE) && redraw)
ChartRedraw();
}
このUpdate関数は、グラフィックリソースのデータを更新し、必要に応じてチャートを再描画するために使用されます。以下では、各引数と関数内部の動作について詳細に解説します。
引数の解説
- res_name (string型)
res_name は、更新するリソースの名前を表す文字列型の引数です。リソースはグラフィックリソースや画像ファイルなどを指し、名前を指定することで、どのリソースを更新するかを識別します。この名前は、リソースを正しく操作するために必要であり、ResourceCreate関数に渡されます。 - pixel_data (uint型配列の参照)
pixel_data は、ピクセルデータを格納する配列の参照です。この配列には、各ピクセルの色情報(ARGB値)が格納されています。このデータがリソースとして使用され、グラフィックリソースの表示内容に反映されます。&が付いているため、この配列は参照渡しされ、関数内での変更が呼び出し元に反映されます。 - width (uint型)
width は、リソースの横幅(ピクセル数)を指定する引数です。この値は、ピクセル配列の幅を指定し、ResourceCreate関数に渡されてリソースのサイズを決定します。幅が0の場合は処理が無効と見なされ、関数は即座に終了します。 - height (uint型)
height は、リソースの縦幅(ピクセル数)を指定する引数です。この値も、width と同様にリソースの高さを決定するために使用されます。高さが0の場合も同様に、処理が無効と見なされ、関数は終了します。 - redraw (bool型)
redraw は、チャートを再描画するかどうかを指定するbool型の引数です。true が指定されると、リソースが更新された後に ChartRedraw関数を呼び出してチャート全体が再描画され、変更が即座に反映されます。false が指定された場合は、再描画は行われません。
関数内部の処理
- 幅と高さのチェック
関数の最初では、width または height が0である場合、即座に関数を終了します。これは、無効なサイズのリソースを作成しないためのチェックです。 - ResourceCreate関数によるリソースの更新
ResourceCreate関数を使用して、指定されたピクセルデータを基にリソースを作成します。この関数は、リソース名、ピクセルデータ、幅、高さなどを引数に取り、リソースを更新します。ここで、COLOR_FORMAT_ARGB_NORMALIZEを指定することで、ピクセルデータが ARGB 形式で正規化されていることを示しています。 - チャートの再描画
ResourceCreate関数の実行が成功し、かつ redraw が true の場合にのみ、ChartRedraw関数が呼び出されます。この関数により、チャートが再描画され、リソースの更新が即座にチャート上に反映されます。
このUpdate関数は、リソースデータを効率的に更新し、必要に応じてチャートに変更を反映させるための重要な機能を提供しています。
サンプルコード解説10:LineVertical関数その1(オリジナル関数)
//+------------------------------------------------------------------+
//| 垂直線を描画する関数 |
//+------------------------------------------------------------------+
void LineVertical(int x, int y1, int y2, const uint clr)
{
int tmp;
//--- y座標を並べ替える
if (y1 > y2)
{
tmp = y1;
y1 = y2;
y2 = tmp;
}
//--- 画像の境界外の場合は描画しない
if (y2 < 0 || y1 >= ExtResHeight || x < 0 || x >= ExtResWidth)
return;
LineVertical関数は、指定された x 座標で垂直線を描画するために使用されます。この関数は、与えられた y 座標の範囲に従い、画像の境界内でのみ線を描画します。
引数の解説
- x (int型)
x は、垂直線を描く位置の x 座標です。x 座標は画像の幅に対応しており、指定された x の位置に垂直線が描かれます。 - y1, y2 (int型)
y1 と y2 は、垂直線の描画範囲を指定する y 座標です。y1 から y2 の範囲で線が描かれます。この2つの値は、範囲が逆になっている場合(y1 が y2 より大きい場合)に正しい順番に並べ替えられます。 - clr (uint型)
clr は、描画する線の色を ARGB 形式で指定します。これはColorToARGB関数などを使用して生成された色で、各ピクセルの色を指定するために使用されます。
関数内部の処理
- y座標の並べ替え
y1 が y2 よりも大きい場合、両者の値を入れ替えています。これにより、常に小さい方の y 座標から大きい方の y 座標に向かって描画されるようになります。この処理は、垂直線が正しい方向に描画されるために必要です。 - 画像の境界チェック
次に、線を描画する y 座標が画像の境界外である場合は描画をスキップしています。具体的には、y2 が 0 未満であったり、y1 が画像の高さより大きい場合、または x 座標が 0 未満または画像の幅を超えている場合に描画を行わないようにしています。この処理により、画像の範囲外に線が描かれないようにしています。
これにより、与えられた範囲内でのみ正しく垂直線が描かれるように調整されています。次の処理で実際に線が描画される部分に進みます。
サンプルコード解説11:LineVertical関数その2(オリジナル関数)
//--- 画像内に収まるように調整する
if (y1 < 0)
y1 = 0;
if (y2 >= ExtResHeight)
y2 = ExtResHeight - 1;
//--- 垂直線を描画
int index = y1 * ExtResWidth + x;
for (int i = y1; i <= y2; i++, index += ExtResWidth)
ExtResData[index] = clr;
}
この部分では、LineVertical関数内で実際に垂直線を描画する処理が行われています。ここでは、y座標の範囲を画像の範囲内に調整し、その範囲内で垂直線を描画しています。
画像内に収まるように調整
最初に、y座標の範囲が画像の範囲内に収まるように調整しています。
- y1 < 0 の場合、y1 を 0 にリセットしています。これは、y座標が画像の上端よりも小さくならないようにするためです。
- y2 >= ExtResHeight の場合、y2 を ExtResHeight – 1 にリセットしています。これは、y座標が画像の下端よりも大きくならないようにするためです。
この処理により、y座標の範囲が画像の有効範囲内に収まるように制御されています。
垂直線を描画
y座標の範囲が調整された後、その範囲内で垂直線を描画します。
- index という変数を使って、描画するピクセルのインデックスを計算しています。index は、y1からy2までの範囲で各ピクセルの位置を指し示します。y1 * ExtResWidth + x という式で、ピクセルデータ配列内の描画開始位置を計算しています。これは、y1行目のx列目のピクセルを示します。
- forループでは、y1からy2までの各y座標に対応するピクセルのインデックスを計算し、その位置に指定された色 clr を設定しています。index += ExtResWidth で次の行に移動するため、y座標ごとに垂直に線を描画していきます。
この処理によって、画像のピクセルデータ配列に垂直線が正しく描画されます。
サンプルコード解説12:LineHorizontal関数その1(オリジナル関数)
//+------------------------------------------------------------------+
//| 水平線を描画する関数 |
//+------------------------------------------------------------------+
void LineHorizontal(int x1, int x2, int y, const uint clr)
{
int tmp;
//--- x座標を並べ替える
if (x1 > x2)
{
tmp = x1;
x1 = x2;
x2 = tmp;
}
LineHorizontal関数は、指定された y 座標で水平線を描画するために使用されます。この関数は、与えられた x 座標の範囲に従い、画像の境界内でのみ水平線を描画します。
引数の解説
- x1, x2 (int型)
x1 と x2 は、水平線の描画範囲を指定する x 座標です。x1 から x2 の範囲で水平線が描かれます。この2つの値は、範囲が逆になっている場合(x1 が x2 より大きい場合)に正しい順番に並べ替えられます。 - y (int型)
y は、水平線を描く位置の y 座標です。y 座標は画像の高さに対応しており、指定された y の位置に水平線が描かれます。 - clr (uint型)
clr は、描画する線の色を ARGB 形式で指定します。この色は、各ピクセルの色を指定するために使用され、水平線の見た目を決定します。
関数内部の処理
- x座標の並べ替え
x1 が x2 よりも大きい場合、両者の値を入れ替えています。これにより、常に小さい方の x 座標から大きい方の x 座標に向かって描画されるようになります。この処理は、水平線が正しい方向に描画されるために必要です。
これにより、与えられた範囲内でのみ正しく水平線が描かれる準備が整います。次のステップで実際に水平線を描画する処理に進みます。
サンプルコード解説13:LineHorizontal関数その2(オリジナル関数)
//--- 画像の境界外の場合は描画しない
if (x2 < 0 || x1 >= ExtResWidth || y < 0 || y >= ExtResHeight)
return;
//--- 画像内に収まるように調整する
if (x1 < 0)
x1 = 0;
if (x2 >= ExtResWidth)
x2 = ExtResWidth - 1;
//--- 水平線を描画
ArrayFill(ExtResData, y * ExtResWidth + x1, (x2 - x1) + 1, clr);
}
この部分では、LineHorizontal関数内で水平線を描画する処理が行われています。ここでは、x座標の範囲が画像の境界内に収まるように調整し、その範囲内で水平線を描画します。
画像の境界外の場合は描画しない
最初に、水平線の描画が画像の範囲外で行われないようにチェックを行っています。
- x2 < 0 または x1 >= ExtResWidth の場合、x座標が画像の左端または右端を超えているため描画をスキップします。
- y < 0 または y >= ExtResHeight の場合、y座標が画像の上下の境界を超えているため、水平線の描画をスキップします。
この処理により、画像の有効範囲外で水平線が描かれないように保護しています。
画像内に収まるように調整
次に、x座標が画像の範囲内に収まるように調整しています。
- x1 < 0 の場合、x1 を 0 にリセットします。これは、x座標が画像の左端より小さくならないようにするためです。
- x2 >= ExtResWidth の場合、x2 を ExtResWidth – 1 にリセットします。これは、x座標が画像の右端を超えないようにするためです。
この処理により、x座標の範囲が画像の有効範囲内に制御されます。
水平線を描画
最後に、ArrayFill関数を使って水平線を描画します。
- y * ExtResWidth + x1 で、描画を開始するピクセルのインデックスを計算しています。これは、y行目のx1列目のピクセル位置を示しています。
- (x2 – x1) + 1 で、描画するピクセル数を計算しています。x1からx2までの範囲に描画されるピクセルの数を指定します。
- clr は指定された色で、これが水平線の色として設定されます。
この処理により、画像データに指定された x 座標の範囲に水平線が描かれます。