English Русский 中文 Español Deutsch Português
初心者のためのMQL5:グラフィックオブジェクトのアンチバンダルプロテクト

初心者のためのMQL5:グラフィックオブジェクトのアンチバンダルプロテクト

MetaTrader 5インディケータ | 11 7月 2016, 10:27
1 415 0
Dina Paches
Dina Paches

ヴァンダリズム (vandalism) とは、
芸術品・公共物・私有財産を含む、美しいものや尊ぶべきものを、
汚染する行為のこと。

ウィキペディア

コンテンツ


1. イントロダクション

MQL5の利点は、既存のMQL5標準機能でさまざまなタスクを完了し、ターミナルを使用する際に別の目標を達成するコードを作ることができる点です。

シンプルな例によるこの記事では、コントロールパネルのグラフィックオブジェクトに対するプログラムの応答アクションが2種類実装されています。誰かが名前を変更してしまった場合、プログラムが削除された後に制御を失う可能性があります。

例として、オブジェクトのプロパティが手動で変更されました場合を考えます。

図1. 例として、オブジェクトのプロパティを手動で変更

例えば、第三者によるプログラムで、意図的なものでないにせよ、チャートの起動時にすべてを ObjectsDeleteAll()クリーンアップする可能性があります:

  • 手動または他のプログラムを使用して作成したオブジェクトと同じウィンドウ/サブウィンドウにあるすべてのグラフィックオブジェクトの完全な除去。
  • あるいはまた、プログラムのコントロールパネル内に存在するオブジェクトの種類を完全に除去。
  • または接頭辞による除去プログラムのオブジェクトのプレフィックスと一致。
これらは偶発的または意図的に起こりえます。

また、この記事では、シンプルに OnChartEvent()のイベント処理を学び始めた人に役立ちます。

この記事では、許可なく変更、もしくは削除されたオブジェクトの「好戦的な」リアクションの作成は扱っていません。ターミナルプログラムの主な目的は、トレーダーが意図しないロボットの介入を解決するということです。

好戦的なアクションを好む人のために、この動きを検討する前に、次の類推をしたいと思います。オフィスクリーナーが、きれいになると信じて、誰かのデスクにあるコンピュータをモップできれいにしたとします。これに対して、所有者がオフィスクリーナーとオフィス内に存在する機器、家具を放り投げるのであれば、その動きは不適切とみなされます。それに加えて、攻撃的な行動をしている人は、このような状況の恩恵を受けることはほとんどありません。

オブジェクトに向かって荒らしに反応することが可能な方法(多くのうち)の例に進む前に、MQL5/ MQL4でプライマリ・オブジェクトのプロテクトの言及をすることも有用であると考えています。


2. MQL5/ MQL4におけるプライマリ・オブジェクトのプロテクト

プログラム・オブジェクトのプロパティを作成するためのアクセスは、このプロテクトなしで、よりオープンになります。

これが何を意味するのか説明しましょう。そのプロパティを介して削除または変更されることから、オブジェクトへの主要なプロテクトを提供するために OBJPROP_HIDDENがあり、明示的に使用することができます。ターミナルのメニューからオブジェクトのリストにグラフィックオブジェクト名を表示するための禁止機能を削除します。チャート- >オブジェクト- >オブジェクトの一覧。デフォルトでは、禁止機能は、カレンダーイベント、取引履歴を表示するオブジェクト、 MQL5プログラムで作成されたオブジェクトに対して設定されます。

(デフォルトで設定されていない)、明示的な禁止機能は、コードに次のスキームを持つことができます。

ObjectSetInteger(chart_id,name,OBJPROP_HIDDEN,true);

ただし、:

  • ObjectSetIntegerは、オブジェクトの関連プロパティの値を設定する関数です。
  • chart_id(現在のチャートのゼロ)オブジェクトが配置されているチャートを識別する;
  • nameは、適用されるオブジェクト名です;
  • OBJPROP HIDDENtrueが、リストにオブジェクトを非表示にし、(falseが取り消し)。

コード内で、この方式の実用的な実装と一貫性がドキュメントに記載されています。オブジェクトの種類一覧から任意のリンクをクリックすると、オブジェクトを作成するための関数の例を見ることができます。

オブジェクトのリストでグラフィックオブジェクト名を表示する禁止機能を持っているオブジェクトを明示的に設定するか、またはデフォルトで、すべてのボタンを押します。これは、オブジェクトの一覧を通じて、手動での介入からグラフィックオブジェクトを守ります。

「すべて」ボタンを押す前の、チャート上のオブジェクトのリスト

図2. 「すべて」ボタンを押す前の、カート上のオブジェクトのリスト

「すべて」ボタンを押した後の、チャート上のオブジェクトのリスト

図3. 「すべて」ボタンを押した後の、チャート上のオブジェクトのリスト

グラフィックオブジェクトを完全に非表示にする場合であっても、チャート上で非表示にすることができないという事実は、むしろ有利です。複数のオブジェクトと前の年のバーが含まれていてもよいグラフ全体をチェックせずに、表示、変更、またはリストをオブジェクトの「プロパティで何かをコピーすることができます。また、リスト内のオブジェクトは、タイプ、名前および他のいくつかのパラメータによって選別することができます。

メタトレーダー5とメタトレーダー4の多くの利点は、ターミナルに自動化アシスタントを書き込み、他の人が作成した複数のアシスタントを使用できる簡単さです。しかし、間違いはありませんか?しかも、書き込みプログラムの準備レベルが異なっている可能性もあります。よって内部の倫理的な境界線とすることができます。プログラミング言語は、人によって変更される可能性があり、時間とともに改善されます。

したがって、任意の時点でプログラムとグラフィックオブジェクトを形成を保証できるという事実は、明確な利点があります。リスト化して、必要なオブジェクトを検索し、グラフ全体を通してではなく、プロパティを見ることができます。また、チャートは任意または故意に隠されたオブジェクトを持っていないと安心することができます。

また、すべてのオブジェクトのリストを表示し、そのうちのいくつかを削除する選択をすることにより、誤ってその時点でグラフ上に存在するオブジェクトを破壊する可能性が非常に高いです。

プログラムの応答アクションに進む前に、以前の記事で述べたMQL5とMQL4プログラミング言語を利用することができます。さまざまなタスクを解決するためのコードを参照してください。


3. バリアントの戦略

コードの中で独自のソリューションを作成し、複雑な経路を使用してソリューションを探しの時間の浪費から解放されます。

あまりにも正式な学術さを回避するために、ここでは、それが自然に起こった方法戦略について扱います。さらに上記のコードは、この記事の最後に添付されています。動作のために、インクルードファイルを保存する必要があります。 ObjectCreateAndSetインクルードフォルダ。オブジェクトを作成し、必要なチェックとそのプロパティを変更する機能が含まれています。このファイルは、 test_types_of_chart_eventsのインジケーターの操作は必要ありません。


3.1. コード内で実際に決定を下す前の考察とアクション

ドキュメントによると、 OnChartEvent()関数を利用して、イベントの9種類に関するプロセスの情報を得ることができます。それらのいくつかは、グラフィックオブジェクトの除去、変更および作成について通知します。

まず第一に、次の実装方法を思いつきました。

  • 削除または手動で変更している場合のオブジェクトの「セルフリカバリー」。
  • 外部の操作でグラフからプログラムの「セルフデバーチャー」。

どちらも同時に、ループ処理などをせずにオブジェクトを取り除く実装をしなければなりません。

私が思いついた最初のアイデアは、プログラムのセルフテストリヴィジョンでした。しかし、利用可能で最も現実的な解決策のようには思えませんでした。セルフチェックは不要な要素が多く、必ずしも正しいとは限らないためだと思いました。

たとえば、オブジェクトとアクションのイベント処理中に、任意のアクションが実行されたチャートオブジェクト名は、プログラムによって比較されます。プログラム内の任意のタイプのイベントを追跡すると、その情報だけではなく、プログラムのグラフィックオブジェクトが、チャート上のすべてのオブジェクトになります。オブジェクト名は、文字列があり、文字列データは、他のタイプより長く処理されます。チャートは、複数のオブジェクトを手動で作成し、それらに適用されるさまざまなアクションの多くを持つことができます。

以下は、グラフィックオブジェクトを削除する通知を送信する機能が有効になっているときに、オブジェクト名が一致していることを確認するための方式です。これは、複数のグラフィックオブジェクトを操作する場合に適用され、余分な比較の量を減少させるため、提供されています。

if(id==CHARTEVENT_OBJECT_DELETE)
        {
         string deletedChartObject=sparam;
         //---
         for(int i=QUANT_OBJ-1;i>=0;i--)
           {
            if(StringCompare(deletedChartObject,nameObj[i],true)==0)
              {
            /*、アクションを持つ特定のコードがある対象の名前
            イベント中に一致
            プログラムのオブジェクト名*/
               return;
              }
           }
        }

さらに、(イベントまたは定期的に基づく)「改正」オプションは、最終的には、プログラムの背後にある「オーナーレス」オブジェクトを残して、それに対する制御を失う可能性があります。

これが、フラグシステムの考えの理由です。フラグが0に等しいアラームと同様に、例えば、コードの変更と削除オブジェクトが不正な外部干渉などのプログラムによって処理されなければならないことを意味しています。修正と削除、変更イベントがもはや「敵国の侵略」として認識されないように、コードによって提供されるオブジェクトを削除するフラグの値が変化します。

しかし、チャートイベントは OnChartEvent()でさらなる処理とキューを形成するので、処理とキューを形成するので、このような場合のためのコードで「セルフリカバリー」オブジェクトを作成する際のフラグをトリガするシステムは、その時点で特に明確ではありませんでした。また、ループ回避し、このタイプのアクションの削除イベントを処理するとき、余分な繰り返し処理ループが発生します。

たとえば、いくつかのオブジェクトからなるパネルがあり、情報の出力は、このパネルのオブジェクトを削除するイベントを処理するコードのPrint()で有効になっています。頻繁に連続レクリエーションからチャート上に点滅しながら、オブジェクトのセルフリカバリーの間にこれらのイベントについて通知するとパネルが簡単に数秒以内に複数のノートを持つログファイルがいっぱいになることがあります。これは名前の選考にかかわらず、フラグとセルフリカバリーの(または同等の)以下のメソッドを使用して適用されます。

