English Русский 中文 Español Deutsch Português
preview
MQLアプリケーションでのCCanvasクラスの使用

MQLアプリケーションでのCCanvasクラスの使用

MetaTrader 5 | 17 5月 2022, 10:23
419 0
Mihail Matkovskij
Mihail Matkovskij

この記事では、CCanvasクラスとMQLアプリケーションでのその使用について詳しく説明します。理論には例が付いています。


アプリケーションのグラフィック

アプリケーションでグラフィックを処理するには、画面上のピクセルデータにアクセスする必要があります。そのようなアクセスが可能な場合、ピクセルの色を変更したり、さまざまなUI要素、入力フィールド、ボタン、パネル、ウィンドウなどの要素を作成したり、ファイルから画像を表示したり、ピクセルデータを取得および処理したりできます。一般に、このメカニズムは、名前に「Canvas」という単語が含まれるクラスに配置されています。Cベースのプログラミング言語では、これは通常、コードの記述スタイルに応じて、CCanvasまたはCanvasとなります。したがって、グラフィックにアクセスするには、すべてのアプリにキャンバスが必要です。


MQLアプリケーションのキャンバス

MQLでは、ツールは、ピクセル配列、ピクセル配列を変更するためのメソッド、および配列をターミナルチャートに送信するメカニズムを含むCCanvasクラスの形式で提供されます。OBJ_BITMAPまたはOBJ_BITMAP_LABELグラフィカルオブジェクトが表示の手段として使用されます。適用されたグラフィカルオブジェクトは、グラフィカルリソースからデータを取得し、グラフィカルリソースはピクセル配列からデータを受信します。

CCanvasクラスを使用すると、すべてのデスクトップUI機能を実装できます。ユーザーインターフェイスに加えて、CCanvasは、指標バッファ、OHLCバーなどの描画を可能にします。可能性は無限大なので、このトピックについては、他の記事で検討します。次に、CCanvasクラスに戻ります。


CCanvasの詳細

さて、最も興味深い部分、つまりCCanvasクラスを掘り下げる時が来ましたその構造を理解することで、このツールをマスターすることができます。CCanvasの構造を以下に示します。

CCanvasの詳細

ご覧のとおり、クラスはデータメソッドの2つの大きなセクションに分かれています。

データについて考えてみましょう。

  • ピクセルデータ: 描画メソッドによって処理されるピクセルを格納するm_pixelsピクセル配列、および m_width(画像幅)とm_height(画像の高さ)のデータです。m_widthおよびm_heightパラメータは、描画メソッドによるm_pixels配列の処理、およびUpdateメソッドによるグラフィカルリソースへのm_pixels配列の受け渡しにとって非常に重要です。
  • テキストを表示するためのフォントデータ: m_fontname(フォント名)、 m_fontsize(サイズ)、m_fontflags(属性)、m_fontangle(テキストの傾斜角度)のフィールドで構成されます。このデータは、TextOutメソッドを呼び出す前に、フォントプロパティを設定および受信するために必要です(フォントプロパティの読み取り/書き込みメソッドを使用)。
  • 線画データ: m_style(線スタイル)とm_style_idx(線スタイルテンプレートの現在のビットインデックス)の2つのフィールドで構成されます。描画メソッドに必要です。
  • デフォルトデータ: ここでは、単一のフィールドm_default_colors(デフォルトのカラー配列)があります。CCanvasクラスのメソッド自体では使用されませんが、CCanvasの子孫クラスの他の関数またはメソッドでカラーパレットとして役立つ場合があります。
  • チャートの相互作用データ: m_chart_id(チャートオブジェクトID)、m_objname(チャートオブジェクト名)、m_objtype(チャートオブジェクトタイプ)、m_rcname(グラフィカルリソース名)、m_format(ピクセル形式)が含まれます。データは、破棄、更新、サイズ変更メソッドを対象としています。特に、TextOutメソッドの操作にはm_formatフィールドが必要です。


メソッドについて考えてみましょう。

  • 作成/添付/削除のメソッド: このカテゴリには、チャートオブジェクトを操作するさまざまなメソッドがあります。グラフィカルオブジェクトを作成するメソッド(CreateBitmapおよびCreateBitmapLabel)は、チャートオブジェクトとそれに関連するグラフィカルリソースを作成するためのものであり、チャートに画像を表示します。接続メソッド(Attach)は、チャートにOBJ_BITMAP_LABELグラフィカルオブジェクト(グラフィカルリソースが接続されているかどうかに関係なく)が含まれている場合、CCanvasは、新しく作成されたグラフィカルオブジェクトを処理するのと同じ方法で処理します。適切なAttachメソッドを使用して接続するだけです。削除メソッドDestroyと呼ばれ、グラフィカルオブジェクトを削除し、m_pixelsピクセル配列バッファを解放し、チャートオブジェクトに関連するグラフィカルリソースを削除します。したがって、クラスはチャートオブジェクトとグラフィカルリソースを自動的に削除しないため、CCanvasの完了時に常にDestroyメソッドを呼び出す必要があります。
  • ファイルから画像をアップロードするメソッド: LoadBitmap静的メソッドは、*.bmpファイルからパラメータとしてアドレスで渡された任意のuint配列に画像をアップロードし、取得した画像のサイズをパラメータとして適切なアドレスでメソッドにも渡される「width」および「height」変数に保存します。LoadFromFileメソッドは、*.bmpファイルからm_pixels配列に画像をアップロードし、m_widthおよびm_height画像パラメータを設定します。m_formatピクセル形式は、COLOR_FORMAT_ARGB_RAWと同じである必要があります。
  • チャートオブジェクトのプロパティを読み取るメソッドは、ChartObjectName(チャートオブジェクト名)、ResourceName(グラフィカルリソース名)、Width(画像の幅)、Height(画像の高さ)で構成されます。これらのメソッドを使用すると、m_objname、m_rcname、m_width、m_heightの画像データなど、チャートを操作するためのデータのみを読み取ることができます。
  • 表示されたテキストのフォントプロパティの読み取り/書き込みメソッド: FontNameSetFontSizeSetFontFlagsSetFontAngleSet書き込みメソッドはそれぞれ表示されるテキストのフォント名、サイズ、属性、傾斜角度を設定します。FontSizeGetFontFlagsGetFontAngleGet読み取りメソッドはそれぞれ、フォントサイズと属性、および表示されたテキストの傾斜角度を返します。フォントプロパティを受信/設定するメソッドもあり、すべてのフォントプロパティを一度に返す/設定します。プロパティを設定するFontSetメソッドはそれぞれ、表示されるテキストのフォント名、サイズ、属性、傾斜角度を設定します。プロパティを受け取るためのFontGetメソッドはそれぞれ、表示されたテキストのフォント名、サイズ、属性、および傾斜角度を返します。 
  • 線画スタイルの読み取り/書き込みメソッド: LineStyleGetメソッドは読み取りに使用され、LineStyleSetは書き込みに適用されます。線スタイルはLineAA、PolylineAA、PolygonAA、TriangleAA、CircleAA、EllipseAA、LineWu、PolylineWu、PolygonWu、TriangleWu、CircleWu、EllipseWu、LineThickVertical、LineThickHorizontal、LineThick、PolylineThick、 PolygonThickグラフィカルプリミティブの描画メソッドに必要です。
  • ピクセル配列での描画メソッド: CCanvasクラスには、さまざまなアルゴリズムを使用してグラフィカルプリミティブを描画する多数のメソッドがあり、アンチエイリアス、Wuのアルゴリズム、ベジェ曲線など、プログレッシブ平滑化メソッドを適用して複雑なグラフィックを作成できます。これらのメソッドについて考えてみましょう。平滑化なしの単純なプリミティブ: LineVerticalLineHorizontalLinePolylinePolygonRectangleTriangleCircleEllipseArc Pieメソッドは、それぞれプリミティブの垂直線、水平線、フリーハンド線、ポリライン、ポリゴン、長方形、三角形、円、楕円、円弧、塗りつぶされた楕円セクターを描画します。塗りつぶされたプリミティブ: FillRectangleFillTriangleFillPolygonFillCircleFillEllipse Fillメソッドはそれぞれ、長方形、三角形、ポリゴン、、楕円、領域の塗りつぶしを描画します。アンチエイリアス(AA)を介して平滑化を使用してプリミティブを描画するPixelSetAALineAAPolylineAAPolygonAATriangleAACircleAAEllipseAAメソッドはピクセルを塗りつぶし、フリーハンドライン、ポリライン、ポリゴン、三角形、、楕円などのプリミティブをそれぞれ表示します。Wuのアルゴリズムを使用してプリミティブを描画するLineWuPolylineWuPolygonWuTriangleWuCircleWuEllipseWuメソッドは、それぞれフリーハンド線、ポリライン、ポリゴン、三角形、、楕円を描画します。事前に並べ替えられたアンチエイリアスと調整可能な線幅を使用してプリミティブを描画する LineThickVerticalLineThickHorizontalLineThickPolylineThickPolygonThickメソッドは、それぞれ垂直線、水平線、フリーハンド線、ポリライン、ポリゴンのプリミティブを描画するためのものです。Bézierメソッドを使用して平滑化されたプリミティブを描画するPolylineSmoothおよびPolygonSmoothメソッドは、それぞれ平滑化された線と平滑化されたポリゴンなどのプリミティブを描画します。上記のメソッドとは別に、このカテゴリには、最初のCCanvasクラスコードのテキスト処理メソッドのグループに分類されるがピクセル配列の色の値も変更するため、テキストTextOutを表示するメソッドも含まれます。
  • チャートに表示するために画像を渡すメソッドのカテゴリには2つのメソッドが含まれます。Updateメソッドは、画像を表示するチャートオブジェクトに関連するグラフィカルリソースへのm_pixelsピクセル配列を渡します。すでに述べたように、m_pixelsピクセル配列は、ピクセル配列内の上記の描画メソッドの助けを借りて変更されます。Resizeメソッドは、m_pixels配列サイズ(画像サイズ)を変更し、それをグラフィカルリソースにも渡します。
  • サービス: CCanvasには2つのサービスメソッドがあります。GetDefaultColorは再定義された色を返し、 TransparentLevelSetはm_pixels配列のアルファチャンネル値を変更することで画像の透明度を変更します。
  • その他の設定: ここにあるのは、アンチエイリアシングフィルタを設定するためのFilterFunctionメソッド1つだけです。これは、名前にAA記号が含まれるすべての描画メソッドのフィルタを設定します。

CCanvasクラスの「private」可視領域にはフィールドとメソッドがあります。それらは内部のものであってCCanvasの子孫クラスの再定義されたメソッドでは使用できないため、この記事では考慮しません。MetaEditorのCanvas.mqhモジュールソースコードをご覧ください。


MQLアプリケーションでCCanvasを使用するときに適用される一連のアクション

上記のすべてを考慮すると、CCanvasクラスをMQLアプリケーションで使用するときに、処理の一般的な一連のアクションを強調表示できるようになりました。画像をチャートに表示するために実行するアクションについて考えてみましょう。

  • チャートオブジェクト(OBJ_BITMAPまたはOBJ_BITMAP_LABEL)を作成または添付するか、既存の OBJ_BITMAP_LABELに添付する
  • フォントパラメータとプリミティブな描画スタイルを設定する
  • 適切な方法を使用して、m_pixels配列で描画を実行する
  • グラフィカルオブジェクトリソース(OBJ_BITMAPまたはOBJ_BITMAP_LABEL)を更新する

その結果、チャートには、グラフィカルな構造またはテキストを持つオブジェクトが含まれます。アクションを詳しく考えてみましょう。

チャートオブジェクトの作成と既存チャートオブジェクトへの接続

MQLアプリケーションでチャートにグラフィックを表示するには、CCanvasクラスまたはその子孫に基づいてオブジェクトを作成する必要があります。CCanvasオブジェクトを作成したら、OBJ_BITMAPまたはOBJ_BITMAP_LABELチャートオブジェクトの開発を開始できます。または、既存のOBJ_BITMAP_LABELを作成したCCanvasオブジェクトに接続することもできます。

