Libraries: EasyAndFastGUI library for creating graphical interfaces - page 11

 
Anatoli Kazharski:

Initially there was simply no such task that after creating the GUI it was necessary to move elements. Everything was based on the idea, when each element already had all the necessary behaviour implemented.

Counter questions: Why do you need to move elements? What do you want to do? What behaviour when interacting with the GUI do you want to get?

To understand if something will break, you need to test all elements after each change in base classes. It's already hard to say that right away. It's been a while since I've looked deep.

Create a test GUI with all elements of the library and test them after changes.

For example, expandable lists. When you click, some of the elements are hidden, everything below is pulled up. And vice versa.

Test GUI is a good idea, I'll have to try to make it :)

By the way, in the same CElement::Moving.

//--- If the binding is on the right
   if(m_anchor_right_window_side)
     {
      //--- Saving coordinates in element fields
      CElementBase::X(m_main.X2()-XGap());
      //--- Saving coordinates in object fields
      m_canvas.X(m_main.X2()-m_canvas.XGap());
     }
   else
     {
      CElementBase::X(m_main.X()+XGap());
      m_canvas.X(m_main.X()+m_canvas.XGap());
     }
//--- If the binding is from below
   if(m_anchor_bottom_window_side)
     {
      CElementBase::Y(m_main.Y2()-YGap());
      m_canvas.Y(m_main.Y2()-m_canvas.YGap());
     }
   else
     {
      CElementBase::Y(m_main.Y()+YGap());
      m_canvas.Y(m_main.Y()+m_canvas.YGap());
     }

If there is a binding, the element moves together with the canvas. So theoretically nothing should break :)

 

Has anyone tried to create a combobox using that library - to change elements in it ????? Share How do you do it?

I create a combobox, everything works. Then I fill it with elements using the following function:

void CPresenter::setCombobox(CComboBox *cb_ptr,CArrayString &arr)
  {
   CListView *lv_ptr=cb_ptr.GetListViewPointer();
   lv_ptr.Clear(true);
   
   cb_ptr.ItemsTotal(arr.Total());
   for(int i=0;i<arr.Total();i++)
      cb_ptr.SetValue(i,arr[i]);
   lv_ptr.SelectItem(0,true);
   cb_ptr.SelectItem(0);
   cb_ptr.Update(true);
   cb_ptr.GetButtonPointer().Update(true);
  }

Everything works. After I select in the filled combobox - for example, the third value. and click on the button, the result of which is a series of actions resulting in the overflow of the combobox. And I refill it with one value (for example, initially there were 20 items in it, after clicking the button there is only one item left !).

And here comes an interesting error - after everything is overwritten (using the above function) - I try to open the combo box, but I can't do it, because the error Array out of range!
The error occurs in the method:
void CListView::RedrawItemsByMode(const bool is_selected_item=false).

On line 1364. As I found out by digging around, it occurs because :
1) when selecting the third item of the list (before pressing the button) - the variable
m_prev_item_index_focus is filled with an index equal to 3.

Then this index is passed through the prev_item_index variable to the
indexes

array on line 1357. The result of which - on line 1364 - is the selection of a value from the array
m_items

at index #2 (index corresponding to the last selected element), while the array (m_items) has only one value at index #0.

I'm digging for the second day and still couldn't find the place where the value of the variable
m_prev_item_index_focus would be reset to zero.

Logically, it should be cleared in the Clear method of the CListView class, which I used to clear all the items there, but unfortunately I couldn't find such a method there....


In connection with all of the above question:
1) Is it a bug in the library, or am I updating the values incorrectly?
2) What is the best way around this problem?

 
The minimum reproducible code for my question:

//+------------------------------------------------------------------+
//|TestCombobox.mq5 |
//| Copyright 2018, MetaQuotes Software Corp. | |
//| https://www.mql5.com |
//+------------------------------------------------------------------+

#include <EasyAndFastGUI\WndEvents.mqh>
#include <Arrays/ArrayString.mqh>
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
class CWindowManager : public CWndEvents
  {
public:
   void              OnDeinitEvent(const int reason){CWndEvents::Destroy();};
   //--- Graph event handler
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);//

   //--- Creates the graphical interface of the programme
   bool              CreateGUI(void);