else  if(id==CHARTEVENT_OBJECT_DELETE)
     {
     if(flagAntivandal==0)
        {
            string deletedChartObject=sparam;
            //---
            for(int i=QUANT_OBJ-1;i>=0;i--)
              {
               //---名前が完全に一致:
               if(StringCompare(deletedChartObject,nameObj[i],true)==0)
                 {
                  //---ターミナルの「エキスパート」タブ
                  TEST_PRINT(deletedChartObject);
                  //---無効"アラーム"プログラム"使いやすい"操作
                  flagAntivandal=-1;
                  //---オブジェクト削除。
                  ObjectsDeleteAll(0,prefixObj,0,-1);
                  //---パネル作成
                  PanelCreate();
                 //---再描画チャート 
                  ChartRedraw();
                 //---オブジェクト「プロテクト」するためのフラグを再有効化:
                  flagAntivandal=0;
                  return;
                 }
              }
         return;
        }
      return;
     }//else  if(id==CHARTEVENT_OBJECT_DELETE)

オブジェクトの除去と作成は、イベント通知の流れを形成し、このようなコードの書き込みでループされます。そして、その後の回復のために他のパネルのオブジェクトの除去が必要とされることがあります。たとえば、他のオブジェクト(ボタン、入力フィールドなど)を備えたキャンバスが誤ってまたは意図的に削除された場合です。

コンピュータに十分なメモリがない場合、上記のコードを使用することはお勧めしません。添付のテストコード test_count_click_2に変更するイベントをを置き換えることによって、自分でテストすることができます。

間違って「セルフリカバリー」のイベントを開始した後、ターミナルを2-3秒をシャットダウンすることを余儀なくされるため、間違ったフラグを使用した結果としてログファイルを埋めるための最大容量をチェックしていません。ログファイルを削除し、すぐにごみ箱を空にします。

また、その時点でコード内のオブジェクト名を変更する解決策は不明のままです。このような状況を解く「アンカー」が欠落していました。

これが、チャートイベントに関するメモリをリフレッシュすることを決めた理由です。オブジェクト名を変更した後二つの事象が同時に形成されていることを述べている ObjectSetString()関数の理由でもあります。

  • 古い名前のオブジェクトを削除。
  • 新しい名前でグラフィックオブジェクトを作成。

オブジェクトプロパティを読んだ後、アンカーを OBJPROP CREATETIMEプロパティを使用して決定するオブジェクトの生成時間にすると決めました。

たとえば、添付のtest_get_objprop_createtime で見てもわかるように、オブジェクトの作成時は、コンピュータ上のローカル時刻に等しい:

オブジェクト作成の時間は、オブジェクトを作成する瞬間にコンピュータのローカル時間に等しい。

図4. オブジェクト作成の時間は、オブジェクトを作成する瞬間にコンピュータのローカル時間に等しい。

テストスクリプトはチャート上のボタンを生成し、ExpertsタブのログPrint() を通して生成される時刻を決定します。ターミナルの同じタブに様々な種類の時間を出力します:コンピュータのローカル時間、トレーディングサーバの推定現在の時間、最後の引用、GMT時間の時点での最後の既知のサーバーの時間。その後、10秒間「フリーズ」し、チャートから作成したボタンを削除します。

次のステップは、コード作成時のソリューションの明確な行動計画が含まれています。「各ボタン」に対して個別の回復アクションを記述する必要はないように、これらの最終的に、十分汎用的でなければなりません。また、チャート上の共存の原則を考慮しなければなりません。


プランは、以下のようになっています。:

3.1.1独立したオブザーバーとして使用するサードパーティプログラムに表示され、そのオブジェクト外部からの影響を受けているプログラムのイベントの順序で確認する。:

  • プロパティダイアログを介して手動でグラフィックオブジェクトのプロパティを変更し、別のプログラムを使用している場合
  • 「オブジェクトのリスト」を通じてオブジェクトを削除するときに手動および他のプログラムを使用している場合;
  • そのプロパティダイアログを介して手動でオブジェクト名を変更し、他のプログラムを使用している場合。

同時に作成するオブジェクトの時刻を表示し、利便性のため、テーブルとして得られた結果を書き留めることが必要です。

従って、以下の計画の最初のポイントを実現する必要があります。

3.1.2. 外部オブザーバーとして機能し、チャート上で発生するイベントについて説明し、プログラムインジケータのアシスタント。

インジケータを選択し、同時にExpert Advisorでチャート上で動作することができます。

このアシスタントについて説明はいたしません。完全なコードは、 test_types_of_chart_eventsにファイルとして添付されています。作業するときに、イベントに慣れることができるので、ここでは次のように言及されます:

  • このインジケータは、標準的な9種類のイベントで動作するように設計されています。
  • 取得したイベントの名前と値を表示しますid, lparam, dparam, sparam(オブジェクト名グラフィックオブジェクトのイベント)。
  • いくつかのイベントに関する通知が無効になので、テストコードを実行している時に動作するnoトレーディング・プログラムを持っていないインジケータを、テストするための個別のグラフを使用することができます。それ以外の場合、プログラムの円滑な実行に必要な通知を無効にすることができます。

    テストインジケータ・オブザーバの外部カスタムプロパティ

図5. テストインジケータ・オブザーバの外部カスタムプロパティ

インジケータは、デフォルトでは無効になっているオブジェクトとアクションにリンクされていないイベントに関する通知があります。これは、通知が動作し、標準的なイベント59の有効化/無効化をしています。

  • また、このテストコードは ExpertsPrint()関数の情報が表示されます。... よって、着信データ量の大きいターミナルのログファイルがあふれるのを避けるために CHARTEVENT_MOUSE_MOVEイベントが表示され、この指標を経由して無効になっていません。このタイプのイベントについての情報の表示は、テストインジケータコードで提供されません。

3.1.3実行に関与している他のアシスタント。:

  • ボタン編集オブジェクトを作成するスクリプト。
  • これで指定した名前でオブジェクトのプロパティを変更し、それが一時停止した後に、変更されたオブジェクトを削除するスクリプト。


3.2. 実験の結果

以下の表は結果です。そのオブジェクトの操作の対象となるプログラムは、イベントに関する標準通知のテーブルだけが提供されている理由を、あるチャート上の他のプログラムがそうであるように同じように、「見なします」。「ボタン」と「編集オブジェクト」オブジェクトとアクションに基づいています。

オブジェクトとアクション id lparam dparam sparam アクションに関する通知イベントの名前は、「手動」で実行します。 オブジェクトの作成時** サードパーティ製プログラムによって実行されたアクションについて「フレンドリー」と通知するイベントの名前
オブジェクトの作成時**
新しいオブジェクトの作成(名前を無変更) 7
0 0 オブジェクト名 CHARTEVENT_OBJECT_CREATE ターミナルが実行しているコンピュータ上のローカル時間 CHARTEVENT_OBJECT_CREATE ターミナルが実行しているコンピュータ上のローカル時間
オブジェクト名を変更(以前の名前を持つオブジェクトが削除され、新しいオブジェクトが同時に作成されます)
6

7

8
0

0

0
0

0

0
オブジェクト名
オブジェクト名
オブジェクト名
CHARTEVENT_OBJECT_DELETE

CHARTEVENT_OBJECT_CREATE

CHARTEVENT_OBJECT_CHANGE
新しいオブジェクトの作成時間は、前の名前のオブジェクトの作成時間に等しいです 警告メッセージはありません
新しいオブジェクトの作成時間は、前の名前のオブジェクトの作成時間に等しいです
オブジェクトの背景を変更 8 0 0 オブジェクト名 СHARTEVENT_OBJECT_CHANGE 変更なし 警告メッセージはありません 変更なし
X軸上のオブジェクトの座標を変更
8 0 0 オブジェクト名 СHARTEVENT_OBJECT_CHANGE 変更なし 警告メッセージはありません 変更なし
削除するオブジェクト 6 0 0 オブジェクト名 CHARTEVENT_OBJECT_DELETE *** CHARTEVENT_OBJECT_DELETE ***

 

テーブル1. どのようにフレンドリーでチャート上の作成、変更、オブジェクトの除去のイベントに関する通知から「見る」ことができるサードパーティ製のプログラム


注釈

*イベント通知をプログラムで処理されているが、取扱い後に現れた他の通知は、このプログラムで処理するためのキューを形成します。

**ターミナルが再起動した後にプログラムによって再作成されていないグラフィックオブジェクトが含まれている場合、再起動後に、 OBJPROP_CREATETIME関数を返します。(1970年1月1日0時〇〇分00秒)この前の時間は、「リセット」です。これはまた、手動で配置され、チャートのオブジェクトで発生します。時間枠を切り替えると、オブジェクトの作成時刻はリセットされません。

***オブジェクトの作成時間を決定しようとした場合、 OBJPROP_CREATETIMEオブジェクトは、すでに削除されているので、その後、イベントの削除についての通知時に、エラーメッセージ4203(グラフィックオブジェクトプロパティの不正な識別子)が表示されます。

プロパティの変更をプログラムで実行された場合は、そのような通知が表示されません。それの残りの部分と同様に、これは明らかな理由のもと行われています。単一のターミナルチャートはグラフィックオブジェクトの数に複数のアクションを実行することができ、これらのプログラムとのオープンチャートが多いです。よって、イベント処理は、任意のチャートのオブジェクトのプロパティのすべてのプログラム的変化に適用されるプログラムの通知は、リソースの消費の大幅な増加につながります。

イベント通知タイプの標準セットを持つユーザーを制限しないようにするには、開発者は私たちのコード内の任意の個々の特定のイベントで、個別の通知を作成することができます。 EventChartCustom()関数は、このためにあり、個別の指定されたカスタムイベントや、ターミナルのすべてのチャートについての通知を生成します。

実験結果によれば、いくつかの多目的な解決策が提案されています。

確かにすべてのシナリオに適用することはできません。しかし、コントロールパネルのオブジェクトに対してタスクを実行することができると仮定して、独自のオプションを開発するのに有用です。

これらのソリューションは、次に基づいています。

  • コード内のフラグ、適応を含むタスクに応じての配置;
  • 構造変異体についてスキームの一部として記載され、特別に設計された機能の動作。

以下は、これらのソリューションに共通です。オブジェクトのセルフリカバリーおよび/またはチャートプログラムのセルフデバーチャーを実現するための「プロテクト」を整理する必要があるかどうかに関わらず、コードに含める必要があります。

  • 変数の可視性のグローバルスコープで宣言保存フラグの変数。OnInit()関数(ターミナルのプログラムのグローバル変数と混同しないようにする)。
  • 名前を「プロテクト」する、オブジェクト用の一般的ではない短いプレフィックスの作成。
  • オブジェクトを削除するための通知( CHART_EVENT_OBJECT_DELETE)のチャートのプロパティで、このプロパティは無効。
  • オブジェクトの削除に関する通知を有効にするため、チェックが予め設定された時間の後に実行されるコードOnTimer()関数を含む。それに応じて、タイマーの周波数を設定。タイマーは、EventKillTimer()を使用して、 OnDeinit()関数で停止。
  • 通知を処理するブロック CHARTEVENT_OBJECT_CHANGE CHARTEVENT_OBJECT_DELETE OnChartEvent()内での不正介入の例に指定されたアクションとイベントコード内の関数。