グラフィカルオブジェクトを作成するために、CCanvasにはCreateBitmapメソッドとCreateBitmapLabelメソッドがあります。それらのそれぞれは、より便利な使用のために独自のオーバーロードオプションを適用します。

bool  CreateBitmap(const long chart_id, const int subwin, const string name, const datetime time, const double price, const int width, const int height, ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);

bool  CreateBitmap(const string name, const datetime time, const double price, const int width, const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);

bool  CreateBitmapLabel(const long chart_id, const int subwin, const string name, const int x, const int y, const int width, const int height, ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);

bool  CreateBitmapLabel(const string name,const int x,const int y, const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);


CreateBitmapメソッドはビットマップ(OBJ_BITMAPオブジェクトタイプ)を作成します。その座標は取引銘柄チャートで時間と価格として設定され、次のパラメータが含まれています。

  • chart_id - チャートID(0 - 現在)
  • window - チャートサブウィンドウインデックス(0 –メインウィンドウ)
  • name –チャート上に作成されたグラフィカルオブジェクトの名前
  • time –チャート上のグラフィカルオブジェクトの時間座標
  • price –チャート上のグラフィカルオブジェクトの価格座標
  • width – チャート上のグラフィカルオブジェクトの幅
  • height – チャート上のグラフィカルオブジェクトの高さ

もう1つのCreateBitmapメソッドオプションはオーバーロードされたメソッドで、 chart_idwindowが0(現在のチャートとメインウィンドウに対応)に等しいCreateBitmapを呼び出します。

//+------------------------------------------------------------------+
//| Create object on chart with attached dynamic resource            |
//+------------------------------------------------------------------+
bool CCanvas::CreateBitmap(const string name,const datetime time,const double price,
                           const int width,const int height,ENUM_COLOR_FORMAT clrfmt)
  {
   return(CreateBitmap(0,0,name,time,price,width,height,clrfmt));
  }

CreateBitmapLabelメソッドには、「time」と「price」を除いて、CreateBitmapと同じパラメータがあります。代わりにxyがあります。

入力:

  • chart_id –チャートID(0 –現在)
  • window - チャートサブウィンドウインデックス(0 –メインウィンドウ)
  • name –チャート上に作成されたグラフィカルオブジェクトの名前
  • x - チャート上のグラフィカルオブジェクトのX座標
  • y –チャート上のグラフィカルオブジェクトのY座標
  • width – 作成されたグラフィカルオブジェクトイメージの幅
  • height –作成されたグラフィカルオブジェクト画像の高さ
  • clrfmt - 作成されたグラフィカルオブジェクト画像のピクセルカラー形式

もう1つのCreateBitmapLabelメソッドオプションはオーバーロードされたメソッドで、chart_idwindowが0に等しいCreateBitmapLabelを呼び出します(CreateBitmapと同じ)。

//+------------------------------------------------------------------+
//| Create object on chart with attached dynamic resource            |
//+------------------------------------------------------------------+
bool CCanvas::CreateBitmapLabel(const string name,const int x,const int y,
                                const int width,const int height,ENUM_COLOR_FORMAT clrfmt)
  {
   return(CreateBitmapLabel(0,0,name,x,y,width,height,clrfmt));
  }

チャートにOBJ_BITMAP_LABELオブジェクトがある場合は、Attachメソッドを使用してCCanvasに接続できます。その結果、チャートオブジェクトは、CreateBitmapまたはCreateBitmapLabelメソッドを使用して作成されたチャートオブジェクトと同じ方法でCCanvasオブジェクトと対話します。

virtual bool  Attach(const long chart_id,const string objname,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);

virtual bool  Attach(const long chart_id,const string objname,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);


このメソッドは、CCanvasを既存のOBJ_BITMAP_LABELチャートオブジェクトに接続します。

入力:

  • chart_id –チャートID(0 –現在)
  • objname - 接続されたグラフィカルオブジェクトの名前
  • width - 接続されたグラフィカルオブジェクト画像の幅
  • height - 接続されたグラフィカルオブジェクト画像の高さ
  • clrfmt – 接続されたグラフィカルオブジェクト画像のピクセルカラー形式

Attachメソッドの最初のオプションは、チャートオブジェクトにグラフィカルリソースがなく、objnamewidthheight clrfmtパラメータを使用して独自に作成することおよび接続されたグラフィカルオブジェクトのさらなる処理に必要なすべてのデータを入力することを示唆します。

2番目のオプションは、グラフィカルリソースの存在を意味し、画像ピクセルデータをm_pixels配列に読み取るだけで、接続されたグラフィカルオブジェクトのさらなる処理に必要なすべてのデータも入力することを示唆します。

フォントパラメータを設定および受信するメソッド、および線画スタイルを設定および受信するメソッド

CreateBitmapまたはCreateBitmapLabelメソッドを使用してグラフィカルオブジェクトを作成した後、またはAttachメソッドを使用して接続した後、必要な画像を取得するためにフォントパラメータとプリミティブ描画スタイルを設定する必要があります。フォントパラメータは、以下のメソッドで設定します。

以下は、フォントプロパティを設定するための簡単なメソッドです。

bool FontNameSet(string name);  // Set the font name

bool FontSizeSet(int size);     // Set the font size

bool FontFlagsSet(uint flags);  // Set the font attributes

bool FontAngleSet(uint angle);  // Set the font slope angle


以下は、フォントプロパティを読み取るための簡単なメソッドです。

string FontNameGet(void) const;   // Return the font name

int    FontSizeGet(void) const;   // Return the font size

uint   FontFlagsGet(void) const;  // Return the font attributes

uint   FontAngleGet(void) const;  // Return the font slope angle


以下は、すべてのフォントプロパティを設定するメソッドです。

bool FontSet(const string name,const int size,const uint flags=0,const uint angle=0); // Set the font properties

入力:

  • name - フォント名
  • size - フォントサイズ
  • flags - フォント属性
  • angle - フォントの傾斜角度

コードからわかるように、このメソッドは、パラメータとして渡されたnamesizeflagsangle変数値に従ってフォント名、サイズ、属性、テキストの傾斜角度を設定します。

以下は、すべてのフォントプロパティを受け取るメソッドです。

void FontGet(string &name,int &size,uint &flags,uint &angle); // Get font properties

入力:

  • name - フォント名
  • size - フォントサイズ
  • flags - フォント属性
  • angle - フォントの傾斜角度

コードからわかるように、このメソッドは、パラメータとして渡されたnamesizeflags angle変数値に従ってフォント名、サイズ、属性、テキストの傾斜角度を書き込みます。

以下は、グラフィカルな下書き線スタイルの読み取りと書き込みのためのメソッドです。

uint LineStyleGet(void) const;       // Return the specified line drawing style

