Also when zoom in to the object, it becomes totally invisible?
When you zoom out, it's there again.
why? How to fix?
Please help.
Thanks!
Below is a code that creates 2 bitmap object.
These objects gets resized accordingly whenever there's changes to the chart ie slide, zoom.
You will see those objects flickering when you slide & zoom.
The reason for the flickering in your example is the use of the ChartTimePriceToXY function.
This is a very slow function (in MQL5). Why it's slow is a very long story. I consider this to be a semantic MQ bug, but I'm tired of fighting with MQ on this issue.
You can use my library iCanvas_CB.mqh, which does not use this function to convert coordinates (time, price) to pixel coordinates. In this library you can see how you can do without these (..XY.. ChartGet.. ChartSet..) very slow functions in order to implement these functions yourself and not use my library.
#property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com/en/users/abiotamalo" #property version "1.00" #property indicator_chart_window #property indicator_buffers 1 #include <Canvas\iCanvas_CB.mqh> //https://www.mql5.com/ru/code/22164 #include <Canvas\Canvas.mqh> #include <Canvas\Charts\HistogramChart.mqh> CHistogramChart chart; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnInit() { //--- create canvas int x=0; int y=0; ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,114),iHigh(Symbol(),PERIOD_CURRENT,114),x,y); int x1=0; int y1=0; ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,97),iLow(Symbol(),PERIOD_CURRENT,97),x1,y1); double priceWidth=x1-x; double priceHeight=y1-y; uchar alpha=80; bool objCreated=false; double barHeight=priceHeight/200; if(true){ CCanvas canvas; bool objCreated=canvas.CreateBitmap("11111",iTime(Symbol(),PERIOD_CURRENT,114),iHigh(Symbol(),PERIOD_CURRENT,114),x1-x,y1-y,COLOR_FORMAT_ARGB_NORMALIZE); canvas.Erase(ColorToARGB(clrNONE, 0)); canvas.Update(); canvas.FillRectangle(0,0,200,200,ColorToARGB(clrBlue,alpha)); //canvas.TransparentLevelSet(alpha); canvas.Update(); } ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,50),iHigh(Symbol(),PERIOD_CURRENT,114),x,y); x1=0; y1=0; ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,5),iLow(Symbol(),PERIOD_CURRENT,97),x1,y1); priceWidth=x1-x; priceHeight=y1-y; alpha=80; objCreated=false; if(true){ CCanvas canvas; objCreated=canvas.CreateBitmap("2222",iTime(Symbol(),PERIOD_CURRENT,50),iHigh(Symbol(),PERIOD_CURRENT,50),x1-x,y1-y,COLOR_FORMAT_ARGB_NORMALIZE); canvas.Erase(ColorToARGB(clrNONE, 0)); canvas.Update(); barHeight=priceHeight/200; canvas.FillRectangle(0,0,200,200,ColorToARGB(clrRed,alpha)); //canvas.TransparentLevelSet(alpha); canvas.Update(); } } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { return rates_total; } void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if(id==CHARTEVENT_CHART_CHANGE){ int x=(int)_X(114.0); int y=(int)_Y(iHigh(_Symbol,0,114)); //ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,114),iHigh(Symbol(),PERIOD_CURRENT,114),x,y); int x1=(int)_X(97.0); int y1=(int)_Y(iLow(_Symbol,0,97)); //ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,97),iLow(Symbol(),PERIOD_CURRENT,97),x1,y1); double priceWidth=x1-x; double priceHeight=y1-y; ObjectSetInteger(0,"11111",OBJPROP_XSIZE,(long)priceWidth); ObjectSetInteger(0,"11111",OBJPROP_YSIZE,(long)priceHeight); x=(int)_X(50.0); y=(int)_Y(iHigh(_Symbol,0,114)); //ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,50),iHigh(Symbol(),PERIOD_CURRENT,114),x,y); x1=(int)_X(5.0); y1=(int)_Y(iLow(_Symbol,0,97)); //ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,5),iLow(Symbol(),PERIOD_CURRENT,97),x1,y1); priceWidth=x1-x; priceHeight=y1-y; ObjectSetInteger(0,"2222",OBJPROP_XSIZE,(long)priceWidth); ObjectSetInteger(0,"2222",OBJPROP_YSIZE,(long)priceHeight); ChartRedraw(); } }
Alternatively, you can use one canvas stretched over the entire chart window and form all the objects in it (I attach an example TestCanvas2Rect.mq5), but in this case the redrawing will lag behind the chart when scrolling, since the canvas is not tied to time and price.
Also when zoom in to the object, it becomes totally invisible?
When you zoom out, it's there again.
why? How to fix?
Please help.
Thanks!
Because you are confusing the bitmap and the resource (canvas). You need to resize update the resource (canvas) and not the bitmap.
So it happens that the bitmap becomes invisible, but the bitmap is still there :
I fixed one of the 2 to show you.
CCanvas canvas2222; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ int OnInit() { //--- create canvas int x=0; int y=0; ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,114),iHigh(Symbol(),PERIOD_CURRENT,114),x,y); int x1=0; int y1=0; ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,97),iLow(Symbol(),PERIOD_CURRENT,97),x1,y1); double priceWidth=x1-x; double priceHeight=y1-y; uchar alpha=80; bool objCreated=false; double barHeight=priceHeight/200; if(true) { CCanvas canvas; bool objCreated=canvas.CreateBitmap("11111",iTime(Symbol(),PERIOD_CURRENT,114),iHigh(Symbol(),PERIOD_CURRENT,114),x1-x,y1-y,COLOR_FORMAT_ARGB_NORMALIZE); canvas.Erase(ColorToARGB(clrNONE, 0)); canvas.Update(); canvas.FillRectangle(0,0,200,200,ColorToARGB(clrBlue,alpha)); //canvas.TransparentLevelSet(alpha); canvas.Update(); } ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,50),iHigh(Symbol(),PERIOD_CURRENT,114),x,y); x1=0; y1=0; ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,5),iLow(Symbol(),PERIOD_CURRENT,97),x1,y1); priceWidth=x1-x; priceHeight=y1-y; alpha=80; objCreated=false; if(true) { objCreated=canvas2222.CreateBitmap("2222",iTime(Symbol(),PERIOD_CURRENT,50),iHigh(Symbol(),PERIOD_CURRENT,50),x1-x,y1-y,COLOR_FORMAT_ARGB_NORMALIZE); canvas2222.Erase(ColorToARGB(clrNONE, 0)); // canvas2222.Update(); barHeight=priceHeight/200; canvas2222.FillRectangle(0,0,200,200,ColorToARGB(clrRed,alpha)); //canvas2222.TransparentLevelSet(alpha); canvas2222.Update(); } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { return rates_total; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if(id==CHARTEVENT_CHART_CHANGE) { ++Counter; int x=0; int y=0; ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,114),iHigh(Symbol(),PERIOD_CURRENT,114),x,y); int x1=0; int y1=0; ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,97),iLow(Symbol(),PERIOD_CURRENT,97),x1,y1); double priceWidth=x1-x; double priceHeight=y1-y; ObjectSetInteger(0,"11111",OBJPROP_XSIZE,priceWidth); ObjectSetInteger(0,"11111",OBJPROP_YSIZE,priceHeight); x=0; y=0; ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,50),iHigh(Symbol(),PERIOD_CURRENT,114),x,y); x1=0; y1=0; ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,5),iLow(Symbol(),PERIOD_CURRENT,97),x1,y1); priceWidth=x1-x; priceHeight=y1-y; canvas2222.FillRectangle(0,0,priceWidth,priceHeight,ColorToARGB(clrRed,80)); canvas2222.Update(); //ObjectSetInteger(0,"2222",OBJPROP_XSIZE,priceWidth); //ObjectSetInteger(0,"2222",OBJPROP_YSIZE,priceHeight); Comment(Counter); ChartRedraw(); } }
Thank you for your response guys
I'm placing the canvas objects into an array now.
There's no flickering but somehow notice the blue rectangle of each canvas object, it sizes differently when chart updated.
#property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com/en/users/abiotamalo" #property version "1.00" #property indicator_chart_window #property indicator_buffers 1 #include <Canvas\Canvas.mqh> #include <Canvas\Charts\HistogramChart.mqh> CCanvas canvasObjects[]; int Counter=0; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ int OnInit() { //--- create canvas int x=0; int y=0; ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,144),iHigh(Symbol(),PERIOD_CURRENT,144),x,y); int x1=0; int y1=0; ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,97),iLow(Symbol(),PERIOD_CURRENT,97),x1,y1); double priceWidth=x1-x; double priceHeight=y1-y; bool objCreated=false; /* First canvas object */ if(true) { CCanvas canvas; string name="144_97";//name consists of the start & end index datetime startTime=iTime(Symbol(),PERIOD_CURRENT,144); double startignPoint=iHigh(Symbol(),PERIOD_CURRENT,144); bool objCreated=canvas.CreateBitmap(name,startTime,startignPoint,x1-x,y1-y,COLOR_FORMAT_ARGB_NORMALIZE); double fillRectangleSize=priceHeight/3; canvas.Erase(ColorToARGB(clrBlack, 0)); ArrayResize(canvasObjects,1); canvasObjects[ArraySize(canvasObjects)-1]=canvas; } ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,50),iHigh(Symbol(),PERIOD_CURRENT,50),x,y); x1=0; y1=0; ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,8),iLow(Symbol(),PERIOD_CURRENT,8),x1,y1); priceWidth=x1-x; priceHeight=y1-y; objCreated=false; /* Second Canvas Object */ if(true) { CCanvas canvas; string name="50_8"; datetime startTime=iTime(Symbol(),PERIOD_CURRENT,50); double startignPoint=iHigh(Symbol(),PERIOD_CURRENT,50); objCreated=canvas.CreateBitmap(name,startTime,startignPoint,x1-x,y1-y,COLOR_FORMAT_ARGB_NORMALIZE); canvas.Erase(ColorToARGB(clrRed, 0)); canvas.Update(); ArrayResize(canvasObjects,2); canvasObjects[ArraySize(canvasObjects)-1]=canvas; } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { return rates_total; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if(id==CHARTEVENT_CHART_CHANGE) { for(int i=0;i<ArraySize(canvasObjects);i++){ CCanvas c=canvasObjects[i]; string name=c.ChartObjectName(); string split[]; StringSplit(name,StringGetCharacter("_",0),split); int startIndex=split[0]; int endIndex=split[1]; int x=0; int y=0; ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,startIndex),iHigh(Symbol(),PERIOD_CURRENT,startIndex),x,y); int x1=0; int y1=0; ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,endIndex),iLow(Symbol(),PERIOD_CURRENT,endIndex),x1,y1); double priceWidth=x1-x; double priceHeight=y1-y; double fillRectangleSize=priceHeight/3; c.FillRectangle(0,0,priceWidth,fillRectangleSize,ColorToARGB(clrRed, 50)); c.FillRectangle(0,fillRectangleSize,priceWidth,fillRectangleSize*2,ColorToARGB(clrGreen, 50)); c.FillRectangle(0,fillRectangleSize*2,priceWidth,fillRectangleSize*3,ColorToARGB(clrBlue, 50)); c.Update(); } } }
Update to the code above.
Some problem solved. But there's still flickering.
#property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com/en/users/abiotamalo" #property version "1.00" #property indicator_chart_window #property indicator_buffers 1 #include <Canvas\Canvas.mqh> #include <Canvas\Charts\HistogramChart.mqh> CCanvas canvasObjects[]; int Counter=0; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ int OnInit() { //--- create canvas int x=0; int y=0; ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,144),iHigh(Symbol(),PERIOD_CURRENT,144),x,y); int x1=0; int y1=0; ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,97),iLow(Symbol(),PERIOD_CURRENT,97),x1,y1); double priceWidth=x1-x; double priceHeight=y1-y; bool objCreated=false; /* First canvas object */ if(true) { CCanvas canvas; string name="144_97";//name consists of the start & end index datetime startTime=iTime(Symbol(),PERIOD_CURRENT,144); double startignPoint=iHigh(Symbol(),PERIOD_CURRENT,144); bool objCreated=canvas.CreateBitmap(name,startTime,startignPoint,x1-x,y1-y,COLOR_FORMAT_ARGB_NORMALIZE); double fillRectangleSize=priceHeight/3; canvas.Erase(ColorToARGB(clrBlack, 0)); ArrayResize(canvasObjects,1); canvasObjects[ArraySize(canvasObjects)-1]=canvas; } ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,50),iHigh(Symbol(),PERIOD_CURRENT,50),x,y); x1=0; y1=0; ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,8),iLow(Symbol(),PERIOD_CURRENT,8),x1,y1); priceWidth=x1-x; priceHeight=y1-y; objCreated=false; /* Second Canvas Object */ if(true) { CCanvas canvas; string name="50_8"; datetime startTime=iTime(Symbol(),PERIOD_CURRENT,50); double startignPoint=iHigh(Symbol(),PERIOD_CURRENT,50); objCreated=canvas.CreateBitmap(name,startTime,startignPoint,x1-x,y1-y,COLOR_FORMAT_ARGB_NORMALIZE); canvas.Erase(ColorToARGB(clrRed, 0)); canvas.Update(); ArrayResize(canvasObjects,2); canvasObjects[ArraySize(canvasObjects)-1]=canvas; } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { return rates_total; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if(id==CHARTEVENT_CHART_CHANGE) { for(int i=0;i<ArraySize(canvasObjects);i++){ CCanvas c=canvasObjects[i]; string name=c.ChartObjectName(); string split[]; StringSplit(name,StringGetCharacter("_",0),split); int startIndex=split[0]; int endIndex=split[1]; int x=0; int y=0; datetime startTime=iTime(Symbol(),PERIOD_CURRENT,startIndex); double startignPoint=iHigh(Symbol(),PERIOD_CURRENT,startIndex); ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,startIndex),iHigh(Symbol(),PERIOD_CURRENT,startIndex),x,y); int x1=0; int y1=0; ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,endIndex),iLow(Symbol(),PERIOD_CURRENT,endIndex),x1,y1); double priceWidth=x1-x; double priceHeight=y1-y; double fillRectangleSize=priceHeight/3; bool objCreated=c.CreateBitmap(name,startTime,startignPoint,x1-x,y1-y,COLOR_FORMAT_ARGB_NORMALIZE);//Looks like I have to do this part which is reduntant. //otherwise there's the update issue e.g. width doesn't resize accordingly. c.FillRectangle(0,0,priceWidth,fillRectangleSize,ColorToARGB(clrRed, 50)); if(i==0)//Just width variation on the middle bar c.FillRectangle(0,fillRectangleSize,priceWidth*0.5,fillRectangleSize*2,ColorToARGB(clrGreen, 50)); else c.FillRectangle(0,fillRectangleSize,priceWidth*0.2,fillRectangleSize*2,ColorToARGB(clrGreen, 50)); c.FillRectangle(0,fillRectangleSize*2,priceWidth,fillRectangleSize*3,ColorToARGB(clrBlue, 50)); c.Update(); } } }
It's a shame that you don't read the answers to your questions. ChartTimePriceToXY!!!
Yes I did, I'm sorry I didn't respond. Because I don't know what are the alternative to ChartTimePriceToXY. It's also because MQL5 shop wouldn't allow to upload & sell an indicator that includes external library other than MQL5's default lib files in the include folder. Right?
No you don't need that.
When is it flickering ? Doing what ? Can you record your screen to show it ?
Sure, please watch it here https://gemoo.com/tools/upload-video/share/569644129862852608?codeId=DGqjl3Veg12Xb&card=569644126134116352
- gemoo.com
Another issue is deleting these canvas objects
I can't delete canvas objects using this function below
void OnDeinit(const int r){ for(int i=0;i<ArraySize(canvasObjects);i++){ CCanvas c=canvasObjects[i]; c.Destroy();//This alone doesn't work c.Update();//Doesn't work } }
I have to use ObjectDelete() and ChartRedraw() to delete the canvas which are not functions belong to the Canvas class. Below is a working code.
void OnDeinit(const int r){ for(int i=0;i<ArraySize(canvasObjects);i++){ CCanvas c=canvasObjects[i]; //c.Destroy();//This alone doesn't work Print(c.ChartObjectName()); ObjectDelete(0,c.ChartObjectName()); ChartRedraw(); } }
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
Below is a code that creates 2 bitmap object.
These objects gets resized accordingly whenever there's changes to the chart ie slide, zoom.
You will see those objects flickering when you slide & zoom.
Thanks!