プログラムのオブジェクトに使用される名前を変更したオブジェクトからチャートのクリアは、提供される以下のものを持っている必要があります。

  • プロテクトされたオブジェクトがある場合、または通常の変数にがある場合は、データ・配列に作成する「プロテクト」オブジェクトの時間を格納。
  • その作成の時点で、オブジェクトの除去・削除をするための具体的な機能。

また、コードで実装する「セキュリティ」アクションの順序は重要です。

唯一の無許可の変更/、その後、コード内で、オブジェクトの削除タスクセットに依存によってトリガチャートからプログラムの「セルフデバーチャー」を構築した場合、単一の変数は、フラグに十分であり得ます。具体例:
  • -1:コード内のオブジェクトとアクションを実行する前に、「アラーム」を無効にします。また、returnと不必要な処理を削減するために、このフラグ値でイベント処理を変更。よって、実際には、このフラグ値で、このようなイベントに関する通知を処理するためのブロックを残すことによって、オブジェクトを変更するイベントについて、着信通知を無視することを意味します:
if(flagAntivandal==-1){return;}
  • 0:オブジェクト(それらのすべてまたは一部を)をプロテクトするための「アラーム」を有効にします。「アラーム」がオブジェクトとの「フレンドリー」のアクションを実行した後に使用可能にされたときに設定されています。「アラーム」がオブジェクトと「フレンドリー」のアクションを実行した後に、使用可能にされたときに設定されます。
    • 削除・変更するオブジェクトのイベントに関する通知フラグ値を受信した場合、0で、そのイベントが「プロテクトされた」オブジェクトのいずれかと特異的に発生していることを確認します。
    • イベントは、「プロテクトされた」オブジェクトのいずれかの場合、その後、更なるステップを取る前に、その値を変更することにより、「アラームの"フラグを-1に無効にする必要があります。
    • これらの予備的行為の後、グラフからプログラムを削除する関数が適用されます。関数が使用して作成されます。
      • ChartIndicatorDelete() インジケーター用インジケータの短い名前はOnInit()の前に設定する必要があります。:
IndicatorSetString(INDICATOR_SHORTNAME,short_name);
  • ExpertRemovе() エキスパートアドバイザー用。まだこの関数に慣れていない場合、ドキュメントを確認してください。

オブジェクトが削除された、およびそれらの代わりに作成された新しいもので不正な干渉をしている場合は、少なくとも二つのフラグが必要とされます。一つは、その関数内の前のフラグに等しいです。2つ目は、オブジェクトの回復アクション中に削除イベントの受信からループコードを防止するために必要とされます。もう少し複雑になります。第2のフラグは適応性があり、自動での自己調整は、アラームの "スムーズな操作を実現し、オブジェクトを削除するイベントを処理するのに役立ちます。それは不要なイベント処理がありません。4.2で、さらに詳しく見ていきます。

さて、それでは、例に移りましょう。


4. 許可されない改変、またはプログラムオブジェクトの除去中におけるバリアントのスキーム

他のオブジェクトを削除するチャートから「セルフデバーチャー」に関する「セルフリカバリー」の同時実施の例は、この記事の第5章に記載されています。その場合、必要に応じてアシスタントになり、動作プログラムのコード体系を説明します。

「はい」と「いいえ」に属する、オブジェクト上でマウスクリックを計算するためのチャート上のパネルを作成し、別のテストコードの例を使用することにより、複雑な事項を単純なものから進行します。

これは、添付のテストコードのパネルが取引ターミナルの言語に応じてどのように見えるかというものです。

図6. 取引ターミナルの言語に応じた添付のテストコードのパネル

これは、2次のアクションタイプの(後述)の動作方式の追跡を容易にした簡単なテストコードです:

以下に記載のスキームと最初のテストインジケータコードは、 test_count_click_0の名前の場所に記事に添付されています。2次スキームの実装時には、このテストコードの2つは、結果を考慮して作成されました。完全なコードとして個別に各方式の動作を見て、これらのコードのオブジェクトを削除することで、チャート上でそれらの動作をテストすることができます。

Print()の出力の行が、オブジェクトを削除するときに実装方式を処理する順序を表示することができるように、これらは添付のコードに含まれています。以下は、補助Print()出力のコード行がありません。


4.1. 変更されたオブジェクトの除去と、チャートプログラムの「セルフデバーチャー」

テストコードのフルバージョンは、 test_count_click_1の名前の場所に取り付けられています。

4.1.1コードでスキームにファイル作成。:

ファイル test_count_click_0は、 test_count_click_1の名前で保存されます。ファイルをMetaEditorでタイトルに番号0を含む添付ファイルを開いて、MetaEditorのトップメニューのファイル -> 保存を選択することによって行うことができます。

4.1.2 すべてのプログラムの可視性スコープ内のすべての機能を超えて宣言された変数OnInit()関数:

#defineで定義された指標名は、その後の内部置換で交換

#define NAME_INDICATOR             "count_click_1: "

変数は、セマフォフラグに追加されます。

int flagAntivandal;
オブジェクトを作成する回数を格納する「プロテクトされた」オブジェクトの量に等しいサイズを持つ配列が続きます。
datetime timeCreateObj[QUANT_OBJ];

指標の「セルフデバーチャー」が追加された場合、2つの警告メッセージを格納する文字列が追加されます。2つ目のグラフから正常に除去する処理の実行中にエラーが発生した場合。これらのメッセージの出力がターミナルの言語に応じて、2つの言語(英語とロシア語)で提供されているため、配列はプログラムのすべての部分への可視性のスコープで宣言されています。

string textDelInd[2];

さらに、この配列に格納されているメッセージが原因のチャートからインジケータを、有用なコードOnInit() REASON_INITFAILED で提供します。

4.1.3LanguageTerminal()は、取引ターミナルの言語に応じて、テキストメッセージを表示する役割があります。:

メッセージのテキストは、プログラムの成功と失敗の両方の「セルフデバーチャー」に追加されます。

void LanguageTerminal()
  {
   string language_t=NULL;
   language_t=TerminalInfoString(TERMINAL_LANGUAGE);
//---
   if(language_t=="Russian")
     {
      textObj[3]="Да: ";
      textObj[4]="Нет: ";
      textObj[5]="Всего: ";
      //---
      StringConcatenate(textDelInd[0],"インジケータを削除できませんでした。: \"",
                        prefixObj,"\". エラーコード: ");
      StringConcatenate(textDelInd[1],"チャート表示から削除: \"",
                        prefixObj,"\".");
     }
   else
     {
      textObj[3]="Yes: ";
      textObj[4]="No: ";
      textObj[5]="All: ";
      //---
      StringConcatenate(textDelInd[0],"インジケータを削除できませんでした: \"",
                        prefixObj,"\". Error code: ");
      StringConcatenate(textDelInd[1],
                        "Withdrew from chart indicator: \"",
                        prefixObj,"\".");
     }
//---
   return;
  }

4.1.4 PanelCreate()は、コントロールパネルのオブジェクトを作成する関数です。:

オブジェクトの作成後に作成された時間が決定され、配列に格納されます。単純なバージョンでは、これは次のように見えます。

void PanelCreate(const long chart_ID=0,const int sub_window=0)
  {
   for(int i=NUMBER_ALL;i>=0;i--)
     {
      //---クリック数を示すフィールド:
      if(ObjectFind(chart_ID,nameObj[i])<0)
        {
         EditCreate(chart_ID,nameObj[i],sub_window,X_DISTANCE+WIDTH,
                    Y_DISTANCE+(HEIGHT)*(i),WIDTH,HEIGHT,
                    textObj[i],"Arial",FONT_SIZE,"\n",ALIGN_RIGHT,true,
                    CORNER_PANEL,clrText[i],CLR_PANEL,CLR_BORDER);
         //---オブジェクト作成の時間を格納します。
         CreateTimeGet(chart_ID,nameObj[i],timeCreateObj[i]);
        }
     }
//---
   int correct=NUMBER_ALL+1;
//---
   for(int i=QUANT_OBJ-1;i>=correct;i--)
     {
      //---注記を持つフィールド:
      if(ObjectFind(chart_ID,nameObj[i])<0)
        {
         EditCreate(chart_ID,nameObj[i],sub_window,X_DISTANCE+(WIDTH*2),
                    Y_DISTANCE+(HEIGHT)*(i-correct),WIDTH,HEIGHT,
                    textObj[i],"Arial",FONT_SIZE,"\n",ALIGN_LEFT,true,
                    CORNER_PANEL,clrText[i-correct],CLR_PANEL,CLR_BORDER);
         //---オブジェクト作成の時間を格納します。
         CreateTimeGet(chart_ID,nameObj[i],timeCreateObj[i]);
        }
     }
   return;
  }

4.1.5. 変数にオブジェクト作成の時間を記憶する機能のバリアントを決定:

bool CreateTimeGet(const long chart_ID,
                   const string &name,
                   datetime &value
                   )
  {
   datetime res=0;
   if(!ObjectGetInteger(chart_ID,name,OBJPROP_CREATETIME,0,res))
     {
      Print(LINE_NUMBER,__FUNCTION__,", Error = ",
            GetLastError(),", name: ",name);
      return(false);
     }
   value=res;
   return(true);
  }

プログラムが凍結によって引き起こされるケース。例えば、ターミナルの緊急再始動時のチャート上にある、オブジェクトの時間を作成するためのリビジョン機能の追加。

bool RevisionCreateTime(int quant,datetime &time_create[])
  {
   datetime t=0;
   for(int i=quant-1;i>=0;i--)
     {
      t=time_create[i];
      if(t==0)
        {
         Print(LINE_NUMBER,__FUNCTION__,", Error create time: ",
               TimeToString(t,TIME_DATE|TIME_SECONDS));
         return(false);
        }
     }
//---
   return(true);
  }

この関数呼び出しは、 PanelCreate()の後にOnInit()に配置されます。

想定しているターミナルの緊急閉鎖とその後の再起動後にこの関数がfalseを返した場合、チャートが応答しないことを示す CreateTimeGet()関数のエラーメッセージ4102が、ターミナルの「エキスパート」タブに表示されることがあります。

4.1.6. OnInit()関数のブロック:

4.1.6.1. コントロールパネルを作成する関数の前に、追加されたセマフォフラグが値-1で初期化されます。これは、アラームがオブジェクトとの「フレンドリー」のアクションを実行する際に無効にされることを意味します。グラフの時間枠が変更された場合、特に、予測不可能性を回避します。

flagAntivandal=-1;

4.1.6.2. まだ行われていない場合、指標に短い名前が設定されています。これは、プログラムの強制撤去に必要となります。