private:
   CComboBox         m_cb;
   CButton           m_btn;

   void              Btn_Click(int id,long lparam);

   bool              CreateComboBox(const string comboBox_name,
                                    const string &items_text[],
                                    const int x_gap,
                                    const int y_gap,
                                    const int x_size,
                                    const int y_size,
                                    CComboBox &comboBox_link,
                                    int x_ButtonSize=0);
   bool              CreateButton(const string text,
                                  const int x_gap,
                                  const int y_gap,
                                  const int x_size,
                                  const int y_size,
                                  CButton &btn_link);
   bool              CreateWindow(const string text);

   void              setCombobox(CComboBox *cb_ptr,CArrayString &arr);
   //--- Main window
   CWindow           m_window;
   //--- Chart window ID and number
   long              m_chart_id;
   int               m_subwin;
  };

CWindowManager _window;
//+------------------------------------------------------------------+
//| Expert initialisation function|
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   if(!_window.CreateGUI())
     {
      Print(__FUNCTION__," > Failed to create a GUI!");
      return(INIT_FAILED);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialisation function|
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   _window.OnDeinitEvent(reason);
  }
//+------------------------------------------------------------------+
//| Expert tick function|
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void OnChartEvent(const int    id,
                  const long   &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   _window.ChartEvent(id,lparam,dparam,sparam);
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void CWindowManager::setCombobox(CComboBox *cb_ptr,CArrayString &arr)
  {
   CListView *lv_ptr=cb_ptr.GetListViewPointer();

   lv_ptr.Clear(true);
   cb_ptr.ItemsTotal(arr.Total());
   for(int i=0;i<arr.Total();i++)
      cb_ptr.SetValue(i,arr[i]);
   lv_ptr.SelectItem(0,true);
   cb_ptr.SelectItem(0);
   cb_ptr.Update(true);
   cb_ptr.GetButtonPointer().Update(true);
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
bool CWindowManager::CreateWindow(const string text)
  {
//--- Add the window pointer to the window array
   CWndContainer::AddWindow(m_window);
//--- Coordinates
   int x=(m_window.X()>0) ? m_window.X() : 1;
   int y=(m_window.Y()>0) ? m_window.Y() : 1;
//--- Properties
   m_window.XSize(300);
   m_window.YSize(300);
   m_window.Alpha(200);
   m_window.IconXGap(3);
   m_window.IconYGap(2);
   m_window.IsMovable(true);
   m_window.ResizeMode(false);
   m_window.CloseButtonIsUsed(true);
   m_window.FullscreenButtonIsUsed(false);
   m_window.CollapseButtonIsUsed(true);
   m_window.TooltipsButtonIsUsed(false);
   m_window.RollUpSubwindowMode(true,true);
   m_window.TransparentOnlyCaption(true);

//--- Set tooltips
   m_window.GetCloseButtonPointer().Tooltip("Close");
   m_window.GetCollapseButtonPointer().Tooltip("Collapse/Expand");
//--- Form creation
   if(!m_window.CreateWindow(m_chart_id,m_subwin,text,x,y))
      return(false);
//---
   return(true);
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
bool CWindowManager::CreateButton(const string text,
                                  const int x_gap,
                                  const int y_gap,
                                  const int x_size,
                                  const int y_size,
                                  CButton &btn_link)
  {
//--- Save the pointer to the main element
   btn_link.MainPointer(m_window);
//--- Properties
   btn_link.XSize(x_size);
   btn_link.YSize(y_size);
   btn_link.IconXGap(3);
   btn_link.IconYGap(3);
   btn_link.IsCenterText(true);
//--- Create a control
   if(!btn_link.CreateButton(text,x_gap,y_gap))
      return(false);
//--- Add a pointer to the element in the base
   CWndContainer::AddToElementsArray(0,btn_link);
   return(true);
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
bool CWindowManager::CreateComboBox(const string comboBox_name,
                                    const string &items_text[],
                                    const int x_gap,
                                    const int y_gap,
                                    const int x_size,
                                    const int y_size,
                                    CComboBox &comboBox_link,
                                    int x_lableXSize)
  {
//--- Save the pointer to the main element
   comboBox_link.MainPointer(m_window);

   if(x_lableXSize==0)
      x_lableXSize=x_size;

   int items_total=ArraySize(items_text);

//--- Set properties before creation
   comboBox_link.XSize(x_size);
   comboBox_link.YSize(y_size);
   comboBox_link.ItemsTotal(items_total);
   comboBox_link.AnchorRightWindowSide(false);
   comboBox_link.GetButtonPointer().YSize(y_size);

   if(StringCompare(comboBox_name,"")==0)
     {
      comboBox_link.GetButtonPointer().XSize(x_size);
      comboBox_link.GetButtonPointer().AnchorRightWindowSide(true);
     }
   else
     {
      comboBox_link.GetButtonPointer().XSize(x_lableXSize);
      comboBox_link.GetButtonPointer().AnchorRightWindowSide(false);
     }

//--- Save the item values to the combo box list
   for(int i=0;i<items_total;i++)
      comboBox_link.SetValue(i,items_text[i]);

//--- Get the list pointer
   CListView *lv=comboBox_link.GetListViewPointer();

//--- Set list properties
   lv.YSize((int)MathMin(items_total*y_size,150));
   lv.LightsHover(true);
   lv.SelectItem(lv.SelectedItemIndex()==WRONG_VALUE ? 0 : lv.SelectedItemIndex());

//--- Create a control
   if(!comboBox_link.CreateComboBox(comboBox_name,x_gap,y_gap))
      return false;

   CWndContainer::AddToElementsArray(0,comboBox_link);
   return true;
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
bool CWindowManager::CreateGUI(void)
  {
   if(!CreateWindow("Combobox Bug ???? "))
      return(false);
   string cb_arr[20];
   for(int i=0;i<20;i++)
      cb_arr[i]=IntegerToString(i+1);
   if(!CreateComboBox("",cb_arr,100,100,100,20,m_cb))
      return false;
   if(!CreateButton("Action",100,130,50,20,m_btn))
      return false;

// Show window
   CWndEvents::CompletedGUI();
   return true;
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void CWindowManager::Btn_Click(int id,long lparam)
  {
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_btn.Id())
     {
      CArrayString s;
      s.Add("new value");
      setCombobox(&m_cb,s);
     }
  }
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
void CWindowManager::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
   Btn_Click(id,lparam);
  }
//+------------------------------------------------------------------+



So far, all the solutions I've found come down to editing the library code (adding new 3 lines of code) - but I don't like the idea of tweaking someone else's code...

 
Andrey Azatskiy:
Minimum reproducible code for my question:

...

So far all the solutions I've found come down to editing the library code (adding new 3 lines of code) - but I don't like the idea of tweaking someone else's code...

Thanks for the message.

Try making a small addition to the CListView class method. You need to zero out the auxiliary fields as noted below:

//+------------------------------------------------------------------+
//| Clears the list (deletes all items) |
//+------------------------------------------------------------------+
void CListView::Clear(const bool redraw=false)
  {
//--- Reset auxiliary fields to zero
   m_item_index_focus      =WRONG_VALUE;
   m_prev_selected_item    =WRONG_VALUE;
   m_prev_item_index_focus =WRONG_VALUE;
//--- Set the size to zero
   ListSize(0);
//--- Calculate and set new list sizes
   RecalculateAndResizeList(redraw);
  }
 
Anatoli Kazharski:

Thank you for the message.

Try making a small addition to the CListView class method. You need to zero out the auxiliary fields as noted below:

Thank you for your reply.

 
Anatoli Kazharski:

How about a repository on bitbucket and accepting commits from active library users?

We'll finish it faster together ;)

 

Can you tell me how to correctly handle the window close button?

The problem is as follows: I place an Expert Advisor (for example, ExampleEAF.ex5) and my indicator in a separate window under the chart (the minimal code only displays an empty window). Then I click the close window button on any of these applications and both are closed (removed from the chart).

This is not quite correct behaviour. Is there any way to distinguish events for different applications working simultaneously on the same chart? There is a suspicion that other events may also overlap.

 
Andrey Khatimlianskii:

How about a repository on bitbucket and accepting commits from active library users?

We'll finish it faster together ;)

I've already been given access. I have doubts about many of the edits.

There is no justification for these or those changes. It is easier to discuss it on the forum here.

If any changes are made, it is necessary to give examples and test results with explanation why it will be better.

 
dmyger:

Can you tell me how to handle the window close button correctly?

The problem is as follows: I place an Expert Advisor (for example, ExampleEAF.ex5) and my indicator in a separate window under the chart (the minimal code only displays an empty window). Then I click the close window button on any of these applications and both of them are closed (removed from the chart).

This is not quite correct behaviour. Is there any way to distinguish events for different applications working simultaneously on the same chart? I suspect that other events may overlap as well.

I will test it when I have time and report the result here.

 

Andrey Khatimlianskii:

Как на счет репозитория на битбакете и принятия коммитов от активных пользователей библиотеки?

Вместе быстрее допилим ;)

Anatoli Kazharski:

...

If any changes are made, it is necessary to give examples and test results with an explanation of why it would be better.

At least briefly. For example:

Corrections in CListView class. In the Clear() method we need to zero out some auxiliary fields to prevent other methods of the class from going outside the array.