MQL5 v1.50: Knopf-Flackern - der Chart trug den Indikator DREIMAL
User: "beim Wechseln der Zeit blinken die Knoepfe kurz gross auf und sind dann wieder klein". Nicht die Groesse war das Problem. BELEG aus dem Terminal-Journal: je Zeitebenen-Wechsel DREI identische Zeilen "custom indicator SR_Levels loaded succesfully" im selben Zehntelsekunden- Fenster. Auf dem Chart lagen drei Instanzen. Jede hat ihren EIGENEN gespeicherten Eingabesatz - die vor v1.49 angehaengten trugen noch 66/17/8, die neue 132/34/16. Alle drei schrieben im Sekundentakt auf dieselben Objektnamen, also wechselte die Groesse permanent hin und her. Doppelte Instanzen sind von aussen unsichtbar, solange nichts schreibend kollidiert - sie kosteten hier zusaetzlich das Dreifache an CSV-Lesevorgaengen und Objekt-Auf-/Abbau je Sekunde. Merksatz: bei unerklaerlichem Chart-Verhalten ZUERST die Ladezeilen im Journal zaehlen. FIX 1: nur eine Instanz zeichnet die Knoepfe. Anspruch je Chart ueber eine temporaere GlobalVariable, gesetzt mit GlobalVariableSetOnCondition - also ATOMAR (ein Check-dann-Set haetten bei gleichzeitigem Start alle drei gewonnen). Nicht-Inhaber steigen in BtnDraw() sofort aus und melden einmalig im Experten-Log, dass eine zweite Instanz laeuft. OnDeinit raeumt die Knoepfe nur noch als Inhaber weg und gibt den Anspruch frei - sonst haette eine beendete Zweit-Instanz die Knoepfe der noch laufenden ersten geloescht. FIX 2: die Groesse heilt sich selbst. BtnDraw() legt einen Knopf neu an, wenn seine gespeicherte XSIZE/YSIZE/FONTSIZE nicht mehr zum Soll passt; reines Nachsetzen der Eigenschaften (v1.49) reichte in der Praxis nicht. Der eigentliche Fix liegt beim Nutzer: doppelte Instanzen entfernen (Rechtsklick > Indikatorenliste). Der Guard verhindert nur den sichtbaren Schaden, nicht die dreifache Last. 0 errors 0 warnings, .ex5 frisch, Spiegel bitgleich.
This commit is contained in:
+57
-2
@@ -12,7 +12,7 @@
|
||||
//| 4) Der Bot muss laufen (schreibt die CSV alle ~5 s). |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Oil Trading Bot"
|
||||
#property version "1.49"
|
||||
#property version "1.50"
|
||||
// v1.42 (2026-08-19): Y-Stapel oben rechts GEMESSEN statt geschaetzt. Der
|
||||
// Faktor 1,8 aus v1.41 war nur die naechste Schaetzung; jetzt liefert
|
||||
// TextGetSize die TATSAECHLICHE Pixelhoehe (LabelH). Ausserdem wird Y bei
|
||||
@@ -334,6 +334,43 @@ bool g_bvis[BTN_N];
|
||||
//| Sichtbar? Einzige Quelle fuer alle Zeichen-Zweige.
|
||||
bool Vis(int i) { return (i >= 0 && i < BTN_N) ? g_bvis[i] : true; }
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| ⚠⚠ NUR EINE INSTANZ DARF DIE KNOEPFE ZEICHNEN (v1.50). |
|
||||
//| Real am 2026-08-22: der Chart trug SR_Levels DREIMAL (im Journal |
|
||||
//| belegt: drei "loaded succesfully" je Zeitebenen-Wechsel). Jede |
|
||||
//| Instanz hat ihren EIGENEN gespeicherten Eingabesatz — die vor |
|
||||
//| v1.49 angehaengten trugen noch 66/17/8, die neue 132/34/16. Alle |
|
||||
//| drei schrieben im Sekundentakt auf DIESELBEN Objektnamen, also |
|
||||
//| wechselte die Groesse staendig hin und her: "blinken kurz gross |
|
||||
//| auf und sind dann wieder klein". |
|
||||
//| ⚠ Der Anspruch wird ATOMAR gesetzt (GlobalVariableSetOnCondition) |
|
||||
//| — drei Instanzen starten praktisch gleichzeitig, ein |
|
||||
//| Check-dann-Set haetten alle drei gewonnen. |
|
||||
//| ⚠ Faellt der Inhaber weg (OnDeinit gibt frei), holt sich der |
|
||||
//| naechste Timer-Durchlauf einer anderen Instanz den Anspruch. |
|
||||
//+------------------------------------------------------------------+
|
||||
double g_stamp = 0.0; // eigene Kennung (nie 0)
|
||||
bool g_isowner = false;
|
||||
bool g_warned = false;
|
||||
|
||||
string BtnOwnGV() { return "SRB_BTNOWN_" + IntegerToString(ChartID()); }
|
||||
|
||||
bool BtnClaim()
|
||||
{
|
||||
if(g_isowner) return true;
|
||||
string gv = BtnOwnGV();
|
||||
if(!GlobalVariableCheck(gv)) GlobalVariableTemp(gv); // legt mit 0 an
|
||||
g_isowner = GlobalVariableSetOnCondition(gv, g_stamp, 0.0);
|
||||
if(!g_isowner && !g_warned)
|
||||
{
|
||||
g_warned = true;
|
||||
Print("SR_Levels: weitere Instanz auf diesem Chart — die Knoepfe "
|
||||
"zeichnet nur die erste. Doppelte Instanzen bitte entfernen "
|
||||
"(Rechtsklick > Indikatorenliste).");
|
||||
}
|
||||
return g_isowner;
|
||||
}
|
||||
|
||||
string BtnGV(int i) { return "SRB_" + _Symbol + "_"
|
||||
+ IntegerToString((int)_Period) + "_" + g_bkey[i]; }
|
||||
|
||||
@@ -376,6 +413,7 @@ void BtnPaint(int i)
|
||||
|
||||
void BtnDraw()
|
||||
{
|
||||
if(!BtnClaim()) return; // eine andere Instanz zeichnet
|
||||
if(!InpShowButtons) { ObjectsDeleteAll(0, BPFX); return; }
|
||||
int h = MathMax(10, InpBtnHoehe);
|
||||
// ⚠⚠ SPALTEN-RUECKFALL. Mit der 200-%-Groesse ist der Stapel 490 px hoch;
|
||||
@@ -390,6 +428,14 @@ void BtnDraw()
|
||||
for(int i = 0; i < BTN_N; i++)
|
||||
{
|
||||
string nm = BPFX + g_bkey[i];
|
||||
// ⚠ Auch NEU ANLEGEN, wenn die Groesse nicht mehr passt: ein von einer
|
||||
// frueheren Fassung erzeugter Knopf behaelt sonst seine alten Masse.
|
||||
// Reines Nachsetzen der Eigenschaften reichte in der Praxis nicht.
|
||||
bool falsch = (ObjectFind(0, nm) >= 0)
|
||||
&& ((int)ObjectGetInteger(0, nm, OBJPROP_XSIZE) != InpBtnBreite
|
||||
|| (int)ObjectGetInteger(0, nm, OBJPROP_YSIZE) != h
|
||||
|| (int)ObjectGetInteger(0, nm, OBJPROP_FONTSIZE) != InpBtnFont);
|
||||
if(falsch) ObjectDelete(0, nm);
|
||||
if(ObjectFind(0, nm) < 0)
|
||||
{
|
||||
if(!ObjectCreate(0, nm, OBJ_BUTTON, 0, 0, 0)) continue;
|
||||
@@ -469,6 +515,9 @@ int LabelH(const string font, const int size)
|
||||
int OnInit()
|
||||
{
|
||||
if(InpApplyTheme) ApplyTheme();
|
||||
// Kennung: nie 0 (0 heisst "frei"), pro Instanz verschieden.
|
||||
g_stamp = (double)(GetTickCount() % 1000000) + 1.0 + (double)(MathRand() % 997) / 1000.0;
|
||||
BtnClaim();
|
||||
BtnInit();
|
||||
EventSetTimer(MathMax(1, InpRefreshS));
|
||||
Redraw();
|
||||
@@ -590,7 +639,13 @@ void OnDeinit(const int reason)
|
||||
EventKillTimer();
|
||||
ObjectsDeleteAll(0, PFX);
|
||||
ObjectsDeleteAll(0, RPFX);
|
||||
ObjectsDeleteAll(0, BPFX);
|
||||
// ⚠ NUR der Inhaber raeumt die Knoepfe weg — sonst loescht eine
|
||||
// beendete Zweit-Instanz die Knoepfe der noch laufenden ersten.
|
||||
if(g_isowner)
|
||||
{
|
||||
ObjectsDeleteAll(0, BPFX);
|
||||
GlobalVariableSet(BtnOwnGV(), 0.0); // Anspruch freigeben
|
||||
}
|
||||
ChartRedraw();
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
Reference in New Issue
Block a user