提供のテストコード例では、インジケータのショートネームは、以前に設定した指標の名前、シンボルとそれが設定され、チャートの期間からなる、オブジェクトの接頭辞に等しかったとされています:

//---コードのオブジェクトとインジケータの短い名前の名の接頭辞を作成します。
   StringConcatenate(prefixObj,NAME_INDICATOR,Symbol(),"_",EnumToString(Period()));
//---指標を設定するショートネーム:
   IndicatorSetString(INDICATOR_SHORTNAME,prefixObj);

4.1.6.3コントロールパネルとオブジェクトの作成時間の配列のリビジョンの作成後の「プロテクト」のアラームを有効にします。:

//---パネルを作成します。
   PanelCreate();
/*オブジェクトを作成し、終了の時間を持つ配列の改訂 
何か問題がある場合:*/
   if(!RevisionCreateTime(QUANT_OBJ,timeCreateObj))
     {return(REASON_INITFAILED);}
/*、応答位置にフラグを設定します
オブジェクトを変更するイベントへ:*/
   flagAntivandal=0;

4.1.6.4チャートからグラフィックオブジェクトの除去のイベントに関する通知が、プロパティで無効になっている場合。:

//---グラフィックオブジェクトを削除するイベントについての通知を有効
 bool res=true;
 ChartEventObjectDeleteGet(res);
 if(res!=true)
 {ChartEventObjectDeleteSet(true);}

注:ChartEventObjectDeleteGet() 及び ChartEventObjectDeleteSet()は、での作業の例でページから

4.1.6.5.削除対象のイベントに関する通知がされる周波数を設定するこのプログラムの動作時のチャートのプロパティが無効の場合、OnInit()を終了する前に、タイマーでチェックする。:

EventSetTimer(5);

4.1.7. OnDeinit() 関数のブロック:

「アラーム」を無効にします:

flagAntivandal=-1;

指定した時間から発生するイベントの終了

EventKillTimer();

OnInit()初期化解除の理由から来るインジケーターの削除REASON_INITFAILEDが失敗した場合:

//--- OnInit()のREASON_INITFAILEDのインジケーターの削除。
   if(reason==REASON_INITFAILED)
     {
      ChIndicatorDelete(prefixObj,textDelInd[0],textDelInd[1],0,0);
     }

4.1.8. OnTimer()関数のブロック:

別のプログラムでは無効になっていた場合には、コピー&ペーストを使用して、ポイント4.1.6.4からのコード行を複製するタイマー付きのチャート上のオブジェクトを削除するイベントに関する通知を有効にする。

4.1.9. OnChartEvent()関数の生成:

4.1.9.1. 取り扱いを変更し、オブジェクトを削除し、1つのブロックに組み合わせることができ、イベントの取り扱いの際に「セキュリティ対策」に提供されている場合。

4.1.9.2.まず最初に、変更/削除するオブジェクトのイベントに関する通知を受信したときに「警報」が有効になっている場合、フラグをチェック。フラグの値が等しい場合に、-1となり、(「アラーム」が無効になっている)、イベント処理を終了します。

4.1.9.3.フラグの値が等しいときに0になり、("アラーム"有効になっている)、最初のオブジェクト名が接頭辞で得られたマッチングのチェックを設定することができます。 StringFind()関数は、このために使用されるので、プログラムの全体の配列は、チャートからの変更とオブジェクトの削除に関するすべての通知で名前をオブジェクト反復処理する必要はありません。この場合、OnInit()で設定されたプレフィックスは短くない。プレフィックス形成は p.4.1.6.2で提供されています。

接頭辞によって一致しない場合、ブロックイベントの処理を終了すします。

4.1.9.4、プレフィックスによって一致がある場合にのみ、受信したイベント通知は「プロテクト」のプログラム・オブジェクトを名前で完全にマッチしているか確認されます。名前が完全に一致した場合、プロテクトフラグの値が-1に変更され、(無効)プログラムがチャートから削除された場合、余分なループを作成しないようにします。

4.1.9.5.名前を変更された結果として「オーナーレス」となったオブジェクトが存在する場合には、1と同じ作成時間を持つオブジェクトの検索がさらに実行されます。

4.1.9.6.プログラムがグラフから削除されます。

コードで作成された説明:

else  if(id==CHARTEVENT_OBJECT_DELETE || id==CHARTEVENT_OBJECT_CHANGE)
     {
      if(flagAntivandal==-1)//ignore the event, if the "alarm is disabled"
        {return;}
      else if(flagAntivandal==0)//「アラーム」が有効になっている場合、
        {
         //--- 接頭辞によって探す:
         findPrefixObject=StringFind(sparam,prefixObj);
         if(findPrefixObject==0)//接頭辞によって一致する場合
           {
            string chartObject=sparam;
            findPrefixObject=-1;
            //---
            for(int i=QUANT_OBJ-1;i>=0;i--)
              {
               //---名前が完全に一致:
               if(StringCompare(chartObject,nameObj[i],true)==0)
                 {
                  //---除去作業ループ回避するために、アラームを無効にします。
                  flagAntivandal=-1;
/*その作成時削除オブジェクトが削除の作成時間に等しい、
 変更されたオブジェクト:*/
                  ObDelCreateTimeExcept0(timeCreateObj[i],0,0,OBJ_EDIT);
                  //---チャートからインジケータを削除します。
                  ChIndicatorDelete(prefixObj,textDelInd[0],textDelInd[1],0,0);
                  //---
                  ChartRedraw();
                  return;
                 }
              }//for(int i=QUANT_OBJ-1;i>=0;i--)
            return;
           }//if(findPrefixObject==0)
         return;
        }//if(flagAntivandal==0)
      return;
     }//if(id==CHARTEVENT_OBJECT_DELETE || id==CHARTEVENT_OBJECT_CHANGE)  

4.1.10その作成の時点でオブジェクトを削除するための ObDelCreateTimeExcept0()関数。:

このように見える作成時刻によってオブジェクトを削除するための関数のスキーム:

void ObDelCreateTimeExcept0(datetime&create_time,//作成時刻
                            long chart_ID=0//グラフ識別子
                            int sub_window=-1,// サブウィンドウの数
                             ENUM_OBJECTtype=-1)//-1=すべての種類のオブジェクト
  {
/*関数からのイグジット、オブジェクトの時間=0(1970年1月1日00:00:00)の場合、
 手動またはプログラムによって作成されたオブジェクトを削除する必要はありません、 
 その作成時間はゼロに 
 ターミナルはチャートから、再起動しました:*/
   if(create_time==0){return;}
   int quant_obj=0;
   quant_obj=ObjectsTotal(chart_ID,sub_window,type);
//---
   if(quant_obj>0)
     {
      datetime create_time_x=0;
      string obj_name=NULL;
      //---
      for(int i=quant_obj-1;i>=0;i--)
        {
         obj_name=ObjectName(chart_ID,i,sub_window,type);
         create_time_x=(datetime)ObjectGetInteger(chart_ID,obj_name,
                        OBJPROP_CREATETIME);
         //---
         if(create_time_x==create_time)
           {ObDelete(chart_ID,obj_name);}
        }
     }
   return;
  }
//+------------------------------------------------------------------+

「プロテクトされた」オブジェクトの作成データは、 01970年1月1日午前0時00分00秒)に等しい場合は、イベント処理は中止すべきです。端末はチャートから、再起動された後に、手動またはプログラム作成されたオブジェクトを削除回避するために必要とされます。

4.1.11. 上記のコードでの ObDelete()関数:

これは、 ObjectCreateAndSetライブラリーから取ったオブジェクトを削除する際に提供されたエラー出力です。

bool ObDelete(long chart_ID,string name)
  {
   if(ObjectFind(chart_ID,name)>-1)
     {
      ResetLastError();
      if(!ObjectDelete(chart_ID,name))
        {
         Print(LINE_NUMBER,__FUNCTION__,", Error Code = ",
               GetLastError(),", name: ",name);
         return(false);
        }
     }
   return(true);
  }

4.1.12.インジケータを削除するための関数:

//+------------------------------------------------------------------+
//| チャートから指標を削除します                                         |
//+------------------------------------------------------------------+
void ChIndicatorDelete(const string short_name,//インジケータ短い名前
                       const string &text_0,//インジケータを削除中にエラーがある場合
                       const string &text_1,//インジケータが正常に削除されたテキスト
                       const long  chart_id=0,//グラフ識別子
                       const int   sub_window=-1//サブウィンドウ数
                       )
  {
   bool res=ChartIndicatorDelete(chart_id,sub_window,short_name);
//---
   if(!res){Print(LINE_NUMBER,text_0,GetLastError());}
   else Print(LINE_NUMBER,text_1);
  }
//+------------------------------------------------------------------+

ここで、 LINE_NUMBERは、#defineで設定されたコードの行番号を含むメッセージの冒頭に一般的なテキストです。

#define LINE_NUMBER    "Line: ",__LINE__,", "

それでは、次のスキームに移りましょう。


4.2. オブジェクトの「セルフリカバリー」

オブジェクトの作成プログラムのループを回避するために、値のセルフリカバリーを配置し、フラグの変化により注意が必要です。

スキームは、前述の test_count_click_1codeの修正に基づいて記述されています。完全なコードのテストは、 test_count_click_2の名前の添付ファイルにあります。

4.2.1コード内でこの方式を使用してファイルを作成します。:

ファイル test_count_click_1は、 test_count_click_2の名前で保存されます。

4.2.2プログラムのすべての範囲で任意の機能を超えて宣言された変数、すなわちOnInit()関数のブロックの前:

指標名は#defineで置き換えられます。:

#define NAME_INDICATOR             "count_click_2: "

別の変数は、前述の単純なフラグに加えて、補助適応フラグとして追加されます。

int flagAntivandal, flagResetEventDelete;

変数はまた、リカバリ操作を実行する前に、メッセージのテキストに作成されます。

string textRestoring;

4.2.3LanguageTerminal()取引ターミナルの言語に応じてメッセージのテキストを表示するための関数。:

パネルオブジェクトの不正除去の場合に、リカバリ操作の前に表示されたメッセージが含まれています。

void LanguageTerminal()
  {
   string language_t=NULL;
   language_t=TerminalInfoString(TERMINAL_LANGUAGE);
//---
   if(language_t=="Russian")
     {
      textObj[3]="Да: ";
      textObj[4]="Нет: ";
      textObj[5]="Всего: ";
      //---
      textRestoring="Уведомление о страховом случае: объект ";
      //---
      StringConcatenate(textDelInd[0],"Не удалось удалиться индикатору: \"",
                        prefixObj,"\". Код ошибки: ");
      StringConcatenate(textDelInd[1],"Удалился с графика индикатор: \"",
                        prefixObj,"\".");
     }
   else
     {
      textObj[3]="Yes: ";
      textObj[4]="No: ";
      textObj[5]="All: ";
      //---
      textRestoring="保障されたイベントの通知:オブジェクト ";
      //---
      StringConcatenate(textDelInd[0],"インジケータを削除できませんでした: \"",
                        prefixObj,"\". Error code: ");
      StringConcatenate(textDelInd[1],
                        "Withdrew from chart indicator: \"",
                        prefixObj,"\".");
     }
//---
   return;
  }

