Discussion of article "Graphical Interfaces X: The Standard Chart Control (build 4)" - page 2
You are missing trading opportunities:
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
Registration
Log in
You agree to website policy and terms of use
If you do not have an account, please register
Anatoly, tell me what the cause of the error is
Everything worked fine before this update. Now when building the CTable table this error pops up.
Please tell me where it is wrong - I have already printed every line - the interface is built, but after somewhere stumbles, and .... error.
File with an example in the archive.
I forgot to make a correction, as it was done earlier in the CCanvasTable class.
In the CTable class, you need to replace the current versions of the CreateScrollV() and CreateScrollH() methods with the ones shown in the listing below:
//|| Creates a vertical scroll bar ||
//+------------------------------------------------------------------+
bool CTable::CreateScrollV(void)
{
//--- Save the form pointer
m_scrollv.WindowPointer(m_wnd);
//--- Coordinates
int x=(m_anchor_right_window_side)? m_x-m_x_size+m_scrollv.ScrollWidth() : CElement::X2()-m_scrollv.ScrollWidth();
int y=CElement::Y();
//--- Set dimensions
m_scrollv.Id(CElement::Id());
m_scrollv.IsDropdown(CElement::IsDropdown());
m_scrollv.XSize(m_scrollv.ScrollWidth());
m_scrollv.YSize((m_columns_total>m_visible_columns_total)? m_y_size-m_scrollv.ScrollWidth()+1 : m_y_size);
m_scrollv.AnchorRightWindowSide(m_anchor_right_window_side);
m_scrollv.AnchorBottomWindowSide(m_anchor_bottom_window_side);
//--- Creating a scroll bar
if(!m_scrollv.CreateScroll(m_chart_id,m_subwin,x,y,m_rows_total,m_visible_rows_total))
return(false);
//--- Hide if not needed now
if(m_rows_total<=m_visible_rows_total)
m_scrollv.Hide();
//---
return(true);
}
//+------------------------------------------------------------------+
//|| Creates a horizontal scroll bar ||
//+------------------------------------------------------------------+
bool CTable::CreateScrollH(void)
{
//--- Save the form pointer
m_scrollh.WindowPointer(m_wnd);
//--- Coordinates
int x=CElement::X();
int y=(m_anchor_bottom_window_side)? m_y-m_area.Y_Size()+m_scrollh.ScrollWidth() : CElement::Y2()-m_scrollh.ScrollWidth();
//--- Set dimensions
m_scrollh.Id(CElement::Id());
m_scrollh.IsDropdown(CElement::IsDropdown());
m_scrollh.XSize((m_rows_total>m_visible_rows_total)? m_area.XSize()-m_scrollh.ScrollWidth()+1 : m_area.XSize());
m_scrollh.YSize(m_scrollh.ScrollWidth());
m_scrollh.AnchorRightWindowSide(m_anchor_right_window_side);
m_scrollh.AnchorBottomWindowSide(m_anchor_bottom_window_side);
//--- Creating a scroll bar
if(!m_scrollh.CreateScroll(m_chart_id,m_subwin,x,y,m_columns_total,m_visible_columns_total))
return(false);
//--- Hide if not needed now
if(m_columns_total<=m_visible_columns_total)
m_scrollh.Hide();
//---
return(true);
}
//---
Similar changes need to be made in the CLabelsTable class. The fixes will be in the next update.
I forgot to make a correction as it was done earlier in the CCanvasTable class.
In the CTable class, you need to replace the current versions of the CreateScrollV() and CreateScrollH() methods with the ones shown in the listing below:
...
//---
Similar changes need to be made in the CLabelsTable class. The fixes will be in the next update.
I forgot to make a correction as it was done earlier in the CCanvasTable class.
In the CTable class, you need to replace the current versions of the CreateScrollV() and CreateScrollH() methods with the ones shown in the listing below:
//|| Creates a vertical scroll bar ||
//+------------------------------------------------------------------+
bool CTable::CreateScrollV(void)
{
//--- Save the form pointer
m_scrollv.WindowPointer(m_wnd);
//--- Coordinates
int x=(m_anchor_right_window_side)? m_x-m_x_size+m_scrollv.ScrollWidth() : CElement::X2()-m_scrollv.ScrollWidth();
int y=CElement::Y();
//--- Set dimensions
m_scrollv.Id(CElement::Id());
m_scrollv.IsDropdown(CElement::IsDropdown());
m_scrollv.XSize(m_scrollv.ScrollWidth());
m_scrollv.YSize((m_columns_total>m_visible_columns_total)? m_y_size-m_scrollv.ScrollWidth()+1 : m_y_size);
m_scrollv.AnchorRightWindowSide(m_anchor_right_window_side);
m_scrollv.AnchorBottomWindowSide(m_anchor_bottom_window_side);
//--- Creating a scroll bar
if(!m_scrollv.CreateScroll(m_chart_id,m_subwin,x,y,m_rows_total,m_visible_rows_total))
return(false);
//--- Hide if not needed now
if(m_rows_total<=m_visible_rows_total)
m_scrollv.Hide();
//---
return(true);
}
//+------------------------------------------------------------------+
//|| Creates a horizontal scroll bar ||
//+------------------------------------------------------------------+
bool CTable::CreateScrollH(void)
{
//--- Save the form pointer
m_scrollh.WindowPointer(m_wnd);
//--- Coordinates
int x=CElement::X();
int y=(m_anchor_bottom_window_side)? m_y-m_area.Y_Size()+m_scrollh.ScrollWidth() : CElement::Y2()-m_scrollh.ScrollWidth();
//--- Set dimensions
m_scrollh.Id(CElement::Id());
m_scrollh.IsDropdown(CElement::IsDropdown());
m_scrollh.XSize((m_rows_total>m_visible_rows_total)? m_area.XSize()-m_scrollh.ScrollWidth()+1 : m_area.XSize());
m_scrollh.YSize(m_scrollh.ScrollWidth());
m_scrollh.AnchorRightWindowSide(m_anchor_right_window_side);
m_scrollh.AnchorBottomWindowSide(m_anchor_bottom_window_side);
//--- Creating a scroll bar
if(!m_scrollh.CreateScroll(m_chart_id,m_subwin,x,y,m_columns_total,m_visible_columns_total))
return(false);
//--- Hide if not needed now
if(m_columns_total<=m_visible_columns_total)
m_scrollh.Hide();
//---
return(true);
}
//---
Similar changes need to be made in the CLabelsTable class. The fixes will be in the next update.
Anatoly, the changes have been made. Take the example from MQL5\Indicators\Article07\ChartWindow02\ChartWindow02.mq5, correct the table in Program.mqh so that the number of rows coincides with the visible number of rows, or the number of columns coincides with the visible number of columns, or both. For example:
//|| Creates a table|
//+------------------------------------------------------------------+
bool CProgram::CreateTable(void)
{
#define COLUMNS1_TOTAL (6)
#define ROWS1_TOTAL (15)
//--- Save the pointer to the form
m_table.WindowPointer(m_window1);
//--- Coordinates
int x=m_window1.X()+TABLE1_GAP_X;
int y=m_window1.Y()+TABLE1_GAP_Y;
//--- Number of visible columns and rows
int visible_columns_total =6;
int visible_rows_total =15;
//--- Set properties before creation
m_table.XSize(600);
m_table.RowYSize(20);
m_table.FixFirstRow(true);
m_table.FixFirstColumn(true);
m_table.LightsHover(true);
m_table.SelectableRow(true);
m_table.TextAlign(ALIGN_CENTER);
m_table.HeadersColor(C'255,244,213');
m_table.HeadersTextColor(clrBlack);
m_table.CellColorHover(clrGold);
m_table.TableSize(COLUMNS1_TOTAL,ROWS1_TOTAL);
m_table.VisibleTableSize(visible_columns_total,visible_rows_total);
//--- Create a control
if(!m_table.CreateTable(m_chart_id,m_subwin,x,y))
return(false);
//--- Let's fill in the table:
// The first cell is empty
m_table.SetValue(0,0,"-");
//--- Headings for columns
for(int c=1; c<COLUMNS1_TOTAL; c++)
{
for(int r=0; r<1; r++)
m_table.SetValue(c,r,"SYMBOL "+string(c));
}
//--- Headings for rows, text alignment method - to the right
for(int c=0; c<1; c++)
{
for(int r=1; r<ROWS1_TOTAL; r++)
{
m_table.SetValue(c,r,"PARAMETER "+string(r));
m_table.TextAlign(c,r,ALIGN_RIGHT);
}
}
//--- Data and table formatting (background colour and cell colour)
for(int c=1; c<COLUMNS1_TOTAL; c++)
{
for(int r=1; r<ROWS1_TOTAL; r++)
{
m_table.SetValue(c,r,string(c)+":"+string(r));
m_table.TextColor(c,r,(c%2==0)? clrRed : clrRoyalBlue);
m_table.CellColor(c,r,(r%2==0)? clrWhiteSmoke : clrWhite);
}
}
//--- Update the table to show changes
m_table.UpdateTable();
//--- Add the object to the common array of object groups
CWndContainer::AddToElementsArray(0,m_table);
return(true);
}
//+------------------------------------------------------------------+
Compile, run the example, click on the lowest row of the table (everything is fine), and then click on it again. On the second click an error pops up:
What to do, and what to do?
Anatoly, the changes have been made. Take the example from MQL5\Indicators\Article07\ChartWindow02\ChartWindow02.mq5, correct the table in Program.mqh so that the number of rows coincides with the visible number of rows, or the number of columns coincides with the visible number of columns, or both. For example, like this:
...
Compile, run the example, click on the lowest row of the table (everything is fine), and then click on it again. An error appears on the second click:
What to do, and what to do?
In the CScrollH and CScrollV classes in the ScrollBarControl() methods, you need to add an additional check on the visibility of the element as shown in the listing below:
//| Scroll control|
//+------------------------------------------------------------------+
bool CScrollH::ScrollBarControl(const int x,const int y,const bool mouse_state)
{
//--- Exit if there is no pointer to the form
if(::CheckPointer(m_wnd)==POINTER_INVALID)
return(false);
//--- Exit if the form is blocked by another element
if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
return(false);
//--- Exit if the item is hidden
if(!CElement::IsVisible())
return(false);
//--- Checking the focus over the slider
m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() &&
y>m_thumb.Y() && y<m_thumb.Y2());
//--- Check and remember the state of the mouse button
CScroll::CheckMouseButtonState(mouse_state);
//--- Change the colour of the list scroll bar
CScroll::ChangeObjectsColor();
//--- If control is passed to the scroll bar, define the slider position
if(CScroll::ScrollState())
{
//--- Moving the slider
OnDragThumb(x);
//--- Changes the slider position number
CalculateThumbPos();
return(true);
}
return(false);
}
//---
The fix will be available in the next library update.
In the CScrollH and CScrollV classes in the ScrollBarControl() methods, we need to add an additional check for the visibility of the element as shown in the listing below:
...
The fix will be available in the next library update.
Thanks. I made these changes: in the Scrolls.mqh file in the CScrollH and CScrollV classes I added lines:
//| Slider control|
//+------------------------------------------------------------------+
bool CScrollV::ScrollBarControl(const int x,const int y,const bool mouse_state)
{
//--- Exit if there is no pointer to the form
if(::CheckPointer(m_wnd)==POINTER_INVALID)
return(false);
//--- If the form is not locked and the identifiers match
if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
return(false);
//--- Exit if the item is hidden
if(!CElement::IsVisible())
return(false);
//--- Checking the focus over the slider
m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() &&
y>m_thumb.Y() && y<m_thumb.Y2());
//--- Check and remember the state of the mouse button
CScroll::CheckMouseButtonState(mouse_state);
//--- Change the colour of the slider
CScroll::ChangeObjectsColor();
//--- If control is passed to the scroll bar, define the slider position
if(CScroll::ScrollState())
{
//--- Moving the slider
OnDragThumb(y);
//--- Changes the slider position number
CalculateThumbPos();
return(true);
}
//---
return(false);
}
//+------------------------------------------------------------------+
//| Scroll control|
//+------------------------------------------------------------------+
bool CScrollH::ScrollBarControl(const int x,const int y,const bool mouse_state)
{
//--- Exit if there is no pointer to the form
if(::CheckPointer(m_wnd)==POINTER_INVALID)
return(false);
if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
return(false);
//--- Exit if the item is hidden
if(!CElement::IsVisible())
return(false);
//--- Checking the focus over the slider
m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() &&
y>m_thumb.Y() && y<m_thumb.Y2());
//--- Check and remember the state of the mouse button
CScroll::CheckMouseButtonState(mouse_state);
//--- Change the colour of the list scroll bar
CScroll::ChangeObjectsColor();
//--- If control is passed to the scroll bar, define the slider position
if(CScroll::ScrollState())
{
//--- Moving the slider
OnDragThumb(x);
//--- Changes the slider position number
CalculateThumbPos();
return(true);
}
return(false);
}
//+------------------------------------------------------------------+
I compile and run the same test file from \MQL5\Indicators\Article07\ChartWindow02\ChartWindow02 .mq5, in which I changed the table building function in Program.mqh so that the number of all columns and rows coincides with the number of visible columns and rows:
//|| Creates a table|
//+------------------------------------------------------------------+
bool CProgram::CreateTable(void)
{
#define COLUMNS1_TOTAL (6)
#define ROWS1_TOTAL (15)
//--- Save the pointer to the form
m_table.WindowPointer(m_window1);
//--- Coordinates
int x=m_window1.X()+TABLE1_GAP_X;
int y=m_window1.Y()+TABLE1_GAP_Y;
//--- Number of visible columns and rows
int visible_columns_total =6;
int visible_rows_total =15;
//--- Set properties before creation
m_table.XSize(600);
m_table.RowYSize(20);
m_table.FixFirstRow(true);
m_table.FixFirstColumn(true);
m_table.LightsHover(true);
m_table.SelectableRow(true);
m_table.TextAlign(ALIGN_CENTER);
m_table.HeadersColor(C'255,244,213');
m_table.HeadersTextColor(clrBlack);
m_table.CellColorHover(clrGold);
m_table.TableSize(COLUMNS1_TOTAL,ROWS1_TOTAL);
m_table.VisibleTableSize(visible_columns_total,visible_rows_total);
//--- Create a control
if(!m_table.CreateTable(m_chart_id,m_subwin,x,y))
return(false);
//--- Let's fill in the table:
// The first cell is empty
m_table.SetValue(0,0,"-");
//--- Headings for columns
for(int c=1; c<COLUMNS1_TOTAL; c++)
{
for(int r=0; r<1; r++)
m_table.SetValue(c,r,"SYMBOL "+string(c));
}
//--- Headings for rows, text alignment method is right aligned
for(int c=0; c<1; c++)
{
for(int r=1; r<ROWS1_TOTAL; r++)
{
m_table.SetValue(c,r,"PARAMETER "+string(r));
m_table.TextAlign(c,r,ALIGN_RIGHT);
}
}
//--- Data and table formatting (background colour and cell colour)
for(int c=1; c<COLUMNS1_TOTAL; c++)
{
for(int r=1; r<ROWS1_TOTAL; r++)
{
m_table.SetValue(c,r,string(c)+":"+string(r));
m_table.TextColor(c,r,(c%2==0)? clrRed : clrRoyalBlue);
m_table.CellColor(c,r,(r%2==0)? clrWhiteSmoke : clrWhite);
}
}
//--- Update the table to show changes
m_table.UpdateTable();
//--- Add the object to the common array of object groups
CWndContainer::AddToElementsArray(0,m_table);
return(true);
}
//+------------------------------------------------------------------+
Compile and run ChartWindow02.ex5
Several times we click on the lowest row of the table and get a flight outside the array:
...
So nothing has changed?After the changes I made, it doesn't play anymore. I may have made some other changes, but I don't remember. I don't have a history of minor edits.
Just in case, try replacing CScroll::Show() and CScroll::Hide() methods with these versions, if they are different:
//| Shows the menu item|
//+------------------------------------------------------------------+
void CScroll::Show(void)
{
//--- Exit if the number of list items is not greater than the number of the visible part of the list
if(m_items_total<=m_visible_items_total)
return;
//---
m_area.Timeframes(OBJ_ALL_PERIODS);
m_bg.Timeframes(OBJ_ALL_PERIODS);
m_inc.Timeframes(OBJ_ALL_PERIODS);
m_dec.Timeframes(OBJ_ALL_PERIODS);
m_thumb.Timeframes(OBJ_ALL_PERIODS);
//--- Update the position of objects
Moving(m_wnd.X(),m_wnd.Y(),true);
//--- Visibility status
CElement::IsVisible(true);
}
//+------------------------------------------------------------------+
//| Hides the menu item|
//+------------------------------------------------------------------+
void CScroll::Hide(void)
{
m_area.Timeframes(OBJ_NO_PERIODS);
m_bg.Timeframes(OBJ_NO_PERIODS);
m_inc.Timeframes(OBJ_NO_PERIODS);
m_dec.Timeframes(OBJ_NO_PERIODS);
m_thumb.Timeframes(OBJ_NO_PERIODS);
//--- Visibility status
CElement::IsVisible(false);
}
//---
If it doesn't help, you'll have to wait for the next update.
But after the changes I made, it doesn't play anymore. I may have made some other changes, but I don't remember. I don't mark the history of minor edits.
Just in case, try replacing CScroll::Show() and CScroll::Hide() methods with these versions, if they are different:
//| Shows the menu item|
//+------------------------------------------------------------------+
void CScroll::Show(void)
{
//--- Exit if the number of list items is not greater than the number of the visible part of the list
if(m_items_total<=m_visible_items_total)
return;
//---
m_area.Timeframes(OBJ_ALL_PERIODS);
m_bg.Timeframes(OBJ_ALL_PERIODS);
m_inc.Timeframes(OBJ_ALL_PERIODS);
m_dec.Timeframes(OBJ_ALL_PERIODS);
m_thumb.Timeframes(OBJ_ALL_PERIODS);
//--- Update the position of objects
Moving(m_wnd.X(),m_wnd.Y(),true);
//--- Visibility status
CElement::IsVisible(true);
}
//+------------------------------------------------------------------+
//| Hides the menu item|
//+------------------------------------------------------------------+
void CScroll::Hide(void)
{
m_area.Timeframes(OBJ_NO_PERIODS);
m_bg.Timeframes(OBJ_NO_PERIODS);
m_inc.Timeframes(OBJ_NO_PERIODS);
m_dec.Timeframes(OBJ_NO_PERIODS);
m_thumb.Timeframes(OBJ_NO_PERIODS);
//--- Visibility status
CElement::IsVisible(false);
}
//---
If it doesn't help, you'll have to wait for the next update.
Thanks, it seems to help. There were missing lines about visibility status in Show():
CElement::IsVisible(true);
: and Hide():
CElement::IsVisible(false);
Thanks, it seems to have worked. There were missing lines about visibility status in Show():
CElement::IsVisible(true);
and Hide():
CElement::IsVisible(false);
One more correction is needed. Visibility should be set before updating the position of the element. Like this:
//--- Visibility status
CElement::IsVisible(true);
//--- Update the position of objects
Moving(m_wnd.X(),m_wnd.Y(),true);
...
Interactivity of interface elements implemented via timer is a strange solution. - Why should it be implemented through (or with) a timer? - Of course, it will consume a lot of resources.
You don't need a timer at all to control the states of controls.
1. Record the current coordinates of all elements in the array (map). Make adjustments to the location coordinates of all form objects as you move the window.
2. Make a function to find elements by coordinates (localiser). The function will loop through the recorded current element coordinates and find the element that is now under the cursor.
3. Call the localiser from the "CHARTEVENT_MOUSE_MOVE" event (on the cursor movement event).
4. Pass the object name returned from the localiser to the interactivity function, where the ObjectSetInteger() function will be applied to the object, which will force it to change its colour.
As you can see, there is no timer in this scheme, so there is no unnecessary consumption of resources.
Interactivity of interface elements implemented via timer is a strange solution. - Why should it be implemented through (or with) a timer? - Of course, it will consume a lot of resources.
...
As you can see, there is no timer in this scheme, so there is no unnecessary resource consumption.
You are wrong. I have already answered in enough detail in the comments above why it was done this way.
It doesn't consume a lot of resources now (now in Windows 10 too). Did you read the article (and the comments too) ?
//---
P.S. By the way, CPU resource consumption in different terminals (MT4/MT5) and OS versions (Windows) is very different under equal conditions. In Windows 7 the MetaTrader 4 terminal showed itself significantly better than MetaTrader 5. Unfortunately, I can't give you the figures now, as I have already completely switched to Windows 10.
As for optimisation, I have not exhausted all the options yet. There is still something to optimise and an understanding of how.