void LineStyleSet(const uint style); // Set the line drawing style


    入力:

    • style - 線画スタイル

    テキストの描画と表示のメソッド 

    CCanvasにはグラフィカルなプリミティブ描画メソッドが多数あるのに対し、テキスト表示メソッドの種類は1つにすぎないため、それから始めましょう。

    テキスト表示

    void TextOut(int x,int y,string text,const uint clr,uint alignment=0); // Display text to the m_pixels array

    入力:

    • x - 表示されるテキストのX座標
    • y - 表示されるテキストのY座標
    • text - 表示されるテキスト
    • clr - 表示されるテキストの色
    • alignment - 表示されるテキストのアンカー方法

    コードによると、このメソッドは、clrで指定された色とalignmentテキスト固定方法を使用して座標(x, y)でtextを表示します。

    ピクセルの変更

    CCanvasでは、m_pixels配列にあるピクセルを変更したり、指定した座標に従ってそれらの値を受信したりできます。

    uint PixelGet(const int x,const int y) const;          // Return the pixel color value according to x and y coordinates
    
    void PixelSet(const int x,const int y,const uint clr); // Change the pixel color value according to x and y coordinates
    
    
    

    入力:

    • x - ピクセルのX座標
    • y - ピクセルのY座標
    • clr - ピクセルの色

    グラフィカルプリミティブの描画

    CCanvasはプリミティブを描画するための多数のメソッドを備えているため、この記事では最も重要なメソッドのみを検討します。他のすべてのメソッドは、ドキュメントにあります。

    垂直線

    void LineVertical(int x,int y1,int y2,const uint clr); // Draw a vertical line according to specified coordinates and color

    入力:

    • x - 線のX座標
    • y1 - 最初の点のY座標
    • y2 - 2番目の点のY座標
    • clr - 線の色

    水平線

    void LineHorizontal(int x1,int x2,int y,const uint clr); // Draw a horizontal line according to specified coordinates and color

    入力:

    • x1 - 最初の点のX座標
    • x2 - 2番目の点のX座標
    • y - 線のX座標
    • clr - 線の色

    フリーハンド線

    void Line(int x1,int y1,int x2,int y2,const uint clr); // Draw a freehand line according to specified coordinates and color

    入力:

    • x1 - 最初の点のX座標
    • y1 - 最初の点のY座標 
    • x2 - 2番目の点のX座標 
    • y2 - 2番目の点のY座標
    • clr - 線の色

    ポリライン

    void Polyline(int &x[],int &y[],const uint clr); // Draw a polyline according to specified coordinates and color

    入力:

    • x - 点Xの座標の配列
    • y - 点Yの座標の配列
    • clr - 線の色

    ポリゴン

    void Polygon(int &x[],int &y[],const uint clr); // Draw a polygon according to specified coordinates and color

    入力:

    • x - 点Xの座標の配列
    • y - 点Yの座標の配列
    • clr - ポリゴンの色

    長方形

    void Rectangle(int x1,int y1,int x2,int y2,const uint clr); // Draw a rectangle according to specified coordinates and color

    入力:

    • x1 - 最初の点のX座標
    • y1 - 最初の点のY座標
    • x2 - 2番目の点のX座標
    • y2 - 2番目の点のY座標
    • clr - 四角形の色 

    三角形

    void Triangle(int x1,int y1,int x2,int y2,int x3,int y3,const uint clr); // Draw a triangle according to specified coordinates and color

    入力:

    • x1 - 最初の点のX座標
    • y1 - 最初の点のY座標
    • x2 - 2番目の点のX座標
    • y2 - 2番目の点のY座標
    • x1 - 3番目の点のX座標
    • x1 - 3番目の点のY座標
    • clr - 三角形の色 

    void Circle(int x,int y,int r,const uint clr); // Draw a circle according to specified coordinates, radius and color

    入力:

    • x - X座標
    • y - Y座標
    • r - 円の半径
    • clr - 円の色

    楕円

    void Ellipse(int x1,int y1,int x2,int y2,const uint clr); // Draw an ellipse according to specified coordinates and color

    入力:

    • x1 - 最初の点のX座標
    • y1 - 最初の点のY座標
    • x2 - 2番目の点のX座標
    • y2 - 2番目の点のY座標
    • clr - 楕円形の色 

    ArcPieなどの他のメソッドの説明は大きすぎて、ここに表示できません。上記のリンクをたどると、ドキュメントでそれらの説明を見つけることができます。

    検討対象のメソッドは、線幅が1ピクセルで、通常のSTYLE_SOLID線スタイルの単純なプリミティブを表示します。シンプルなグラフィックで問題がなければ、それらを使用できます。

    ただし、STYLE_SOLIDとは異なるものが必要な場合は、以下で説明する方法のいずれかを選択してください。

    //--- Methods for drawing primitives with smoothing using antialiasing
        
    void PixelSetAA(const double x,const double y,const uint clr);
        
    void LineAA(const int x1,const int y1,const int x2,const int y2,const uint clr,const uint style=UINT_MAX);
        
    void PolylineAA(int &x[],int &y[],const uint clr,const uint style=UINT_MAX);
        
    void PolygonAA(int &x[],int &y[],const uint clr,const uint style=UINT_MAX);
        
    void TriangleAA(const int x1,const int y1,const int x2,const int y2,const int x3,const int y3,const uint clr,const uint style=UINT_MAX);
        
    void CircleAA(const int x,const int y,const double r,const uint clr,const uint style=UINT_MAX);
        
    void EllipseAA(const double x1,const double y1,const double x2,const double y2,const uint clr,const uint style=UINT_MAX);
        
    //--- Methods for drawing primitives with smoothing using Wu's algorithm
        
    void LineWu(int x1,int y1,int x2,int y2,const uint clr,const uint style=UINT_MAX);
        
    void PolylineWu(const int &x[],const int &y[],const uint clr,const uint style=UINT_MAX);
        
    void PolygonWu(const int &x[],const int &y[],const uint clr,const uint style=UINT_MAX);
        
    void TriangleWu(const int x1,const int y1,const int x2,const int y2,const int x3,const int y3,const uint clr,const uint style=UINT_MAX);
        
    void CircleWu(const int x,const int y,const double r,const uint clr,const uint style=UINT_MAX);
        
    void EllipseWu(const int x1,const int y1,const int x2,const int y2,const uint clr,const uint style=UINT_MAX);
    

    これらのメソッドはすべて上記で検討したものと似ていますが、ENUM_LINE_STYLE列挙から選択できる追加のstyleパラメータを持ちます。コードでは黄色で強調表示されています。styleパラメータが設定されていない場合(UINT_MAXと等しい)、呼び出されたメソッドは、LineStyleSetメソッドによって設定されたm_style値を使用します 。値は、LineStyleGetメソッドを使用して取得できます。

    メソッドには線のスタイルを設定する機能があっても線の幅を変更できないことにお気付きかもしれません。次のメソッドを使用すると、線幅を設定する機能を使用してプリミティブを描画できます。

    //--- Methods for drawing primitives with preliminarily set antialiasing filter
    
    void LineThickVertical(const int x,const int y1,const int y2,const uint clr,const int size,const uint style,ENUM_LINE_END end_style);
    
    void LineThickHorizontal(const int x1,const int x2,const int y,const uint clr,const int size,const uint style,ENUM_LINE_END end_style);
    
    void LineThick(const int x1,const int y1,const int x2,const int y2,const uint clr,const int size,const uint style,ENUM_LINE_END end_style);
    
    void PolylineThick(const int &x[],const int &y[],const uint clr,const int size,const uint style,ENUM_LINE_END end_style);
    
    void PolygonThick(const int &x[],const int &y[],const uint clr,const int size,const uint style,ENUM_LINE_END end_style);
    

    上記のメソッドと同様に、現在のメソッドでは、style線スタイルを設定できます。また、size(線幅の設定)、end_style(ENUM_LINE_END列挙から選択できる終了スタイル)などの新しいパラメータも備えています。

    さらに、CCanvasには、ベジェ法を使用して平滑化されたプリミティブを描画するためのメソッドがあります。最終的な画質を向上させるために、結果のプリミティブはビットマップ平滑化アルゴリズムを使用して処理されます。以前のメソッドとは異なり、ここでのプリミティブは直線ではなくベジェ曲線で構成されています。これらのメソッドについて考えてみましょう。

    //--- Methods for drawing a smoothed polyline and smoothed polygon
    
    void PolylineSmooth(const int &x[],const int &y[],const uint clr,const int size,
                        ENUM_LINE_STYLE style=STYLE_SOLID,ENUM_LINE_END end_style=LINE_END_ROUND,
                        double tension=0.5,double step=10);
    
    void PolygonSmooth(int &x[],int &y[],const uint clr,const int size,
                       ENUM_LINE_STYLE style=STYLE_SOLID,ENUM_LINE_END end_style=LINE_END_ROUND,
                       double tension=0.5,double step=10);
    

    すでにおなじみのxおよびyプリミティブ座標点(clr色、size線幅、 style線スタイル、end_style線補完スタイル)の配列に加えて、ここでは、2つの追加の張力パラメータ(平滑化パラメータ値とステップ近似ステップ)があります。

    上記で検討したプリミティブの描画方法とは別に、CCanvasは塗りつぶされたプリミティブを描画するメソッドを備えています。

    //--- Methods of drawing filled primitives
    
    void FillRectangle(int x1,int y1,int x2,int y2,const uint clr);
    
    void FillTriangle(int x1,int y1,int x2,int y2,int x3,int y3,const uint clr);
    
    void FillPolygon(int &x[],int &y[],const uint clr);
    
    void FillCircle(int x,int y,int r,const uint clr);
    
    void FillEllipse(int x1,int y1,int x2,int y2,const uint clr);
    
    void Fill(int x,int y,const uint clr);
    
    void Fill(int x,int y,const uint clr,const uint threshould);
    

    これらは、平滑化アルゴリズムを持たない単純なメソッドです。パラメータの割り当ては、すでに検討したメソッドのパラメータと同様に実行され、行で構成される同様のプリミティブの作成が含まれます。


    ピクセル形式と色成分

    上記で検討したメソッドに戻り、CreateBitmapメソッドとCreateBitmapLabelメソッドのピクセル形式に注目しましょう。clrfmtパラメータが形式を担当します。このパラメータは、グラフィカルリソース用に作成されたピクセル形式を設定します。この形式は、後で適切なチャートオブジェクトに接続します。CreateBitmapまたはCreateBitmapLabelメソッドを使用してCanvasの作成中にグラフィックリソースに設定されたピクセル形式は、チャートに表示するときのターミナルによる画像処理メソッドに影響します。画像処理メソッドを定義するためにENUM_COLOR_FORMATを参照してみましょう。ここでは、3つの可能な定数値の1つを選択できます。

    ENUM_COLOR_FORMAT

    • COLOR_FORMAT_XRGB_NOALPHA-XRGB形式(アルファチャンネルは無視)
    • COLOR_FORMAT_ARGB_RAW -「生の」ARGB形式(色成分はターミナルで処理されない)
    • COLOR_FORMAT_ARGB_NORMALIZE - ARGB形式(色成分はターミナルで処理されない)

    次に、これらの形式で色成分を提供する順序について考えてみましょう。

    ピクセル形式と色成分

    ここでは、色成分の位置をm_pixelsピクセル配列セルバイトで確認できます。ここで、Rは赤のチャンネル、Gは緑のチャンネル、Bは青のチャンネル、Aはアルファチャンネル、Xは未使用バイトです。uintピクセルデータ型、4バイト。チャンネルごとに1バイト。1バイトには、0から255までの数値を格納できます。バイト値を変更することで、ピクセルの色を設定できます。たとえば、255をRチャンネルに設定し、0をGおよびBチャンネルに設定すると、赤い色が得られます。255をGチャンネルに設定し、残りの値を0に設定すると、緑色になります。Bチャンネルが255に設定され、残りのチャンネルが0に設定されている場合、青色になります。したがって、RGBチャンネル値のさまざまな組み合わせを設定することで、さまざまな色を取得できます。アルファチャンネル値を0(完全に非表示、透明)から255(完全に表示、非透明)に設定することにより、チャート画像のピクセルが重なる効果を作成することにより、ピクセルの非透明性を管理できます。これは、 COLOR_FORMAT_ARGB_NORMALIZE形式で正しく実行できます。次に、色に移り、カラーパレットについて考えてみましょう。

    カラーパレット

    ここでは、各チャンネルのレベルの組み合わせを変更すると、結果の色にどのように影響するかを明確に確認できます。色はRGBおよびHEX形式で提供されます。RGBについてはすでに検討しましたが、HEX は、特にCCanvasを習得する意欲のある初心者プログラマーにとってはいくつかの説明が必要です。0から15までの数を含む16進数システムを考えて、10進数システム(0-9)と比較してみましょう。10進法には、0、1、2、3、4、5、6、7、8、9の記号があります。16進法で9を超える数を表す必要がある場合はAからFまでのラテン文字が使用されます。したがって、16進数システムには、0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、Fの記号のセットがあります。これで、チャンネル値を含むバイトがHEX形式でどのように表示されるかを簡単に理解できます。Cベースのプログラミング言語では、HEXは0x[値]として示されます。したがって、1バイトの範囲は0x00から0xFFまでの値のように見えます。


    CCanvasを使用してグラフィックを作成する例

    ピクセル形式に戻り、CCanvasを適用するアプリケーションの簡単な例を考えてみましょう。さらに、さまざまなピクセル形式で画像の色とアルファチャンネルの値を設定することにより、さまざまなピクセル形式の値を試してみます。最も一般的な形式であるCOLOR_FORMAT_ARGB_NORMALIZEから始めましょう。これを使用して、最初のアプリケーションを開発します。

    CCanvasを使用したシンプルなアプリケーション

    スクリプトを作成し、名前をErase.mq5にします。

    #include <Canvas\Canvas.mqh>
    
    //+------------------------------------------------------------------+
    //| Script program start function                                    |
    //+------------------------------------------------------------------+
    void OnStart()
     {
        CCanvas canvas;
        canvas.CreateBitmapLabel("canvas", 15, 30, 300, 250, COLOR_FORMAT_ARGB_NORMALIZE);
        canvas.Erase(ColorToARGB(clrWhite, 255));
        canvas.Update(true);
        Sleep(6000);
        canvas.Destroy();
     }
    

    最初の文字列には、Canvas.mqhモジュールが含まれていることがわかります。これで、例に示すように、さらに作業するために、CCanvasクラスのインスタンスであるオブジェクトを作成できるようになりました。

    CCanvas  canvas;

    次に、clrfmtパラメータCOLOR_FORMAT_ARGB_NORMALIZEを使用して、Canvas自体を作成します

     canvas.CreateBitmapLabel("canvas", 15, 30, 300, 250, COLOR_FORMAT_ARGB_NORMALIZE);

    そして、Eraseメソッドを使用してそれを埋めます。

     canvas.Erase(ColorToARGB(clrWhite, 255));

    Canvasを作成した後、Updateメソッドを呼び出します。

    canvas.Update(true);

    redraw: trueを使用します。デフォルトで設定されているため、このパラメータはオプションですが、わかりやすくするために設定することをお勧めします。次に、6秒間待ってチャートでアプリケーションを処理した結果を確認します。

    Sleep(6000); 

    次に、Destroyメソッドを呼び出して、グラフィカルリソースとチャートオブジェクトが占有しているメモリを解放します。

    canvas.Destroy();

    次に、スクリプトはその作業を完了します。 結果は下の画像で見ることができます。

    Erase

    ここでは、より複雑なグラフィック構造を描画するための基礎または背景として使用できる塗りつぶされた長方形を見ることができます。

    ピクセル形式とオーバーラップメソッド

    すでに検討した例Erase.mq5を見て、ColorToARGB関数を使用せずに直接色を設定してみましょう。例のコード全体をコピーして、ARGB_NORMALIZE.mq5という名前のスクリプトを作成します。次に、上記のパレットからclrPaleGreenなどの色の1つを選択して、色を設定します。その値をHEX形式で取得し、左側に0xFFアルファチャンネル値を追加します。

    #include <Canvas\Canvas.mqh>
    
    //+------------------------------------------------------------------+
    //| Script program start function                                    |
    //+------------------------------------------------------------------+
    void OnStart()
     {
        CCanvas canvas;
        canvas.CreateBitmapLabel("canvas", 15, 30, 300, 250, COLOR_FORMAT_ARGB_NORMALIZE);
        canvas.Erase(0xFF98FB98);
        canvas.Update(true);
        Sleep(6000);
        canvas.Destroy();
     }
    

    RGB成分はコード内で緑色で強調表示され、A成分は灰色で強調表示されています。スクリプトを起動して結果を確認します。

    COLOR_FORMAT_ARGB_NORMALIZE形式での色の変更

    画像の色がどのように変化したかがわかります。それでは、透明度を変更してみましょう。アルファチャンネル値を0xCCに設定します。

    void OnStart()
     {
        CCanvas canvas;
        canvas.CreateBitmapLabel("canvas", 15, 30, 300, 250, COLOR_FORMAT_ARGB_NORMALIZE);
        canvas.Erase(0xCC98FB98);
        canvas.Update(true);
        Sleep(6000);
        canvas.Destroy();
     }
    

    結果を見てみましょう。

    COLOR_FORMAT_ARGB_NORMALIZE形式での非透明性の変更

    ここでは、塗りつぶされた領域が半透明になっていることがわかります。

    ピクセル形式をCOLOR_FORMAT_ARGB_RAWに変更し、画像を再び完全に不透明にします。これを行うには、別の例(ARGB_RAW.mq5)を作成します。

    void OnStart()
     {
        CCanvas canvas;
        canvas.CreateBitmapLabel("canvas", 15, 30, 300, 250, COLOR_FORMAT_ARGB_RAW);
        canvas.Erase(0xFF98FB98);
        canvas.Update(true);
        Sleep(6000);
        canvas.Destroy();
     }
    

    例を実行して結果を確認します。

    COLOR_FORMAT_ARGB_RAW形式の非透明性

    結果はCOLOR_FORMAT_ARGB_NORMALIZEの結果と変わらないことがわかります。

    アルファチャンネルを0xFBに設定し、チャートの背景色を白に変更します。

    void OnStart()
     {
        ChartSetInteger(0, CHART_COLOR_BACKGROUND, clrWhite);
        CCanvas canvas;
        canvas.CreateBitmapLabel("canvas", 15, 30, 300, 250, COLOR_FORMAT_ARGB_RAW);
        canvas.Erase(0xFB98FB98);
        canvas.Update(true);
        Sleep(6000);
        canvas.Destroy();
     }
    

    ここで見られる変化はわずかで、COLOR_FORMAT_ARGB_NORMALIZEピクセル形式との違いはありません。

    COLOR_FORMAT_ARGB_RAW形式での非透明性の変更

    ただし、アルファチャンネル値を1つ減らすと、

    canvas.Erase(0xFA98FB98);

    最終的な画像のかなりの変化にすぐに気づきます。

    COLOR_FORMAT_ARGB_RAW形式でわずかな非透明性の変更があった場合の画像の変更

    次に、透明度が完全に変更された場合の画像の動作を確認しましょう。これを行うには、新しい例を作成し、ARGB_RAW-2.mq5という名前を付けます。そこに前の例のコードをコピーし、わずかな変更を加えて、アルファチャンネル値が指定された間隔で255から0に変更できるようにします。

    void OnStart()
     {
      ChartSetInteger(0, CHART_COLOR_BACKGROUND, clrWhite);
      CCanvas canvas;
      canvas.CreateBitmapLabel("canvas", 15, 30, 300, 250, COLOR_FORMAT_ARGB_RAW);
      canvas.Erase(0xFF98FB98);
      for(int a = 255; a >= 0; a--)
       {
        canvas.TransparentLevelSet((uchar)a);
        canvas.Update(true);
        Sleep(100);
       }
      canvas.Destroy();
     }
    

    コードからわかるように、アプリケーションは、TrancparentLevelSetメソッドを呼び出して画像全体の透明度を変更することによって透明度を変更するforループ(aループ変数)を備えています。

    canvas.TransparentLevelSet((uchar)a);

    次に、すでにおなじみのUpdateメソッドを呼び出します。

    canvas.Update(true);

    次に、Sleep関数は、ループを100ミリ秒待機させます(これにより、ユーザーは透明度の変化を確認できます)。

    Sleep(100);

    次に、Canvasが削除され、

    canvas.Destroy();

    作業が完了します。結果は下のGIFアニメーションで見ることができます。

    COLOR_FORMAT_ARGB_RAW形式での透明度の完全な変更

    以下の例と、COLOR_FORMAT_ARGB_RAW形式を適用したすべての例から、アルファチャンネル値が255の画像 が正しく表示されていることがわかります。ただし、値を小さくすると、形式にRGBチャンネル値の正規化がないため、画像が歪んでしまいます。チャンネルがいっぱいになり、255を超える過剰な値は単に破棄されるため、アーティファクトと歪みが発生する可能性があります。一方、この形式を使用すると、 COLOR_FORMAT_ARGB_NORMALIZE形式と比較して画像の表示が高速化されます。

    COLOR_FORMAT_ARGB_RAWピクセル形式ARGB_RAW.mq5の使用に関する例に戻りましょう。XRGB_NOALPHA.mq5という名前のスクリプトを作成し、ピクセル形式をCOLOR_FORMAT_XRGB_NOALPHAに設定して、コードをARGB_RAW.mq5からスクリプトにコピーします。また、Eraseメソッドのアルファチャンネル値をゼロに設定します。 

    void OnStart()
     {
        CCanvas canvas;
        canvas.CreateBitmapLabel("canvas", 15, 30, 300, 250, COLOR_FORMAT_XRGB_NOALPHA);
        canvas.Erase(0x0098FB98);
        canvas.Update(true);
        Sleep(6000);
        canvas.Destroy();
     }
    

    スクリプトを起動して結果を確認します。

    COLOR_FORMAT_XRGB_NOALPHA形式で色を重ね合わせる

    ご覧のとおり、結果は、Eraseメソッドの最大アルファチャンネル値(0xFF)を使用したCOLOR_FORMAT_ARGB_NORMALIZEおよびCOLOR_FORMAT_ARGB_RAW形式と同じです。したがって、この形式ではアルファチャンネル値が完全に無視され、画像がチャート画像に単に重ね合わされていることがわかります。 

    テキスト表示

    CCanvasには、TextOutテキストを表示するメソッドが備わっていることがわかっています。テキストを表示してみましょう。スクリプトを作成し、TextOut.mq5という名前を付けます。上記で検討したErase.mq5を、そのコードに対処するための基礎として使用してみましょう。FontSetフォントパラメータを設定するメソッドを追加し、必要な値であるフォント「Calibri」およびフォントサイズ-210を設定します。

    FontSetメソッドとFontSizeSetメソッドでsize のフォントサイズをピクセル単位で設定するには、-10を掛ける必要があります。したがって、フォントサイズが21ピクセルの場合、sizeは-210になります。

    残りのパラメータはデフォルトのままです。次に、 textパラメータ「Text」を使用してTextOutメソッドを追加します。動作例に必要な他のすべての文字列は、コピーされたコードに残ります。

    void OnStart()
     {
        CCanvas canvas;
        canvas.CreateBitmapLabel("canvas", 15, 30, 300, 250, COLOR_FORMAT_ARGB_NORMALIZE);
        canvas.Erase(ColorToARGB(clrWhite, 255));
        canvas.FontSet("Calibri", -210);
        canvas.TextOut(15, 15, "Text", ColorToARGB(clrLightSlateGray, 255));
        canvas.Update(true);
        Sleep(6000);
        canvas.Destroy();
     }
    

    スクリプト操作の結果を見てみましょう。

    TextOutメソッドを使用したテキストの表示

    画像にテキストが表示されます。 

    画像がチャートの中央に正確に表示され、Labelオブジェクト(OBJ_LABEL)を思い出させるように、例を変更してみましょう。スクリプトに基づいて新しい例を作成し、TextOut-2.mq5という名前を付けます。

    void OnStart()
     {
      string text = "Text";
      int width, height;
      const int textXDist = 10, textYDist = 5;
      int canvasX, canvasY;
      CCanvas canvas;
      
      canvas.FontSet("Calibri", -210);
      canvas.TextSize(text, width, height);
      
      canvasX = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0) / 2 - width / 2;
      canvasY = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0) / 2 - height / 2;
      
      canvas.CreateBitmapLabel("canvas", canvasX, canvasY,
                               width + textXDist * 2, height + textYDist * 2,
                               COLOR_FORMAT_ARGB_NORMALIZE);
      canvas.Erase(ColorToARGB(clrWhite, 255));
      canvas.TextOut(textXDist, textYDist, text, ColorToARGB(clrLightSlateGray, 255));
      canvas.Update(true);
      Sleep(6000);
      canvas.Destroy();
     }
    

    コードによると、表示されるテキストはtext変数に設定されています(スクリプトコードで2回アクセスされるため)。

    string text = "Text";

    表示されたテキストサイズを保存するために、width変数とheight変数が宣言されています。

    int width, height;

    宣言された2つの定数textXDisttextYDistは、表示されたテキストのインデントをそれぞれ画像の右端と上端から保存します。

    const int textXDist = 10, textYDist = 5;

    次に、画像座標計算の結果を保存するための2つの宣言された変数canvasXcanvasYがあります。

    int canvasX, canvasY;

    次に、フォントパラメータを定義するFontSetメソッドがあります(事前に設定します)。

    canvas.FontSet("Calibri", -210);

    TextSizeメソッドを使用すると、widthおよびheight変数に保存される表示テキストのサイズを(画像サイズを定義するために)定義できます。

    canvas.TextSize(text, width, height);

    次に、チャートの中央に画像を表示するために使用される画像座標を計算します。

    canvasX = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0) / 2 - width / 2;
    canvasY = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0) / 2 - height / 2;
    

    次に、以前に計算された座標が設定されているCreateBitmapLabelを使用して画像を作成します。

    canvas.CreateBitmapLabel("canvas", canvasX, canvasY,
                               width + textXDist * 2, height + textYDist * 2,
                               COLOR_FORMAT_ARGB_NORMALIZE);
    

    その後、Eraseメソッドを使用して画像を色で塗りつぶします。

    canvas.Erase(ColorToARGB(clrWhite, 255));

    次に、前に設定したtextXDisttextYDist座標を指定するTextOutメソッドを使用して、テキストが表示されます(text)。

    canvas.TextOut(textXDist, textYDist, text, ColorToARGB(clrLightSlateGray, 255));

    次に、説明を必要としない、すでにおなじみの文字列があります。スクリプトを起動して結果を見てみましょう。

    テキストラベルの例

    画像には、テキストラベルに似たオブジェクトが表示されますが、透明な背景を欠いています。背景は、現在のピクセル形式COLOR_FORMAT_ARGB_NORMALIZEで設定できますが、私は別の道を進むことにします。この場合、色を混合する必要がないため、COLOR_FORMAT_ARGB_RAWピクセル形式をCanvasに設定しましょう。一方、形式のアルファチャンネル0および255の色は歪みなく表示されます。アルファチャンネル値が0の色は、最終的な画像には影響しません。前の例に基づいて、LabelExample.mq5スクリプトをコピーします。

    void OnStart()
     {
      string text = "Text";
      int width, height;
      const int textXDist = 10, textYDist = 5;
      int canvasX, canvasY;
      CCanvas canvas;
      
      canvas.FontSet("Calibri", -210);
      canvas.TextSize(text, width, height);
      
      canvasX = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0) / 2 - width / 2;
      canvasY = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0) / 2 - height / 2;
      
      canvas.CreateBitmapLabel("canvas", canvasX, canvasY,
                               width + textXDist * 2, height + textYDist * 2,
                               COLOR_FORMAT_ARGB_RAW);
      canvas.Erase(ColorToARGB(clrWhite, 255));
      canvas.FontSet("Calibri", -210);
      canvas.TextOut(textXDist, textYDist, text, ColorToARGB(clrLightSlateGray, 255));
      canvas.Update(true);
      Sleep(6000);
      canvas.Destroy();
     }
    

    アルファチャンネルは変更されていないため、255のアルファチャンネルでチャートピクセルが完全に再描画されます。

    COLOR_FORMAT_ARGB_RAW形式の確認

    次に、アルファチャンネル値を0に設定しましょう。

    void OnStart()
     {
      string text = "Text";
      int width, height;
      const int textXDist = 10, textYDist = 5;
      int canvasX, canvasY;
      CCanvas canvas;
      
      canvas.FontSet("Calibri", -210);
      canvas.TextSize(text, width, height);
      
      canvasX = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0) / 2 - width / 2;
      canvasY = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0) / 2 - height / 2;
      
      canvas.CreateBitmapLabel("canvas", canvasX, canvasY,
                               width + textXDist * 2, height + textYDist * 2,
                               COLOR_FORMAT_ARGB_RAW);
      canvas.Erase(ColorToARGB(clrWhite, 0));
      canvas.FontSet("Calibri", -210);
      canvas.TextOut(textXDist, textYDist, text, ColorToARGB(clrLightSlateGray, 255));
      canvas.Update(true);
      Sleep(6000);
      canvas.Destroy();
     }
    

    スクリプトを実行して、結果を確認します。

    ラベルアナログ

    テキストラベルのアナログ(OBJ_LABEL)が表示されます。したがって、画像を完全に再描画することなく、画像の上にテキストを表示することができます。これは、コントロールを強調表示したり、テキストデータを表示したりするために、さまざまなUIで広く使用されています。

    平滑化せずに単純なプリミティブを描画する

    DrawPrimitives.mq5を検討して、CCanvasでプリミティブを描画するメソッドを理解しましょう。

    void OnStart()
     {
      CCanvas canvas;
      int w, h;
      int minSize, point;
      uint color_ = ColorToARGB(clrDodgerBlue, 255);
      uint fillColor = ColorToARGB(clrRed, 255);
      int plX[] = {6, 8, 9, 11, 12, 14}, plY[] = {14, 12, 13, 11, 12, 10};
      int pgX[] = {15, 14, 15, 17, 18, 17}, pgY[] = {9, 7, 5, 5, 7, 9};
      w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0);
      h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0);
      minSize = (int)fmin(w, h);
      point = minSize / 15;
      canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA);
      canvas.Erase(ColorToARGB(clrWhite, 255));
      canvas.LineHorizontal(point, w - point, h - point, color_);
      canvas.LineVertical(point, point, h - point, color_);
      canvas.Line(point * 2, point * 13, point * 8, point * 9, color_);
      for (int i = 0; i < (int)plX.Size(); i++)
        plX[i] *= point;
      for (int i = 0; i < (int)plY.Size(); i++)
        plY[i] *= point;
      canvas.Polyline(plX, plY, color_);
      for (int i = 0; i < (int)pgX.Size(); i++)
        pgX[i] *= point;
      for (int i = 0; i < (int)pgY.Size(); i++)
        pgY[i] *= point;
      canvas.Polygon(pgX, pgY, color_);
      canvas.Rectangle(point * 2, point * 5, point * 7, point, color_);
      canvas.Triangle(point * 2, point * 11, point * 2, point * 6, point * 7, point * 6, color_);
      canvas.Circle(point * 10, point * 3, point * 2, color_);
      canvas.Ellipse(point * 8, point * 9, point * 12, point * 6, color_);
      canvas.Arc(point * 15, point * 2, point * 2, point, 45.0 * M_PI / 180, 180.0 * M_PI / 180, color_);
      canvas.Pie(point * 16, point * 3, point * 2, point, 180.0 * M_PI / 180, 402.5 * M_PI / 180, color_, fillColor);
      canvas.Update(true);
      Sleep(6000);
      canvas.Destroy();
     }
    

    すべてのプリミティブは、正方形に沿って便利に描画できます。それらの座標と残りのパラメータは、同じメソッドを使用して便利に設定できます。そこで、CCanvasの画像を同じ幅と高さのパーツに分割し、正方形の座標に1つの正方形のサイズを掛けてピクセルに変換できるように、作業を簡素化することにしました。これを実現するために、チャートのサイズをCCanvasの画像サイズとし、最小サイズの値を15で割りました。

      CCanvas canvas;
      int w, h;
      int minSize, point;
      uint color_ = ColorToARGB(clrDodgerBlue, 255);
      uint fillColor = ColorToARGB(clrRed, 255);
      int plX[] = {6, 8, 9, 11, 12, 14}, plY[] = {14, 12, 13, 11, 12, 10};
      int pgX[] = {15, 14, 15, 17, 18, 17}, pgY[] = {9, 7, 5, 5, 7, 9};
      w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0);
      h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0);
      minSize = (int)fmin(w, h);
      point = minSize / 15;
    

    コードはリストで黄色で強調表示されています。単一の正方形(point変数)のサイズがわかったので、正方形に設定された座標をピクセル単位の実際のサイズに変換できます。例を作成する前に、チャート画像を正方形に分割し、それらを使用してスクリプト内のすべてのプリミティブの座標を設定しました。

    int plX[] = {6, 8, 9, 11, 12, 14}, plY[] = {14, 12, 13, 11, 12, 10};
    int pgX[] = {15, 14, 15, 17, 18, 17}, pgY[] = {9, 7, 5, 5, 7, 9};
    

    ここでは、配列内のポリライン(Polyline)とポリゴン(Polygon)の座標を設定します。次に、それらをピクセルに変換して、ループ内の配列を1つずつ選択し、ポリラインとポリゴンを描画しました。

      for (int i = 0; i < (int)plX.Size(); i++)
        plX[i] *= point;
      for (int i = 0; i < (int)plY.Size(); i++)
        plY[i] *= point;
      canvas.Polyline(plX, plY, color_);
      for (int i = 0; i < (int)pgX.Size(); i++)
        pgX[i] *= point;
      for (int i = 0; i < (int)pgY.Size(); i++)
        pgY[i] *= point;
      canvas.Polygon(pgX, pgY, color_);
    

    プリミティブ描画メソッドを呼び出すためのコードは黄色で強調表示されています。残りのプリミティブは次のように表示されます。

      canvas.Polygon(pgX, pgY, color_);
      canvas.Rectangle(point * 2, point * 5, point * 7, point, color_);
      canvas.Triangle(point * 2, point * 11, point * 2, point * 6, point * 7, point * 6, color_);
      canvas.Circle(point * 10, point * 3, point * 2, color_);
      canvas.Ellipse(point * 8, point * 9, point * 12, point * 6, color_);
      canvas.Arc(point * 15, point * 2, point * 2, point, 45.0 * M_PI / 180, 180.0 * M_PI / 180, color_);
      canvas.Pie(point * 16, point * 3, point * 2, point, 180.0 * M_PI / 180, 402.5 * M_PI / 180, color_, fillColor);
    

    コードからわかるように、すべての座標にpointを掛けて、ピクセルに変換します。スクリプトの結果を考えてみましょう。

    単純なプリミティブ

    変更できない単純な線画スタイル(STYLE_SOLID)のプリミティブを見ることができます。

    平滑化と変更可能な線スタイルを使用したプリミティブの描画

    線のスタイルを変更できるようにするために、アンチエイリアス(AA)を適用する並べ替えアルゴリズムのメソッドを使用します。スクリプトDrawPrimitivesAA.mq5を作成し、前の例のコードをそのスクリプトにコピーします。AAプレフィックス( LineAA、PolylineAA、PolygonAA、TriangleAA、CircleAA、EllipseAA)が付いたCCanvasクラスに存在するすべてのメソッドは、完全に準拠しています。他のメソッドは削除されます。前の例に比べてプリミティブが少なくなっているので、それらの場所を変更できます。

    void OnStart()
     {
      CCanvas canvas;
      int w, h;
      int minSize, point;
      uint color_ = ColorToARGB(clrDodgerBlue, 255);
      uint fillColor = ColorToARGB(clrRed, 255);
      int plX[] = {6, 8, 9, 11, 12, 14}, plY[] = {13, 11, 12, 10, 11, 9};
      int pgX[] = {15, 14, 15, 17, 18, 17}, pgY[] = {7, 5, 3, 3, 5, 7};
      ENUM_LINE_STYLE lineStyle = STYLE_SOLID;
      w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0);
      h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0);
      minSize = (int)fmin(w, h);
      point = minSize / 15;
      canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA);
      canvas.Erase(ColorToARGB(clrWhite, 255));
      canvas.LineStyleSet(lineStyle);
      canvas.LineAA(point * 2, point * 12, point * 8, point * 8, color_);
      for (int i = 0; i < (int)plX.Size(); i++)
        plX[i] *= point;
      for (int i = 0; i < (int)plY.Size(); i++)
        plY[i] *= point;
      canvas.PolylineAA(plX, plY, color_);
      for (int i = 0; i < (int)pgX.Size(); i++)
        pgX[i] *= point;
      for (int i = 0; i < (int)pgY.Size(); i++)
        pgY[i] *= point;
      canvas.PolygonAA(pgX, pgY, color_);
      canvas.TriangleAA(point * 2, point * 9, point * 2, point * 4, point * 7, point * 4, color_);
      canvas.CircleAA(point * 16, point * 11, point * 2, color_);
      canvas.EllipseAA(point * 8, point * 4, point * 12, point * 7, color_);
      canvas.Update(true);
      Sleep(6000);
      canvas.Destroy();
     }
    

    変更された文字列は黄色で強調表示されています。それでは、スクリプトを起動して結果を見てみましょう。

    アンチエイリアシングを使用したプリミティブ

    この画像は、アンチエイリアスを使用したメソッドの結果を示しています。単純なプリミティブを含む前の例と比較して、線はより滑らかに見えます。

    ただし、ここでは線のスタイルはまだSTYLE_SOLIDです。スクリプトDrawPrimitivesAA-2.mq5を作成し、そこに前の例のコードを挿入して、これを修正しましょう。sleepを入力パラメータとして設定し、線のスタイルを変更してプリミティブを表示した後の遅延を設定します。

    #property script_show_inputs
    
    //--- input parameters
    input int sleep = 1000;
    

    すべての描画メソッドはマクロで設定されます。

    #define drawPrimitives canvas.Erase(ColorToARGB(clrWhite, 255));                               \
      canvas.LineAA(point * 2, point * 12, point * 8, point * 8, color_);                          \
      canvas.PolylineAA(plX, plY, color_);                                                         \
      canvas.PolygonAA(pgX, pgY, color_);                                                          \
      canvas.TriangleAA(point * 2, point * 9, point * 2, point * 4, point * 7, point * 4, color_); \
      canvas.CircleAA(point * 16, point * 11, point * 2, color_);                                  \
      canvas.EllipseAA(point * 8, point * 4, point * 12, point * 7, color_);                       \
      canvas.Update(true);                                                                         \
      Sleep(sleep);
    

    次に、LineStyleSetメソッドを使用し、プリミティブを表示して、線画のスタイルを1つずつ変更します。例を見てみましょう。

    #property script_show_inputs
    
    //--- input parameters
    input int sleep = 1000;
    
    //+------------------------------------------------------------------+
    //|                                                                  |
    //+------------------------------------------------------------------+
    #include <Canvas\Canvas.mqh>
    
    //+------------------------------------------------------------------+
    //|                                                                  |
    //+------------------------------------------------------------------+
    #define drawPrimitives canvas.Erase(ColorToARGB(clrWhite, 255));                               \
      canvas.LineAA(point * 2, point * 12, point * 8, point * 8, color_);                          \
      canvas.PolylineAA(plX, plY, color_);                                                         \
      canvas.PolygonAA(pgX, pgY, color_);                                                          \
      canvas.TriangleAA(point * 2, point * 9, point * 2, point * 4, point * 7, point * 4, color_); \
      canvas.CircleAA(point * 16, point * 11, point * 2, color_);                                  \
      canvas.EllipseAA(point * 8, point * 4, point * 12, point * 7, color_);                       \
      canvas.Update(true);                                                                         \
      Sleep(sleep);
    
    //+------------------------------------------------------------------+
    //| Script program start function                                    |
    //+------------------------------------------------------------------+
    void OnStart()
     {
      CCanvas canvas;
      int w, h;
      int minSize, point;
      uint color_ = ColorToARGB(clrDodgerBlue, 255);
      uint fillColor = ColorToARGB(clrRed, 255);
      int plX[] = {6, 8, 9, 11, 12, 14}, plY[] = {13, 11, 12, 10, 11, 9};
      int pgX[] = {15, 14, 15, 17, 18, 17}, pgY[] = {7, 5, 3, 3, 5, 7};
      //ENUM_LINE_STYLE lineStyle;
      w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0);
      h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0);
      minSize = (int)fmin(w, h);
      point = minSize / 15;
      canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA);
      
      for (int i = 0; i < (int)plX.Size(); i++)
        plX[i] *= point;
      for (int i = 0; i < (int)plY.Size(); i++)
        plY[i] *= point;
      for (int i = 0; i < (int)pgX.Size(); i++)
        pgX[i] *= point;
      for (int i = 0; i < (int)pgY.Size(); i++)
        pgY[i] *= point;
      
      canvas.LineStyleSet(STYLE_SOLID);
      drawPrimitives
      canvas.LineStyleSet(STYLE_DOT);
      drawPrimitives
      canvas.LineStyleSet(STYLE_DASH);
      drawPrimitives
      canvas.LineStyleSet(STYLE_DASHDOTDOT);
      drawPrimitives
      
      Sleep(6000);
      canvas.Destroy();
     }
    

    強調表示されたコードフラグメントは、スタイルがどのように変更され、描画メソッドが呼び出されるかを示しています。スクリプトの操作結果を見てみましょう。

    線画スタイルの変更(AA)

    GIFアニメーションは、指定されたsleep間隔でのプリミティブな線のスタイルの変化を示しています。

    ここで、Wuアルゴリズムを使用した描画プリミティブの例を作成することをお勧めします。前の例に基づいて、DrawPrimitivesWu.mq5スクリプトを作成します。AA記号の組み合わせをWuに置き換え、リストに示されているように文字列をコメントアウトします。

    #property script_show_inputs
    
    //--- input parameters
    input int sleep = 1000;
    
    //+------------------------------------------------------------------+
    //|                                                                  |
    //+------------------------------------------------------------------+
    #include <Canvas\Canvas.mqh>
    
    //+------------------------------------------------------------------+
    //|                                                                  |
    //+------------------------------------------------------------------+
    #define drawPrimitives canvas.Erase(ColorToARGB(clrWhite, 255));                               \
      canvas.LineWu(point * 2, point * 12, point * 8, point * 8, color_);                          \
      canvas.PolylineWu(plX, plY, color_);                                                         \
      canvas.PolygonWu(pgX, pgY, color_);                                                          \
      canvas.TriangleWu(point * 2, point * 9, point * 2, point * 4, point * 7, point * 4, color_); \
      canvas.CircleWu(point * 16, point * 11, point * 2, color_);                                  \
      canvas.EllipseWu(point * 8, point * 4, point * 12, point * 7, color_);                       \
      canvas.Update(true);                                                                         \
      Sleep(sleep);
    
    //+------------------------------------------------------------------+
    //| Script program start function                                    |
    //+------------------------------------------------------------------+
    void OnStart()
     {
      CCanvas canvas;
      int w, h;
      int minSize, point;
      uint color_ = ColorToARGB(clrDodgerBlue, 255);
      uint fillColor = ColorToARGB(clrRed, 255);
      int plX[] = {6, 8, 9, 11, 12, 14}, plY[] = {13, 11, 12, 10, 11, 9};
      int pgX[] = {15, 14, 15, 17, 18, 17}, pgY[] = {7, 5, 3, 3, 5, 7};
      //ENUM_LINE_STYLE lineStyle;
      w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0);
      h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0);
      minSize = (int)fmin(w, h);
      point = minSize / 15;
    
      canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA);
      
      for (int i = 0; i < (int)plX.Size(); i++)
        plX[i] *= point;
      for (int i = 0; i < (int)plY.Size(); i++)
        plY[i] *= point;
      for (int i = 0; i < (int)pgX.Size(); i++)
        pgX[i] *= point;
      for (int i = 0; i < (int)pgY.Size(); i++)
        pgY[i] *= point;
    
      canvas.LineStyleSet(STYLE_SOLID);
      drawPrimitives
      //canvas.LineStyleSet(STYLE_DOT);
      //drawPrimitives
      //canvas.LineStyleSet(STYLE_DASH);
      //drawPrimitives
      //canvas.LineStyleSet(STYLE_DASHDOTDOT);
      //drawPrimitives
      
      Sleep(6000);
      canvas.Destroy();
     }
    

    追加されたすべてのメソッドは黄色で強調表示されています。例を実行して結果を確認します。

    Wu平滑化を使用したプリミティブ

    Wuアルゴリズムを使用した平滑化のおかげで、描画品質が再び向上したことがわかります。次に、スクリプト内の文字列のコメントを解除して、再度起動します。

    描画スタイルの変更(Wu)

    線のスタイルは前の例と同じように変更されますが、プリミティブ画像の平滑化の品質は高くなります。

    線幅を変更できる描画プリミティブ

    前の例に基づいてスクリプトを作成し、DrawPrimitivesThick.mq5という名前を付けます。既存のプリミティブ描画メソッドを「Thick」プレフィックスを備えたメソッドに置き換え、リストに表示されている類似物のないメソッドを削除します。前の例のように、不要な文字列をコメントアウトします。

    #property script_show_inputs
    
    //--- input parameters
    input int sleep = 1000;
    
    //+------------------------------------------------------------------+
    //|                                                                  |
    //+------------------------------------------------------------------+
    #include <Canvas\Canvas.mqh>
    
    //+------------------------------------------------------------------+
    //|                                                                  |
    //+------------------------------------------------------------------+
    #define drawPrimitives canvas.Erase(ColorToARGB(clrWhite, 255));                                      \
      canvas.LineThickVertical(point, point, h - point, color_, size, lineStyle, endStyle);               \
      canvas.LineThickHorizontal(point, w - point, h - point, color_, size, lineStyle, endStyle);         \
      canvas.LineThick(point * 2, point * 12, point * 8, point * 8, color_, size, lineStyle, endStyle);   \
      canvas.PolylineThick(plX, plY, color_, size, lineStyle, endStyle);                                  \
      canvas.PolygonThick(pgX, pgY, color_, size, lineStyle, endStyle);                                   \
      canvas.Update(true);                                                                                \
      Sleep(sleep);
    
    //+------------------------------------------------------------------+
    //| Script program start function                                    |
    //+------------------------------------------------------------------+
    void OnStart()
     {
      CCanvas canvas;
      int w, h;
      int minSize, point;
      uint color_ = ColorToARGB(clrDodgerBlue, 255);
      uint fillColor = ColorToARGB(clrRed, 255);
      int plX[] = {6, 8, 9, 11, 12, 14}, plY[] = {13, 11, 12, 10, 11, 9};
      int pgX[] = {17, 18, 17, 15, 14, 15, 17}, pgY[] = {7, 5, 3, 3, 5, 7, 7};
      ENUM_LINE_STYLE lineStyle = STYLE_SOLID;
      int size = 3;
      ENUM_LINE_END endStyle = LINE_END_ROUND;
      w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0);
      h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0);
      minSize = (int)fmin(w, h);
      point = minSize / 15;
      canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA);
      
      for (int i = 0; i < (int)plX.Size(); i++)
        plX[i] *= point;
      for (int i = 0; i < (int)plY.Size(); i++)
        plY[i] *= point;
      for (int i = 0; i < (int)pgX.Size(); i++)
        pgX[i] *= point;
      for (int i = 0; i < (int)pgY.Size(); i++)
        pgY[i] *= point;
    
      canvas.LineStyleSet(STYLE_SOLID);
      drawPrimitives
      //canvas.LineStyleSet(STYLE_DOT);
      //drawPrimitives
      //canvas.LineStyleSet(STYLE_DASH);
      //drawPrimitives
      //canvas.LineStyleSet(STYLE_DASHDOTDOT);
      drawPrimitives
      
      Sleep(6000);
      canvas.Destroy();
     }
    

    追加されたメソッドは黄色で強調表示されています。すでにお気づきかもしれませんが、ここで検討するメソッドには、size(線幅)とend_style(線補完スタイル)の2つの追加パラメータがあります。スクリプトを実行して、結果を確認します。

    プリミティブの表示(Thick)

    この画像は、上記のように幅を変更できる太い線のプリミティブを示しています。前のスクリプトに基づいてスクリプトを作成し、DrawPrimitivesThick-2.mq5という名前を付けます。これにより、線幅、線スタイル、線補完スタイルのすべての可能な組み合わせを確認できます。実現するには、以前にコメントアウトした文字列をアンコメントしてmethod1マクロに追加します。ここで、行の補完スタイルを変更し、変更するたびにmethod0マクロを呼び出します。method0マクロでプリミティブ描画メソッドを呼び出します。drawPrimitivesマクロでは、線のスタイルを変更し、線のスタイルを変更するたびにmethod1を呼び出します。drawPrimitivesマクロは、指定された範囲で線幅が変更されるループで呼び出されます。

    #property script_show_inputs
    
    //--- input parameters
    input int sleep = 1000;
    input int beginSize = 1;
    input int endSize = 4;
    
    //+------------------------------------------------------------------+
    //|                                                                  |
    //+------------------------------------------------------------------+
    #include <Canvas\Canvas.mqh>
    
    //+------------------------------------------------------------------+
    //|                                                                  |
    //+------------------------------------------------------------------+
    #define drawPrimitives lineStyle = STYLE_SOLID; \
      method1                                       \
      lineStyle = STYLE_DOT;                        \
      method1                                       \
      lineStyle = STYLE_DASH;                       \
      method1                                       \
      lineStyle = STYLE_DASHDOTDOT;                 \
      method1 
      
    #define method1 endStyle = LINE_END_ROUND; \
      method0                                  \
      endStyle = LINE_END_BUTT;                \
      method0                                  \
      endStyle = LINE_END_SQUARE;              \
      method0
    
    #define method0 canvas.Erase(ColorToARGB(clrWhite, 255));                                                                                                      \
      canvas.LineThickVertical(point, point, h - point, color_, size, lineStyle, endStyle);                                                                        \
      canvas.LineThickHorizontal(point, w - point, h - point, color_, size, lineStyle, endStyle);                                                                  \
      canvas.LineThick(point * 2, point * 12, point * 8, point * 8, color_, size, lineStyle, endStyle);                                                            \
      canvas.PolylineThick(plX, plY, color_, size, lineStyle, endStyle);                                                                                           \
      canvas.PolygonThick(pgX, pgY, color_, size, lineStyle, endStyle);                                                                                            \
      canvas.TextOut(point * 2, point, "Size: " + (string)size + "; Style: " + EnumToString(lineStyle) + "; End Style: " + EnumToString(endStyle) + ";", color_);  \
      canvas.Update(true);                                                                                                                                         \
      Sleep(sleep);
    
    //+------------------------------------------------------------------+
    //| Script program start function                                    |
    //+------------------------------------------------------------------+
    void OnStart()
     {
      CCanvas canvas;
      int w, h;
      int minSize, point;
      uint color_ = ColorToARGB(clrDodgerBlue, 255);
      uint fillColor = ColorToARGB(clrRed, 255);
      int plX[] = {6, 8, 9, 11, 12, 14}, plY[] = {13, 11, 12, 10, 11, 9};
      int pgX[] = {17, 18, 17, 15, 14, 15, 17}, pgY[] = {7, 5, 3, 3, 5, 7, 7};
      ENUM_LINE_STYLE lineStyle = STYLE_SOLID;
      int size = 3;
      ENUM_LINE_END endStyle = LINE_END_ROUND;
      w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0);
      h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0);
      minSize = (int)fmin(w, h);
      point = minSize / 15;
      canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA);
      canvas.FontSet("Calibri", -120);
      
      for (int i = 0; i < (int)plX.Size(); i++)
        plX[i] *= point;
      for (int i = 0; i < (int)plY.Size(); i++)
        plY[i] *= point;
      for (int i = 0; i < (int)pgX.Size(); i++)
        pgX[i] *= point;
      for (int i = 0; i < (int)pgY.Size(); i++)
        pgY[i] *= point;
    
      for (int i = beginSize; i <= endSize; i++) {
        size = i;
        drawPrimitives
      }
      
      Sleep(6000);
      canvas.Destroy();
     }
    //+------------------------------------------------------------------+
    

    すべてのコード変更は黄色で強調表示されています。結果のスクリプトは、beginSizeおよびendSize入力パラメータから線幅の範囲を取得し、マクロを使用してすべての可能な線のスタイルと補完の組み合わせオプションに沿って移動します。その結果、スクリプトを実行することで組み合わせを確認できる、考えられるすべてのプリミティブラインパラメータの列挙を取得します。次のGIFアニメーションは、スクリプト操作の結果を示しています。

    異なるパラメータを持つプリミティブ

    アニメーションは、線幅、線スタイル、線補完スタイルの変化を示しています。これらのパラメータはすべてCanvasに表示され、確認できます。

    線幅を変更できるベジェアルゴリズムに従った、平滑化されたプリミティブの描画

    前の例の1つであるDrawPrimitivesThick.mq5を使用して、スクリプトDrawPrimitivesSmooth.mq5を作成しましょう。スクリプトで、PolylineThickとPolygonThickを PolylineSmoothPolygonSmoothに置き換えます。プリミティブがほぼ中央に表示されるように、ポリラインとポリゴンの座標を2マス左に移動します。

    void OnStart()
     {
      CCanvas canvas;
      int w, h;
      int minSize, point;
      uint color_ = ColorToARGB(clrDodgerBlue, 255);
      uint fillColor = ColorToARGB(clrRed, 255);
      int plX[] = {3, 5, 6, 8, 9, 11}, plY[] = {13, 11, 12, 10, 11, 9};
      int pgX[] = {14, 15, 14, 12, 11, 12}, pgY[] = {7, 5, 3, 3, 5, 7};
    

    変更された値はコードで強調表示されています。結果のスクリプトは次のようになります。

    #property script_show_inputs
    
    //--- input parameters
    input int sleep = 1000;
    
    //+------------------------------------------------------------------+
    //|                                                                  |
    //+------------------------------------------------------------------+
    #include <Canvas\Canvas.mqh>
    
    //+------------------------------------------------------------------+
    //|                                                                  |
    //+------------------------------------------------------------------+
    #define drawPrimitives canvas.Erase(ColorToARGB(clrWhite, 255));                                      \
      canvas.PolylineSmooth(plX, plY, color_, size, lineStyle, endStyle);                                 \
      canvas.PolygonSmooth(pgX, pgY, color_, size, lineStyle, endStyle);                                  \
      canvas.Update(true);                                                                                \
      Sleep(sleep);
    
    //+------------------------------------------------------------------+
    //| Script program start function                                    |
    //+------------------------------------------------------------------+
    void OnStart()
     {
      CCanvas canvas;
      int w, h;
      int minSize, point;
      uint color_ = ColorToARGB(clrDodgerBlue, 255);
      uint fillColor = ColorToARGB(clrRed, 255);
      int plX[] = {3, 5, 6, 8, 9, 11}, plY[] = {13, 11, 12, 10, 11, 9};
      int pgX[] = {14, 15, 14, 12, 11, 12}, pgY[] = {7, 5, 3, 3, 5, 7};
      ENUM_LINE_STYLE lineStyle = STYLE_SOLID;
      int size = 3;
      ENUM_LINE_END endStyle = LINE_END_BUTT;
      w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0);
      h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0);
      minSize = (int)fmin(w, h);
      point = minSize / 15;
      canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA);
      
      for (int i = 0; i < (int)plX.Size(); i++)
        plX[i] *= point;
      for (int i = 0; i < (int)plY.Size(); i++)
        plY[i] *= point;
      for (int i = 0; i < (int)pgX.Size(); i++)
        pgX[i] *= point;
      for (int i = 0; i < (int)pgY.Size(); i++)
        pgY[i] *= point;
    
      canvas.LineStyleSet(STYLE_SOLID);
      drawPrimitives
      
      Sleep(6000);
      canvas.Destroy();
     }
    

    例を実行して結果を確認します。

    ベジェアルゴリズムプリミティブ(スムーズ)

    ベジェ曲線を使用して作成されたポリラインとポリゴンを確認できます。PolylineSmoothメソッドとPolygonSmoothメソッドは、張力パラメータ(ベジェ曲線が基づいている平滑化およびステップ(近似ステップ))を特徴としています。これらのパラメータが指定された間隔の後に変更され、画面にこれらの変更の結果が表示される例を作成してみましょう。DrawPrimitivesThick-2.mq5の例を使用して、それに基づいてDrawPrimitivesSmooth-2.mq5スクリプトを作成しましょう。結果を見てみましょう。

    #property script_show_inputs
    
    //+------------------------------------------------------------------+
    //|                                                                  |
    //+------------------------------------------------------------------+
    #include <Canvas\Canvas.mqh>
    
    //--- input parameters
    input int sleep = 1000;
    input int lineSize = 3;
    input ENUM_LINE_STYLE lineStyle = STYLE_SOLID;
    input ENUM_LINE_END lineEndStyle = LINE_END_BUTT;
    input double minTension = 0.0;
    input double stepTension = 0.1;
    input double maxTension = 1.0;
    input double minStep = 1.0;
    input double stepStep = 5.0;
    input double maxStep = 21.0;
    
    //+------------------------------------------------------------------+
    //| Script program start function                                    |
    //+------------------------------------------------------------------+
    void OnStart()
     {
      CCanvas canvas;
      int w, h;
      int minSize, point;
      uint color_ = ColorToARGB(clrDodgerBlue, 255);
      uint fillColor = ColorToARGB(clrRed, 255);
      int plX[] = {3, 5, 6, 8, 9, 11}, plY[] = {13, 11, 12, 10, 11, 9};
      int pgX[] = {14, 15, 14, 12, 11, 12}, pgY[] = {7, 5, 3, 3, 5, 7};
      ENUM_LINE_STYLE style = lineStyle;
      int size = lineSize;
      ENUM_LINE_END endStyle = lineEndStyle;
      w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0);
      h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0);
      minSize = (int)fmin(w, h);
      point = minSize / 15;
      canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA);
      canvas.FontSet("Calibri", -120);
      
      for (int i = 0; i < (int)plX.Size(); i++)
        plX[i] *= point;
      for (int i = 0; i < (int)plY.Size(); i++)
        plY[i] *= point;
      for (int i = 0; i < (int)pgX.Size(); i++)
        pgX[i] *= point;
      for (int i = 0; i < (int)pgY.Size(); i++)
        pgY[i] *= point;
    
      for (double tension = minTension; tension <= maxTension; tension += stepTension)
        for (double step = minStep; step <= maxStep; step += stepStep)
         {
           canvas.Erase(ColorToARGB(clrWhite, 255));
           canvas.PolylineSmooth(plX, plY, color_, size, style, endStyle, tension, step);
           canvas.PolygonSmooth(pgX, pgY, color_, size, style, endStyle, tension, step);
           canvas.TextOut(point * 2, point, "Size: " + (string)size + "; Style: " + EnumToString(style) + "; End Style: " + EnumToString(endStyle) + ";", color_);
           canvas.TextOut(point * 2, point * 2, "Tension: " + DoubleToString(tension, 2) + ";" + " Step: " + DoubleToString(step, 2) + ";", color_);
           canvas.Update(true);
           Sleep(sleep);
         }
      
      canvas.Destroy();
     }
    

    ご覧のとおり、コードはほぼ完全に変更されています。入力パラメータには、線サイズのlineSize、線スタイルのlineStyle、線補完スタイルのlineEndStyleの設定が含まれています(現在は ループに参加していない)。さらに、ベジェ曲線の描画パラメータを設定するための入力パラメータもあります。これらは、minTensionmaxTensionstepTension(張力平滑化パラメータ範囲と値ステップ)、minStepmaxStepstepStep(step近似ステップ範囲と値ステップ)です。さらに、これらのパラメータはループで機能し、指定されたstepTensionおよびstepStepに従ってすべての可能なtensionおよびstepパラメータの組み合わせを設定します。 例を実行して、結果を確認します。

    異なるパラメータを持つプリミティブ

    GIFアニメーションは、変更可能な平滑化パラメータを使用して平滑化されたプリミティブを表示します。その値は、画像の2行目に表示されます。

    塗りつぶされたプリミティブを描画する

    グラフィカルアプリケーションを開発するときは、プリミティブを埋めることができます。CCanvasクラスは、その場合にFillプレフィックスが付いたメソッドを備えています。これらのメソッドは、適切なプリミティブを均一な色でペイントします。前の例のDrawPrimitivesWu.mq5を使用して、必要なプリミティブのすべての座標を特徴とするスクリプト DrawPrimitivesFill.mq5を作成し、適切なメソッドを挿入して塗りつぶしの色を設定するだけでよいようにします。FillPolygonFillTriangleFillCircle FillEllipseメソッドを挿入します。塗りつぶしメソッドを以下に説明します(塗りつぶしを検討する場合)。結果のコードを見てみましょう。

    void OnStart()
     {
      CCanvas canvas;
      int w, h;
      int minSize, point;
      uint fillColor = ColorToARGB(clrRed, 255);
      int pgX[] = {4, 5, 7, 8, 7, 5}, pgY[] = {12, 10, 10, 12, 14, 14};
      w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0);
      h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0);
      minSize = (int)fmin(w, h);
      point = minSize / 15;
      canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA);
      
      for (int i = 0; i < (int)pgX.Size(); i++)
        pgX[i] *= point;
      for (int i = 0; i < (int)pgY.Size(); i++)
        pgY[i] *= point;
    
      canvas.Erase(ColorToARGB(clrWhite, 255));
      canvas.FillPolygon(pgX, pgY, fillColor);
      canvas.FillTriangle(point * 4, point * 8, point * 4, point * 3, point * 9, point * 3, fillColor); 
      canvas.FillCircle(point * 13, point * 12, point * 2, fillColor);
      canvas.FillEllipse(point * 11, point * 3, point * 15, point * 6, fillColor);
      canvas.Update(true);                                                                         
      
      Sleep(6000);
      canvas.Destroy();
     }
    

    変更および追加されたすべての文字列は黄色で強調表示されています。スクリプトを起動して結果を確認します。

    塗りつぶされたプリミティブ(塗りつぶし) 

    この画像は、均一な色で塗りつぶされたプリミティブを示しています。それらの上に、通常のプリミティブを境界線として、または上記で検討した編集可能な線のスタイルを持つプリミティブを描画できます。

    塗りつぶし

    グラフィカルエディタで塗りつぶしツールを使用したことがある場合、お話しすることをすでにご存じかもしれません。上記の塗りつぶしのメソッドを見てみましょう。これは、特定の色の画像領域を別の色で塗りつぶすことができるメソッドです。指標として新しい例を作成しましょう(スクリプトとは対照的に、チャートイベント(OnChartEvent)を処理するため)。チャートイベントをここで処理する必要がある理由を尋ねられるかもしれません。塗りつぶしの色を選択し、任意の画像ポイントをクリックして選択した色で塗りつぶすことができる例を作成します。新しい指標を作成し、Filling.mq5という名前を付けます。指標コードを見てみましょう。

    #property indicator_chart_window
    #property indicator_plots 0
    
    //+------------------------------------------------------------------+
    //|                                                                  |
    //+------------------------------------------------------------------+
    #include <Canvas\Canvas.mqh>
    #include <ChartObjects\ChartObjectsTxtControls.mqh>
    
    //+------------------------------------------------------------------+
    //|                                                                  |
    //+------------------------------------------------------------------+
    CCanvas canvas;
    CChartObjectButton colors[14];
    CChartObjectButton * oldSelected = NULL;
    uint fillColor = 0;
    
    //+------------------------------------------------------------------+
    //| Custom indicator initialization function                         |
    //+------------------------------------------------------------------+
    int OnInit()
     {
      int w, h;
      int minSize, point;
      uint Color1 = ColorToARGB(clrDodgerBlue, 255);
      uint Color2 = ColorToARGB(clrRed, 255);
      int pgX[] = {4, 5, 7, 8, 7, 5}, pgY[] = {12, 10, 10, 12, 14, 14};
      w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0);
      h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0);
      minSize = (int)fmin(w, h);
      point = minSize / 15;
    
      canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA);
      
      canvas.FontSet("Calibri", -120);
      
      for (int i = 0; i < (int)pgX.Size(); i++)
        pgX[i] *= point;
      for (int i = 0; i < (int)pgY.Size(); i++)
        pgY[i] *= point;
    
      canvas.Erase(ColorToARGB(clrWhite, 255));
      canvas.Polygon(pgX, pgY, Color1);
      canvas.FillTriangle(point * 4, point * 8, point * 4, point * 3, point * 9, point * 3, Color2);
      canvas.FillCircle(point * 13, point * 12, point * 2, Color2);
      canvas.Ellipse(point * 11, point * 3, point * 15, point * 6, Color1);
      canvas.Update(true); 
      
      ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
      
      for (int i = 0; i < (int)colors.Size(); i++)
       {
        colors[i].Create(0, "color-"+(string)i, 0, (int)((i + 2.8) * point), point, 21, 21);
        colors[i].SetInteger(OBJPROP_BGCOLOR, ColorToARGB(CCanvas::GetDefaultColor(i), 0));
       }
      
      if ((oldSelected = GetPointer(colors[(int)colors.Size()-1])) == NULL)
        return(INIT_FAILED); 
      oldSelected.State(1);  
      fillColor = ColorToARGB((color)oldSelected.GetInteger(OBJPROP_BGCOLOR), 255);
      
      return(INIT_SUCCEEDED);
     }
     
    //+------------------------------------------------------------------+
    //| Custom indicator deinitialization function                       |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
     {
      canvas.Destroy();
     }
     
    //+------------------------------------------------------------------+
    //| Custom indicator iteration function                              |
    //+------------------------------------------------------------------+
    int OnCalculate(const int rates_total,
                    const int prev_calculated,
                    const int begin,
                    const double &price[])
     {
    //---
    //--- return value of prev_calculated for next call
      return(rates_total);
     }
    //+------------------------------------------------------------------+
    //| ChartEvent function                                              |
    //+------------------------------------------------------------------+
    void OnChartEvent(const int id,
                      const long &lparam,
                      const double &dparam,
                      const string &sparam)
     {
      uint mouseState = (uint)sparam;
      int x = (int)lparam, y = (int)dparam;
      CChartObjectButton * colorBtn;
      int left, right, bottom, top;
      
      if (id == CHARTEVENT_MOUSE_MOVE) 
        if ((mouseState & 1) == 1) 
         {
          for (int i = 0; i < (int)colors.Size(); i++) 
           {
            if ((colorBtn = GetPointer(colors[i])) == NULL)
              return;
            left = colorBtn.X_Distance();
            top = colorBtn.Y_Distance();
            right = left + colorBtn.X_Size() - 1;
            bottom = top + colorBtn.Y_Size() - 1;
            if (x >= left && x <= right && y >= top && y <= bottom) {
              fillColor = ColorToARGB((color)colorBtn.GetInteger(OBJPROP_BGCOLOR), 255);
              if (oldSelected == NULL)
                return;
              oldSelected.State(0);
              oldSelected = GetPointer(colorBtn);
              ChartRedraw();
              return;
            }
           }
          canvas.Fill(x, y, fillColor);
          canvas.Update(true);
         }
        
     }
    

    例はどのように機能するでしょうか。まず、canvas変数がグローバルレベルで指定され、指標操作の全期間にわたってアクセスできるようになりました。

    CCanvas canvas;

    14個のボタンの配列により、色を選択できます。ボタンの1つを押すと、塗りつぶしの色が定義されます。

    CChartObjectButton colors[14];

    次に、oldSelectedポインタが宣言されました。

    CChartObjectButton * oldSelected = NULL;

    次のパラメータは、押されたボタンを保存したり、開始位置に戻したり、塗りつぶしの色を保存したりするために使用されます。

    uint fillColor = 0;

    次に、OnInitハンドラで、Canvasを作成し、その上にプリミティブを描画する、すでにおなじみのコードを確認できます。

    int OnInit()
     {
      int w, h;
      int minSize, point;
      uint Color1 = ColorToARGB(clrDodgerBlue, 255);
      uint Color2 = ColorToARGB(clrRed, 255);
      int pgX[] = {4, 5, 7, 8, 7, 5}, pgY[] = {12, 10, 10, 12, 14, 14};
      w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0);
      h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0);
      minSize = (int)fmin(w, h);
      point = minSize / 15;
      canvas.CreateBitmapLabel("canvas", 0, 0, w, h, COLOR_FORMAT_XRGB_NOALPHA);
      
      canvas.FontSet("Calibri", -120);
      
      for (int i = 0; i < (int)pgX.Size(); i++)
        pgX[i] *= point;
      for (int i = 0; i < (int)pgY.Size(); i++)
        pgY[i] *= point;
    
      canvas.Erase(ColorToARGB(clrWhite, 255));                                                                                                                 
      canvas.Polygon(pgX, pgY, Color1);                                                          
      canvas.FillTriangle(point * 4, point * 8, point * 4, point * 3, point * 9, point * 3, Color2); 
      canvas.FillCircle(point * 13, point * 12, point * 2, Color2);                                  
      canvas.Ellipse(point * 11, point * 3, point * 15, point * 6, Color1);                     
      canvas.Update(true);
    ...
    

    その後、マウスイベントの処理が有効になります。

    ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);

    次に、さまざまな色のボタンを作成します(塗りつぶしの色を変更するため)。

      for (int i = 0; i < (int)colors.Size(); i++)
       {
        colors[i].Create(0, "color-"+(string)i, 0, (int)((i + 2.8) * point), point, 21, 21);
        colors[i].SetInteger(OBJPROP_BGCOLOR, ColorToARGB(CCanvas::GetDefaultColor(i), 0));
       }
    

    ボタンの色がどこから取られているかに注意してください。コードフラグメントは黄色で強調表示されています。CCanvas::GetDefaultColor統計メソッドを確認できます。0から始まるiパラメータを設定することで、カラーパレットを取得できます。

    次にoldSelectedボタンを開始位置に移動するためのリンクを初期化します。

      if ((oldSelected = GetPointer(colors[(int)colors.Size()-1])) == NULL)
        return(INIT_FAILED); 
      oldSelected.State(1);
    

    fillColorの塗りつぶし色が初期化されます。

    fillColor = ColorToARGB((color)oldSelected.GetInteger(OBJPROP_BGCOLOR), 255);

    次に、チャートイベントはOnChartEventで処理されます。マウスパラメータを受信および保存するための変数は、その中で宣言されています。

    void OnChartEvent(const int id,
                      const long &lparam,
                      const double &dparam,
                      const string &sparam)
     {
      uint mouseState = (uint)sparam;
      int x = (int)lparam, y = (int)dparam;
    ...
    

    次に、変数が宣言されます。これは、押されたボタンを格納するためのポインタです。

    CChartObjectButton * colorBtn;

    は、ボタンを左クリックしたときにカーソルがボタンの側面の座標を入力することによって定義されます。辺の座標は、次の変数に格納されます。

    int left, right, bottom, top;

    次に、CHARTEVENT_MOUSE_MOVEイベントとマウスの左ボタンのクリックイベントが追跡されます。

      if (id == CHARTEVENT_MOUSE_MOVE) 
        if ((mouseState & 1) == 1) 
         {
          ...
         }
    

    これは、色の選択と画像の塗りつぶしが実行されるコードです。ここで、ループは、ユーザーが押したボタンを定義するcolors配列内のすべてのボタンを1つずつ通過し、ボタンの色をfillColor変数に保存し、前に押したボタン oldSelectedを開始位置に移動します。次に、塗りつぶす画像ではなくボタンをクリックしたので、ハンドラを終了します(return)。ボタンの1つではなく、画像をクリックすると、コントロールがさらに渡され、Fillメソッドと選択したfillColorとその後の画像アップデートを使用して塗りつぶしが実行されます。

      if (id == CHARTEVENT_MOUSE_MOVE) 
        if ((mouseState & 1) == 1) 
         {
          for (int i = 0; i < (int)colors.Size(); i++) 
           {
            if ((colorBtn = GetPointer(colors[i])) == NULL)
              return;
            left = colorBtn.X_Distance();
            top = colorBtn.Y_Distance();
            right = left + colorBtn.X_Size() - 1;
            bottom = top + colorBtn.Y_Size() - 1;
            if (x >= left && x <= right && y >= top && y <= bottom) {
              fillColor = ColorToARGB((color)colorBtn.GetInteger(OBJPROP_BGCOLOR), 255);
              if (oldSelected == NULL)
                return;
              oldSelected.State(0);
              oldSelected = GetPointer(colorBtn);
              ChartRedraw();
              return;
            }
           }
          canvas.Fill(x, y, fillColor);
          canvas.Update(true);
         }
    

    結果の例を実行して、塗りつぶしを実行してみましょう。

    CCanvasへの塗りつぶし

    GIFアニメーションによると、グラフィカルエディタの塗りつぶしツールと同様に機能するCCanvasを使用して塗りつぶしを作成しました。


    終わりに

    この記事では、CCanvasクラスについて説明し、ユーザーがクラス操作の原則を完全に理解できるようにそのメソッドについて説明しました。提供された例は、理解するのが難しいいくつかの理論的側面を明らかにしながら、CCanvasクラスを処理する原理を説明しています。


    MetaQuotes Ltdによってロシア語から翻訳されました。
    元の記事: https://www.mql5.com/ru/articles/10361

    添付されたファイル |
    MQL5.zip (21.43 KB)
    エキスパートアドバイザーが失敗する理由の分析 エキスパートアドバイザーが失敗する理由の分析
    この記事では、通貨データの分析を示して、エキスパートアドバイザーが特定の時間領域で良好なパフォーマンスを示し他の領域でパフォーマンスが低下する理由をよりよく理解します。
    MVCデザインパターンとその可能なアプリケーション(第2部): 3つのコンポーネント間の相互作用の図 MVCデザインパターンとその可能なアプリケーション(第2部): 3つのコンポーネント間の相互作用の図
    本稿は、前の記事で説明したMQLプログラムのMVCパターンのトピックの続きです。この記事では、パターンの3つのコンポーネント間の可能な相互作用の図を検討します。
    単一チャート上の複数インジケータ(第04部): エキスパートアドバイザーに進む 単一チャート上の複数インジケータ(第04部): エキスパートアドバイザーに進む
    以前の記事では、複数のサブウィンドウでインジケータを作成する方法を説明しました。これは、カスタムインジケータを使用するときに興味深いものになります。今回は、エキスパートアドバイザーに複数のウィンドウを追加する方法を説明します。
    DoEasyライブラリのグラフィックス(第95部):複合グラフィカルオブジェクトコントロール DoEasyライブラリのグラフィックス(第95部):複合グラフィカルオブジェクトコントロール
    本稿では、複合グラフィカルオブジェクトを管理するためのツールキット(拡張された標準グラフィカルオブジェクトを管理するためのコントロール)について検討します。今日は、複合グラフィカルオブジェクトの再配置から少し脱線して、複合グラフィカルオブジェクトを特徴とするチャートに変更イベントのハンドラを実装します。さらに、複合グラフィカルオブジェクトを管理するためのコントロールに焦点を当てます。