選択肢が望ましくない場合に、セーフティネットとして機能していることを想定し、このテキストを使用しました。

4.2.4. OnInit() 関数のブロック:

オブジェクト作成の関数の前に、-1値で両方のフラグを初期化する(アラームが完全に無効):

flagAntivandal = flagResetEventDelete = -1;

パネルのオブジェクトの作成のブロックやオブジェクトを作成するための時間配列の改正後 - フラグの値で初期化0(「アラーム」を可能に):

//---パネルを作成します。
   PanelCreate();
/*オブジェクトを作成し、終了の時間を持つ配列の改訂 
何か問題がある場合:*/
   if(!RevisionCreateTime(QUANT_OBJ,timeCreateObj))
     {return(REASON_INITFAILED);}
/*レスポンスの位置にフラグを設定します 
削除したオブジェクトを変更するイベント:*/
   flagAntivandal= flagResetEventDelete=0

4.2.5. OnChartEvent()関数に進みましょう:

オブジェクトを削除するイベントの通知を処理する前に、既存のブロックを変更します。新しいブロックでは、オブジェクトを削除し、変更のイベントを処理するための一般的であるスキームを行います。

  • 「プロテクト」が有効になっているか、確認してください。有効でない場合は、ブロックを処理するイベントから、イグジットします。
  • その後、余分な削除イベントをリセットするための補助フラグは0、パネルのオブジェクトを削除し、変更のイベントについて、着信通知がリセットされるフラグが等しくなるまで、0より高い場合。
  • プライマリおよび補助フラグがゼロに等しい場合にのみ、回復アクションが許可されていないオブジェクトの除去が可能です。
else  if(id==CHARTEVENT_OBJECT_DELETE || id==CHARTEVENT_OBJECT_CHANGE)
     {
      if(flagAntivandal==-1){return;}
      else if(flagResetEventDelete>0)
        {
         findPrefixObject=StringFind(sparam,prefixObj);
         if(findPrefixObject==0)
           {
            findPrefixObject=-1;
/*イベントの値をリセットするカウンタフラグその後のため
削除するオブジェクトの構築イベントのコードの動作
リカバリー・アクションの結果として:*/
            flagResetEventDelete=flagResetEventDelete-1;
            //---
            return;
           }
         return;
        }
      else if(flagAntivandal==0 && flagResetEventDelete==0)
        {
         //---接頭辞によって一致を調べる。
         findPrefixObject=StringFind(sparam,prefixObj);
         if(findPrefixObject==0)//接頭辞によって一致する場合
           {
            string chartObject=sparam;//イベントでオブジェクト名
            findPrefixObject=-1;
/*オブジェクトが「プロテクト」されているかどうかをチェックし、回復する 
            /*測定...
            RestoringObjArrayAll(chartObject,prefixObj,flagAntivandal,
                                     flagResetEventDelete,QUANT_OBJ,nameObj,
                                     timeCreateObj);
            return;
           }//if(findPrefixObject==0)
         return;
        }//else if(flagAntivandal==0 && flagResetEventDelete==0)
      return;
     }//else  if(id==CHARTEVENT_OBJECT_DELETE || id==CHARTEVENT_OBJECT_CHANGE)

主な復旧はRestoringObjArrayAll()で作成されます。このような関数は、同時にオブジェクトの異なるグループに対してブロックで適用することができます。この記事の第五章では、関連する例を扱います。「プロテクトされた」オブジェクトに一致する場合、接頭辞によって確認した後に、この機能の下で変更した場合のオブジェクト名。

4.2.6. RestoringObjArrayAll() 関数。

次のようになります。

  • 名前で完全一致のチェックは、イベントによって、オブジェクトが、その後、「プロテクト」されていることを示している場合:
    • 「アラーム」の主なフラグは、-1(「アラーム」が「フレンドリー」アクションの時間に無効)を取得。
    • オブジェクトを削除するイベントが処理されている場合、この時点で少なくとも1オブジェクトが削除されたことを意味するので、オブジェクトを削除する場合は、補助フラグは、「プロテクトされた」オブジェクトマイナス1の全体的な量に等しくなるように設定されます。
  • 削除されたオブジェクトが計算されている間、これらの予備的な作業の後、プロテクトされた残りのオブジェクトは、以下に示すObDeletePrefixFlag()関数を使用して、接頭辞によって削除されます。必要な場合、この補助フラグの値に基づいて、 flagResetEventDeleteは、補正されます。

補助フラグの値がリセットされなくなるまでは、削除イベントが表示されるオブジェクトの削除中なので、その後、0コードの部分で処理されません。:

else if(flagResetEventDelete>0)
        {
         findPrefixObject=StringFind(sparam,prefixObj);
         if(findPrefixObject==0)
           {
            findPrefixObject=-1;
/ *イベントのリセット値は、後続のフラグをカウント 
削除するオブジェクトの構築イベントのコードの動作
リカバリー・アクションの結果として:*/
            flagResetEventDelete=flagResetEventDelete-1;
            //---
            return;
           }
         return;
        }
    • オブジェクトは接頭辞によって削除され、補助フラグの取り扱いに必要ではないイベント「排除」の実際の数に等しい値を採用している場合、チャートを再描画する関数が配置されます。その後、流れに従ってください。
    • チャート再描画は、イベントを受信した上で作成されたオブジェクトの時間に等しく、作成時点で検索やオブジェクトの除去が続きます。オブジェクト名が変更された場合、イベントが形成され、「オーナーレス」オブジェクトがチャートに登場します。これは、すでに p.4.1.10で既知の通り、 ObDelCreateTimeExcept0()関数を使用して除去する必要があります。
    • 取り扱いの最終ステップ:パネルまたはその一部の回復。
    • 最後に、グラフを再描画し、メインフラグに("アラート"セット)値0を割り当てます。この時点で、補助フラグに必要な値が自動的に形成されているので、何も記述する必要はありません。

//+---------------------------------------------------------------------------------------+
//|Function of objects' "self-recovery" on OnChartEvent()                                 |
//+---------------------------------------------------------------------------------------+
//|string sparam = object's name passed to OnChartEvent()                                 |
//|string prefix_obj = common prefix of protected objects                                 |
//|int &flag_antivandal = flag for enabling/disabling alarm                               |
//|int &flag_reset = flag for resetting events                                            |
//|int quant_obj = total amount of objects in the "protected"                             |
//|配列|
//|string &name[] = array of names of "protected" objects                                 |
//|datetime &time_create[] = array of times of creating these objects                     |
//|int quant_obj_all=-1 total amount of recoverable objects                               |
//|of the program, >= quant_obj (if -1, then equals quant_obj)                            |
//|const long chart_ID = 0 chart's identifier                                             |
//|const int sub_window = 0 window's index                                                |
//|int start_pos=0 which position in the objects' name to start searching the prefix with |
//+---------------------------------------------------------------------------------------+
int RestoringObjArrayAll(const string sparam,
                         const string prefix_obj,
                         int &flag_antivandal,
                         int &flag_reset,
                         const int quant_obj,
                         string &name[],
                         datetime &time_create[],
                         int quant_obj_all=-1,
                         const long chart_ID=0,
                         const int sub_window=0,
                         const int start_pos=0
                         )
  {
//---結果をここに入れます:
   int res=-1;
/*オブジェクトの入力の正確さをチェック
   関数の外部パラメータ。間違った外部パラメータ 
   この関数のコードの作成時に入力しました。
   唯一の「アラーム」のイベントの後、既知となります。
   これが事前に確認する必要がある理由です。
   コードを作成するときに、この機能に正しい外部パラメータを設定します。*/
   if(quant_obj<=0)//プロテクトされたオブジェクトの指定された量<=0
     {
      Print(LINE_NUMBER,__FUNCTION__,
            ", Error Code. 間違った値:quant_obj="、quant_obj)。
      return(res);
     }
   else   if(quant_obj>quant_obj_all && quant_obj_all!=-1)
     {
      Print(LINE_NUMBER,__FUNCTION__,
            ", Error Code. 正しくない値:quant_obj_all")。
      return(res);
     }
   else if(quant_obj_all==-1){quant_obj_all=quant_obj;}
//---完全なオブジェクト名の比較用の変数:
   int comparison=-1;
/*イベントから取得したオブジェクト名を確認するためのループ 
 プロテクトされたオブジェクトの配列:*/
   for(int i=quant_obj-1;i>=0;i--)
     {
      comparison=StringCompare(sparam,name[i],true);
      //---名前が完全に一致:
      if(comparison==0)
        {
         comparison=-1;
         res=1;
         //---「保険」の事態の発生に関する通知:
         Print(LINE_NUMBER,textRestoring,sparam);
/*プログラムは、オブジェクトを復元しながら、フラグを設定します 
オブジェクトの削除のイベントに反応しないように:*/
         flag_antivandal=-1;
/*初期値不要になったイベントのカウンタ 
イベント処理。その結果としての予防線 
コードのループ削除の構築イベント
リカバリー・アクションの結果としてのオブジェクト:*/
         flag_reset=quant_obj_all-1;
         //---いずれの場合でも、配列の残りのプロテクトされたオブジェクトを削除:
         ObDeletePrefixFlag(flag_reset,prefix_obj,chart_ID,sub_window,start_pos);
         //---チャートを再描写:
         ChartRedraw();
         //---、いずれの場合でも、名前を変更したオブジェクトを削除:
         ObDelCreateTimeExcept0(time_create[i],chart_ID,sub_window);
         //---オブジェクトの再生成:
         PanelCreate();
         //---チャートの最終的な再描画:
         ChartRedraw();
         //---アラームを有効に:
         flag_antivandal=0;
         //---
         return(res);
        }
     }//for(int i=QUANT_OBJECTS-1;i>=0;i--)
   return(res);
  }
注:この関数でオブジェクトタイプによって選択をします。オブジェクトの「セルフリカバリー」中に、すべて削除した場合、逆の効果をもたらすオブジェクトタイプで取り扱いを狭くすることで、取り扱いの量を減少させる再作成パネルのオブジェクトは異なるタイプにします。したがって、不正な干渉により、チャート上のパネルのオブジェクトがさまざまな種類で構成されている場合、オブジェクトの特定のタイプによって取り扱い範囲を狭めるの戦略を適用しないことをお勧めします。そして、この警告を無視しようとしている人々があるかもしれないと仮定して、上記の関数から削除されます。

異なる型のオブジェクトは、パネル上の第5章からの例では「セルフリカバリー」中にオブジェクトの選択をする場合は、望ましくない影響を表示することができます。事前にイベントや回復を処理するためのコードPrint()を入力する必要があります。

プログラムの"セルフデバーチャー"から、オブジェクトの種類別に制限を通じてコードで取り扱いの量を減少させることによって、簡単にリソースを節約することができます。

4.2.7. ObDeletePrefixFlag()関数は、必要に応じて、接頭辞によりオブジェクトを削除し、補助フラグの値を修正します。...

Artem Trishkinとユーザー7777877によって付け加えられた、Sergei Kovalevのテキストにあるスキームに頼っています。スキームのベースがかなり汎用的であり、多くの異なるタスクで支援をされているので、感謝しています。

基本的に、ここで適用されます。

//+------------------------------------------------------------------+
//| int &flag_reset = flag for resetting events of deleting objects  |
//| string prefix_obj = general prefix in the objects' names         |
//| long  chart_ID = chart's identifier                              | 
//| int   sub_window=-1 = window's index (-1 = all)                  |
//| int start_pos=-1 = start position of a general prefix's          |
//| substring in the objects' name                                   |
//+------------------------------------------------------------------+
int ObDeletePrefixFlag(int &flag_reset,
                       string prefix_obj,
                       const long chart_ID=0,
                       const int sub_window=0,
                       int start_pos=0)

  {
   int quant_obj=ObjectsTotal(chart_ID,sub_window,-1);
   if(quant_obj>0)
     {
      int count=0;
      int prefix_len=StringLen(prefix_obj);
      string find_substr=NULL,obj_name=NULL;
//---
      for(int i=quant_obj-1;i>=0;i--)
        {
         obj_name=ObjectName(chart_ID,i,sub_window,-1);
         find_substr=StringSubstr(obj_name,start_pos,prefix_len);

         if(StringCompare(find_substr,prefix_obj,true)==0)
           {
            count=count+1;
            ObDelete(chart_ID,obj_name);
           }
        }
      if(count>0 && flag_reset<count)
        {flag_reset=count;}
     }
   return(flag_reset);
  }
コードの動作は、それぞれ確認することができます。
  • チャート上の添付テストコードを実行します。
  • 「はい」と「いいえ」オブジェクトをクリックしてから、別の値にゼロから値を増加させます。
  • そして、プロパティダイアログを介して、削除することによって、このパネルのオブジェクトを変更してください。
パネルがある自動回復アクションを実行した後、「クリック」の回数は、パネルを再作成するときに使用されるデータ配列に保存されています。

しかし、様々なオブジェクトへの種々の応答を作成することができます。

次のようないくつかの特別な場合を除いて、手順の主要部分を提示します:

  • イベント処理を除く。
  • 別のプログラムによってオブジェクトのプロパティを変更します。

さて、プログラムを削除し、そのオブジェクトの変化に対応し、両方の実用的な実装の例に進みましょう。


5. 一つのプログラムで2つのレスポンスオプションを実装する例

不正な行為への段階的に提供される二つのオプションでの指標の選択は、ランダムではありません。

  • より複雑なコードで、これらのオプションの例を提供した場合、読者は混乱するかもしれません。
  • 以下に添付したオプションは簡単とはいえ、条件を含む実用的な情報が多くあります。
  • また、この指標は、この記事の主題とは無関係なものも含めて、オブジェクトを操作するのに有用です。

将来、必要に応じて、それが表示された値のリストを拡張することができます。

完全なコードは、 id_name_objectに取り付けられています。概説です:

  • オブジェクト名とオブジェクトマップを保存するための配列や変数のマップ。
  • 一般的なコード体系。
  • 直接、記事の主題に関連しているコードのセクション。

提供されたインジケータの目的:任意のグラフオブジェクトをクリックしたときに、オブジェクト名はその作成時間と種類を示しています。必要なら、表示されるフィールドから、これらの値をコピーすることができます。変更、復元しようとしている間に、提供されているパネルから表示された値を削除。これは、別々に機能します。

さらに、次の機能があります。

  • チャート上のパネルの主要部分の「最小化」。
  • オブジェクトの「セルフリカバリー」、パネルの主要部分の任意のオブジェクトが変更または削除されている場合。
  • 最小化パネルのボタンが削除されたり原理に基づいて変更された場合、チャートからのインジケータの「セルフデバーチャー」:"それが最小限に抑えていた場合、それは多くの瞬間で必要ではないです」
  • 最後の2つの測定は、オブジェクトがグラフからリネーム後に削除する必要を考慮して実装されています。
  • ロシア語の場合、パネルのタイトルを表示

ターミナルの言語に応じたコントロールパネルの外観

図7. ターミナルの言語に応じたコントロールパネルの外観

配列用のマップとパネルオブジェクトの作成された名前を格納するための変数

図8. パネルオブジェクトの作成された名前を格納するための配列と変数のマップ



オブジェクトのタイプ
目的
テキストの格納場所
フォント
テキストの色*
バックグラウンド * 境界線の色*
作成された時刻を格納
nameRectLabel
OBJ_RECTANGLEのLABEL
キャンバス
---
--- ---
CLR_PANEL criNONE
timeCreateRectLabel
nameButton[0]
OBJ_BUTTON
チャートから識別子を除去するためのボタン
textButtUchar[0]**
"Wingdings"
CLR_TEXT
CLR_PANEL criNONE
timeCreateButton[0]
nameButton[1] OBJ_BUTTON
「最小化」パネル用のボタン
textButtUchar[1]**
"Wingdings"
CLR_TEXT
CLR_PANEL criNONE
timeCreateButton[1]
nameButton[2] OBJ_BUTTON
「最大化」パネル用のボタンの後に「最小化」
textButtUchar[2]**
"Wingdings"
CLR_TEXT
CLR_PANEL criNONE
timeCreateButton[2]
nameEdit0[0]
OBJ_EDIT
"Object's name:" label
textEdit0[0]
"Arial"
CLR_TEXT_BACK
CLR_PANEL CLRのBORDER
timeCreateEdit0[0]
nameEdit0[1]
OBJ_EDIT
"Creation time:" label textEdit0[1] "Arial"
CLR_TEXT_BACK
CLR_PANEL CLRのBORDER
timeCreateEdit0[1]
nameEdit0[2]
OBJ_EDIT
"Object's type:" label textEdit0[2] "Arial"
CLR_TEXT_BACK
CLR_PANEL CLRのBORDER
timeCreateEdit0[2]
nameEdit1[0]
OBJ_EDIT
オブジェクト名を表示するフィールド textEdit1[0]
"Arial"
CLR_TEXT
CLR_PANEL CLRのBORDER
timeCreateEdit1[0]
nameEdit1[1] OBJ_EDIT
作成時刻を表示するためのフィールド textEdit1[1] "Arial"
CLR_TEXT
CLR_PANEL CLRのBORDER
timeCreateEdit1[1]
nameEdit1[2] OBJ_EDIT
オブジェクトの型を表示するためのフィールド
textEdit1[2] "Arial"
CLR_TEXT
CLR_PANEL CLRのBORDER
timeCreateEdit1[2]

 

表2. パネルのオブジェクトのマップ

* Colors set with #define:

#define CLR_PANEL                  clrSilver//パネル一般的な背景
#define CLR_TEXT                   C'39,39,39'//テキストのメインカラー
#define CLR_TEXT_BACK              C'150,150,150' //影付き文字の色
#define CLR_BORDER                 clrLavender//フレームの色

** Symbols "Wingdings":

uchar textButtUchar[3]={251,225,226};


5.1外部変数。

パネルの大きさは、1つのボタンの大きさに基づいて計算されます。したがって、幅と1ボタンとフォントサイズの高さは、外部カスタムプロパティに表示されます。これは、コード内で直接調整しなくても、表示パネルやテキストを増加させることができます。

指標の外部カスタムプロパティ

図9. 指標の外部カスタムプロパティ


5.2<プログラムのすべての部分への可視性のスコープ内の任意の関数を越えて宣言されたフラグの変数、つまりOnInit()関数のブロック。:

2つのフラグを宣言します:

int flagClick, flagResetEventDelete;

flagClickは、パネルのボタンのクリック通知の追跡を設定するフラグです。その値は次のとおりです。

0
パネルの主要部分がチャート上にある場合、この値をパネルの「最小化」ボタンをクリックし、チャートから識別子を除去するイベントに関する通知が与えられます。
-1
「最小化」や「最大化」に対応するボタンをクリックした後に、チャートから識別子を削除するアクションの前に設定されます。
1 「最大化」ボタンのクリックのイベントに関する通知を追跡する場合。

 

さらに、不正な変更、またはオブジェクトの除去の場合(この記事の前のコードより flagAntivandal)「アンチバンダル」フラグとして機能します。0は、パネルの主要部分の「アラーム」、1は有効 - 、および-1は、「最大化」ボタンのを無効にします。

コードでのイベント処理をリセットするための補助フラグとして、「アンチバンダル」フラグを作成する場合は、別々の変数がこの目的のために必要とされます。

flagResetEventDeleteは、変更/削除されたオブジェクトの「自己回復」オプションを実装する場合、適応値で不要なイベントの処理をリセットするために使用されるフラグです。

この地域で宣言された他の変数は、添付のコードで表示することができます。


5.3. OnInit()関数のブロック:

  • チャート上のパネルを作成する前にフラグ値-1を取得。
  • クリックされたチャートオブジェクトの結果として値が表示されるパネルのフィールドのテキストの配列は、空の値で満たされています。
  • 一般的なオブジェクトの接頭辞が作成され、短い名前を任意の指標に割り当てられます。
  • 共通のプレフィックスに基づいて、パネルのオブジェクト名が作成されます。
  • ターミナルの言語に応じて、オブジェクトの回収に関するメッセージおよび削除は言語パネルのタイトルに決定されます。
  • 外部パラメータが不正なサイズを持っている場合には、ボタンの幅と高さの制限が設定されています。
  • パネルの主要部分は、チャート上に作成されます。
  • 配列はオブジェクトの作成時に検討されています。
  • フラグ flagClick flagResetEventDeleteは、0が割り当てられています。
  • その後は、プロパティで無効になっている場合、チャート上のオブジェクトを削除するイベントについて通知を有効にするために行われます。
  • タイマーの周波数は秒単位で設定されています。

int OnInit()
  {
   flagClick=flagResetEventDelete=-1;
/*パネルのテキストフィールドの配列 
   クリックされたグラフィックオブジェクトの値が結果として表示されます。*/
   for(int i=QUANT_OBJ_EDIT-1;i>=0;i--){textEdit1[i]=" ";}
//+------------------------------------------------------------------+
/*インジケーターの短い名前:*/
   StringConcatenate(prefixObj,INDICATOR_NAME,"_",Symbol(),"_",
                     EnumToString(Period()));
   IndicatorSetString(INDICATOR_SHORTNAME,prefixObj);
//---オブジェクト名
   NameObjectPanel(nameRectLabel,prefixObj,"rl");
   NameObjectPanel(QUANT_OBJ_BUTTON,nameButton,prefixObj,"but");
   NameObjectPanel(QUANT_OBJ_EDIT,nameEdit0,prefixObj,"ed0");
   NameObjectPanel(QUANT_OBJ_EDIT,nameEdit1,prefixObj,"ed1");
//+------------------------------------------------------------------+
/*インジケーターテキスト、取引ターミナルの言語に応じて:*/
   LanguageTerminal();
//+------------------------------------------------------------------+
/*1ボタンの幅と高さの制限:*/
   if(objWidthHeight>=20 && objWidthHeight<=300)
     {obj0WidthHeight=objWidthHeight;}
   else if(objWidthHeight>300){obj0WidthHeight=300;}
   else {obj0WidthHeight=20;}
//---チャート上のコントロールパネルを作成します
   PanelCreate();
/*オブジェクトを作成し、プログラムを終了する時間を持つ配列の改正、
うまくいかない場合:
(3つのうち2つのボタンは、パネルの主要部分に存在しています
したがって、改訂時に、その量は1以下になります*/
   if(!RevisionCreateTime(QUANT_OBJ_BUTTON-1,timeCreateButton))
     {return(REASON_INITFAILED);}
   if(!RevisionCreateTime(QUANT_OBJ_EDIT,timeCreateEdit0))
     {return(REASON_INITFAILED);}
   if(!RevisionCreateTime(QUANT_OBJ_EDIT,timeCreateEdit1))
     {return(REASON_INITFAILED);}
//---
   flagClick=flagResetEventDelete=0;
//---グラフィックオブジェクトを削除するイベントに関する通知:
   bool res;
   ChartEventObjectDeleteGet(res);
   if(res!=true)
     {ChartEventObjectDeleteSet(true);}
//---タイマーを作成
   EventSetTimer(8);
//---
   return(INIT_SUCCEEDED);
  }

5.4. PanelCreate() 関数:

パネルオブジェクトは、将来的にその外観の変化を簡単にするため、別の名前のグループに分割されます。パネル自体は、グラフの右上に配置されます。したがって、X軸Y軸に沿ったピクセルでの距離は、チャートの右上隅に関連していて、オブジェクトの左上の点の位置を決定します。

オブジェクトの不正な名前変更の場合、時間の作成が設定され、このために提供される配列に記録されます。独立した変数は、パネルのキャンバスに設けられています。

void PanelCreate(const long chart_ID=0,//チャートID 
                 const int sub_window=0)//サブウィンドウ数
  {
//---パネルのキャンバスの幅:
   int widthPanel=(obj0WidthHeight*11)+(CONTROLS_GAP_XY*2);
//---パネルのキャンバスの高さ:
   int heightPanel=(obj0WidthHeight*6)+(CONTROLS_GAP_XY*8);
//---x軸に沿った距離:
   int x_dist=X_DISTANCE+widthPanel;
//---
   if(ObjectFind(chart_ID,nameRectLabel)<0)//キャンバス
     {
      RectLabelCreate(chart_ID,nameRectLabel,sub_window,x_dist,
                      Y_DISTANCE,widthPanel,heightPanel,"\n",CLR_PANEL,
                      BORDER_RAISED,CORNER_PANEL,clrNONE,STYLE_SOLID,1,
                      false,false,true);
      //---オブジェクト作成の時間の記録と決定:
      CreateTimeGet(chart_ID,nameRectLabel,timeCreateRectLabel);
     }
//---
   x_dist=X_DISTANCE+CONTROLS_GAP_XY;
   int y_dist=Y_DISTANCE+CONTROLS_GAP_XY;
//---
   for(int i=QUANT_OBJ_BUTTON-2;i>=0;i--)
     {
      //---指標を最小化するためのボタン:
      if(ObjectFind(chart_ID,nameButton[i])<0)
        {
         ButtonCreate(chart_ID,nameButton[i],sub_window,
                      x_dist+(obj0WidthHeight*(i+1)),y_dist,obj0WidthHeight,
                      obj0WidthHeight,CORNER_PANEL,
                      CharToString(textButtUchar[i]),"\n","Wingdings",
                      font_sz+1,CLR_TEXT,CLR_PANEL,clrNONE);
         //---オブジェクト作成の時間の記録と決定:
         CreateTimeGet(chart_ID,nameButton[i],timeCreateButton[i]);
        }
     }
//---
   x_dist=X_DISTANCE+widthPanel-CONTROLS_GAP_XY;
   int y_dist_plus=(CONTROLS_GAP_XY*2)+(obj0WidthHeight*2);
//---
   for(int i=QUANT_OBJ_EDIT-1;i>=0;i--)
     {
      //---オブジェクトのプロパティの名:
      if(ObjectFind(chart_ID,nameEdit0[i])<0)
        {
         EditCreate(chart_ID,nameEdit0[i],sub_window,x_dist,
                    y_dist+(y_dist_plus*i),obj0WidthHeight*8,
                    obj0WidthHeight,textEdit0[i],"Arial",font_sz,
                    "\n",ALIGN_CENTER,true,CORNER_RIGHT_UPPER,
                    CLR_TEXT_BACK,CLR_PANEL,CLR_BORDER);
         //---オブジェクト作成の時間の記録と決定:
         CreateTimeGet(chart_ID,nameEdit0[i],timeCreateEdit0[i]);
        }
     }
//---
   y_dist=Y_DISTANCE+obj0WidthHeight+(CONTROLS_GAP_XY*2);
//---
   for(int i=QUANT_OBJ_EDIT-1;i>=0;i--)
     {
      //---オブジェクトのプロパティ値のテキストを表示:
      if(ObjectFind(chart_ID,nameEdit1[i])<0)
        {
         EditCreate(chart_ID,nameEdit1[i],sub_window,x_dist,
                    y_dist+(y_dist_plus*i),obj0WidthHeight*11,
                    obj0WidthHeight,textEdit1[i],"Arial",font_sz,
                    "\n",ALIGN_LEFT,true,CORNER_RIGHT_UPPER,
                    CLR_TEXT,CLR_PANEL,CLR_BORDER);
         //---オブジェクト作成の時間の記録と決定:
         CreateTimeGet(chart_ID,nameEdit1[i],timeCreateEdit1[i]);
        }
     }
   return;
  }

5.5. In the OnDeinit():

初期化解除の理由がある場合は、OnInit()から REASON_INITFAILEDチャートからインジケータを接頭辞によりオブジェクトを削除すると、タイマからのイベントの生成が停止し、チャートからインジケータを除去する際のための主要なフラグを受信します。

void OnDeinit(const int reason)
  {
   flagClick=-1;
   ObjectsDeleteAll(0,prefixObj,0,-1);
   EventKillTimer();
//---REASON_INITFAILEDがOnInitにある場合、削除。
   if(reason==REASON_INITFAILED)
     {
      ChIndicatorDelete(prefixObj,textDelInd[0],textDelInd[1],0,0);
     }
//---
   ChartRedraw();
  }

5.6. OnTimer():

OnInit()に設定された時間によって、グラフィックオブジェクトを削除するイベントについての通知がチャートのプロパティに含まれている場合:

void OnTimer()
  {
//---グラフィックオブジェクトを削除するイベントに関する通知を含みます
   bool res;
   ChartEventObjectDeleteGet(res);
   if(res!=true)
     {ChartEventObjectDeleteSet(true);}
  }


5.7. OnChartEvent()関数:

5.7.1マウスでオブジェクトをクリックするイベントに関する通知を処理するためのブロック。
flagClickフラグが0に等しい場合:
  • 最初のチェックは、このパネルの主要部分のボタンのクリックがあったかどうかを調べるために行われています。
  • パネルの最小化ボタンのクリックがあった場合、flagClickフラグ - 1値を取得。
  • 「最小化」ボタンがクリックされた場合には、パネルの主要部分が最小化され、ボタンはグラフの右上に作成されます。
  • flagClickは、この後、1の値が与えられ、パネルの上のクリックを追跡するボタンとその不正な改変を削除。
  • チャートからインジケータを除去するためのボタンをクリックした場合、flagClickフラグは-1を与えられます。チャートからインジケータを除去するために行われます。
  • この場合は、コントロールパネルのボタンのクリックではありませんでしたが、他のチャートのオブジェクトに代わり、この指標のオブジェクトを除いて、その名前、作成、種類が決定され、このオブジェクトの値をパネルに表示します。

flagClickフラグが1に等しい場合、次にボタンを「最大化」:

  • このフラグは、以降のアクションの前に-1値が与えられる。
  • ボタンが削除され、パネルが作成されます。
  • その後flagClickフラグは、0値を指定されます。 flagResetEventDelete フラグの「最大化」ボタンは、値1を取得します。
if(id==CHARTEVENT_OBJECT_CLICK)//id = 1
     {
      if(flagClick==0)//コントロールパネルの主な部分はチャート上にある場合は、
        {
         string clickedChartObject=sparam;
         findPrefixObject=StringFind(clickedChartObject,prefixObj);
         //---
         if(findPrefixObject==0)
           {
            findPrefixObject=-1;
            //---
            for(int i=1;i>=0;i--)
              {
               if(StringCompare(clickedChartObject,nameButton[i],true)==0)
                 {
                  switch(i)
                    {
                     //---ボタンを最小化:
                     case 1:flagClick=-1;
                     MinimizeTable(nameButton,2,textButtUchar,2,
                                   timeCreateButton,obj0WidthHeight);
                     flagClick=1;return;
                     //---チャートから指標を削除するボタン:
                     case 0:flagClick=-1;
                     ChIndicatorDelete(prefixObj,textDelInd[0],textDelInd[1],0,0);
                     return;
                     default:return;
                    }
                 }
              }
           }
         else//クリックがコントロールパネルのボタン上にない場合、
           {
            SetValuesTable(clickedChartObjectは);//オブジェクトの値を設定する
            return;
           }
        }
      //-クリックが進行中なら、パネルを「最大」に:
      else if(flagClick==1)
        {
         findPrefixObject=StringFind(sparam,prefixObj);
         if(findPrefixObject==0)
           {
            string clickedChartObject=sparam;
            findPrefixObject=-1;
            //---「最大化」パネルのボタン:
            if(StringCompare(clickedChartObject,nameButton[2],true)==0)
              {
               flagClick=-1;
               //---主なアクションは、パネルの「最大化」ボタン
               ToExpandTheTable(clickedChartObject);
               //---
               flagClick=0;
               //--- このボタンを削除するイベントをリセット:
               flagResetEventDelete=1;
               //---
               return;
              }
           }
         return;
        }
      return;
     }//if(id==CHARTEVENT_OBJECT_CLICK)
5.7.2テキストの編集を終え、通知を処理するためのブロックでの編集グラフィックオブジェクト。:
このパネルにおけるグラフィックオブジェクトの値が存在する場合、これらのフィールドからコピーするために利用可能になります。したがって、インジケータによって表示される値を変更したり、これらのフィールドに誤って/意図的にコピーするときに削除された場合、前のテキストが復元されます。
else  if(id==CHARTEVENT_OBJECT_ENDEDIT)//id = 3
     {
      findPrefixObject=StringFind(sparam,prefixObj);
      if(findPrefixObject==0)
        {
         string endEditChartObject=sparam;
         findPrefixObject=-1;
         int comparison=-1;
         //---
         for(int i=QUANT_OBJ_EDIT-1;i>=0;i--)
           {
            if(StringCompare(endEditChartObject,nameEdit1[i],true)==0)
              {
               string textNew=ObjectGetString(0,endEditChartObject,OBJPROP_TEXT);
               comparison=StringCompare(textEdit1[i],textNew,true);
               //---
               if(comparison!=0)
                 {
                  ObSetString(0,nameEdit1[i],OBJPROP_TEXT,textEdit1[i]);
                 }
               //---
               ChartRedraw();
               return;
              }
           }//for(int i=0;i<QUANT_OBJ_EDIT;i++)
         return;
        }//if(findPrefixObject==0)
      return;
     }//if(id==CHARTEVENT_OBJECT_ENDEDIT)
5.7.3オブジェクトの削除または削除に関する通知を処理するためのブロック。
  • flagClickフラグ-1に等しい場合、取り扱いブロックは、発生したイベントから終了して、"フレンドリー"アクション中にフラグを与えられます。
  • 最初のチェックが完了し、それが明らかになった場合、flagResetEventDeleteリセットイベントの補助フラグが0 を超え、イベントによってオブジェクトが参照するパネルのことオブジェクトは、その後のイベントがリセットされ、処理ブロックから射出されます。
  • フラグ flagClick flagResetEventDelete0に等しい場合、回復アクションが RestoringObjArrayAll()機能および添付機能を使用して実行されます。
  • flagClickフラグ1に等しい場合、パネルを「最大化」するためのボタンは、インジケータがチャートから削除されます。

else  if(id==CHARTEVENT_OBJECT_DELETE || id==CHARTEVENT_OBJECT_CHANGE)
     {
      if(flagClick==-1)return;
      else if(flagResetEventDelete>0)
        {
         findPrefixObject=StringFind(sparam,prefixObj);
         if(findPrefixObject==0)
           {
            findPrefixObject=-1;
            flagResetEventDelete=flagResetEventDelete-1;
            //---
            return;
           }
         return;
        }
      //オブジェクトが削除された場合:
      else if(flagClick==0 && flagResetEventDelete==0)
        {
         findPrefixObject=StringFind(sparam,prefixObj);
         //---
         if(findPrefixObject==0)
           {
            string chartObject=sparam;
            findPrefixObject=-1;
            int res=-1;
            //---オブジェクトがコントロールパネルのキャンバスにある場合:
            res=RestoringObjOneAll(chartObject,prefixObj,flagClick,
                                   flagResetEventDelete,nameRectLabel,
                                   timeCreateRectLabel,QUANT_OBJ_ALL);
            //---
            if(res==1){return;}
            //---オブジェクトがコントロールパネルのボタンである場合:
            res=RestoringObjArrayAll(chartObject,prefixObj,flagClick,
                                     flagResetEventDelete,QUANT_OBJ_BUTTON,
                                     nameButton,timeCreateButton,QUANT_OBJ_ALL);
            //---
            if(res==1){return;}
            //---オブジェクトがコントロールパネル上のノート(Edit0)の場合:
            res=RestoringObjArrayAll(chartObject,prefixObj,flagClick,
                                     flagResetEventDelete,QUANT_OBJ_EDIT,
                                     nameEdit0,timeCreateEdit0,QUANT_OBJ_ALL);
            //---
            if(res==1){return;}
            //---オブジェクトがコントロールパネルのノート(EDIT1)である場合:
            res=RestoringObjArrayAll(chartObject,prefixObj,flagClick,
                                     flagResetEventDelete,QUANT_OBJ_EDIT,
                                     nameEdit1,timeCreateEdit1,QUANT_OBJ_ALL);
            //---
            return;
           }
        }
      else if(flagClick==1)//最小化パネルのボタンが変更または削除された場合
        {
         string clickedChartObject=sparam;
         if(StringCompare(clickedChartObject,nameButton[2],true)==0)
           {
            flagClick=-1;
            //---チャートから指標を削除:
            ChIndicatorDelete(prefixObj,textDelInd[0],textDelInd[1],0,0);
            return;
           }
         return;
        }
      return;
     }//else  if(id==CHARTEVENT_OBJECT_DELETE || id==CHARTEVENT_OBJECT_CHANGE)
このブロックの新機能は、パネルのキャンバスが変更または削除されたときにRestoringObjOneAll()関数が適用されます。以前に使用した RestoringObjArrayAll()関数に似ています。
//+-----------------------------------------------------------------------+
//|string sparam = object's name passed to OnChartEvent()                 |
//|string prefix_obj = common prefix of protected objects                 |
//|int &flag_antivandal = flag for enabling/disabling alarm               |
//|int &flag_reset = flag for resetting events                            |
//|string name = object's name                                            |
//|datetime time_create = time of object's creation                       |
//|int quant_obj_all = total number of recoverable objects                |
//|of the program, >= quant_obj (if -1, then equals quant_obj)            |
//|const long chart_ID = 0 chart's identifier                             |
//|const int sub_window = 0 window's index                                |
//|int start_pos=0 the position in the name of objects to look for prefix |
//+-----------------------------------------------------------------------+
int RestoringObjOneAll(const string sparam,
                       const string prefix_obj,
                       int &flag_antivandal,
                       int &flag_reset,
                       string name,
                       datetime time_create,
                       const int quant_obj_all,
                       const long chart_ID=0,
                       const int sub_window=0,
                       int start_pos=0
                       )
  {
   int res=-1;
   int comparison=-1;
//---
   comparison=StringCompare(sparam,name,true);
//---名前が完全に一致:
   if(comparison==0)
     {
      res=1;
      comparison=-1;
      //---「保険」の事態の発生に関する通知:
      Print(LINE_NUMBER,textRestoring,sparam);
      //---
      flag_antivandal=-1;
      flag_reset=quant_obj_all-1;
      //---
      ObDeletePrefixFlag(flag_reset,prefix_obj,chart_ID,sub_window,start_pos);
      //---
      ChartRedraw();
      //---
      ObDelCreateTimeExcept0(time_create,chart_ID,sub_window,-1);
      //---
      PanelCreate();
      //---
      ChartRedraw();
      //---
      flag_antivandal=0;
      //---
      return(res);
     }
   return(res);
  }

インジケータコードは、 id_name_objectにあります。


6. 結論

この記事に記載されたフラグシステムに基づいて、簡単なスキームおよび、そのバリエーションは、多くのオブジェクトに関連したコードに追加することができます。プログラムの主な操作を担当しているコードの部分に大きな変更を行う必要はありません。

必要に応じて、他の関連するアクションは、同様のコードで提供することができます。

  • コードの誤操作などのため、例えば、他のプログラムとコントロールパネルの一部のオブジェクトを変更します。
  • それらの多くがイベント通知を除きます。

たとえば、コードに関して正当化される場合、タイマーによってパネルに表示された、重要なデータパネルの「ルーチン」アクションだけでなく、選択的または全体のリビジョンチェック中に、追加チェックを実装することができます。

エキスパートアドバイザーでは、たとえば、トレーディングの性能に重大な干渉を引き起こさない場合は、メッセージを表示せずにグラフィックオブジェクトの除去中にアニメーションすることができます。

チャートからプログラムを削除、または破損したオブジェクトを復元する試み:メッセージを表示するときには、例えば、該当するボタンを押して選択を提供することができます。この「XX」プログラムのオブジェクト内の不正な干渉:さらに、オブジェクトの不正除去または変更の状況で、次の警告が表示されることがあり、カウンタを提供することができます。「XX」の場合、後のプログラムは、チャートから自分自身を削除します。このような状況"の理由を見つけてください。

MQL5プログラミング言語の機会、探求心と知識に基づいて、必要であれば、この記事で説明されていなかったものも含めて、さまざまなオプションを作成することができます。

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

グラフィカルインタフェース V:コンボボックス要素(チャプター 3) グラフィカルインタフェース V:コンボボックス要素(チャプター 3)
シリーズの第五部の最初の2つの記事では、スクロールバーとビューリストを作成するためのクラスが作成されました。この章では、コンボボックスコントロールのクラスを作成する方法についてお話します。これはまた、とりわけ第五部の前の章で考慮された要素を含むコンパウンドコントロールです。
グラフィカルインタフェースVI:スライダーとデュアルスライダーコントロール(チャプター 2) グラフィカルインタフェースVI:スライダーとデュアルスライダーコントロール(チャプター 2)
前回の記事では、チェックボックス、編集コントロールやチェックボックスやコンボボックスを持つ編集コントロールの4つの頻繁にグラフィカルインタフェースで使用されるコントロールでライブラリを改良しました。第六部の第2章は、スライダーとデュアルスライダーコントロールに専念されます。
エキスパートアドバイザの自己最適化:進化的遺伝的アルゴリズム エキスパートアドバイザの自己最適化:進化的遺伝的アルゴリズム
この記事では、進化的アルゴリズムにある主要な原理と、その多様性および特徴について検証します。実験を使用した簡単なエキスパートアドバイザの例では、最適化が私達の取引システムに何をもたらすかを見ていきます。遺伝的、進化的、またその他のタイプの最適化を実装するプログラムのセットを検証し、取引システムのパラメータの最適化や予測変数のセットの最適化時の適用例をご紹介します。
グラフィカルインタフェースVI:チェックボックスコントロール、編集コントロールとその混合型(チャプター 1) グラフィカルインタフェースVI:チェックボックスコントロール、編集コントロールとその混合型(チャプター 1)
本稿は、MetaTrader端末でグラフィカルインタフェースを作成するためのライブラリの開発に関するシリーズの第六部の始まりです。第1章ではチェックボックスコントロール、編集コントロールとその混合型についてお話します。