Библиотеки: EasyAndFastGUI - библиотека для создания графических интерфейсов - страница 10

 
Oleksii Chepurnyi:

Составные части сложных элементов привязываются к основному, и двигаются вместе сним. На сколько я понял... А холст как-то выпал из этой концепции :)

Целью данного вопроса было узнать, бывают ли случаи, когда нужно двигать элемент без холста или холст без элемента?

Есть идея добавить в CElement::Moving что-то такое

Чтобы холст всегда двигался за элементом.

Ничего не сломается в таком случае? :)

Изначально просто не было такой задачи, чтобы уже после создания GUI нужно было перемещать элементы. Всё закладывалось на идею, когда в каждом элементе было уже всё необходимое поведение реализовано.

Встречные вопросы: Зачем нужно перемещать элементы? Что Вы хотите сделать? Какое поведение при взаимодействии с GUI нужно получить?

Чтобы понять сломается ли что-то, нужно тестировать все элементы после каждого изменения в базовых классах. Так сразу уже сложно сказать. Давно глубоко не заглядывал.

Создайте тестовый GUI, в котором будут все элементы библиотеки и тестируйте после внесённых изменений.

 
Anatoli Kazharski:

Изначально просто не было такой задачи, чтобы уже после создания GUI нужно было перемещать элементы. Всё закладывалось на идею, когда в каждом элементе было уже всё необходимое поведение реализовано.

Встречные вопросы: Зачем нужно перемещать элементы? Что Вы хотите сделать? Какое поведение при взаимодействии с GUI нужно получить?

Чтобы понять сломается ли что-то, нужно тестировать все элементы после каждого изменения в базовых классах. Так сразу уже сложно сказать. Давно глубоко не заглядывал.

Создайте тестовый GUI, в котором будут все элементы библиотеки и тестируйте после внесённых изменений.

Ну, например, разворачивающиеся списки. По клику часть элементов скрывается, все, что ниже, подтягивается вверх. И наоборот.

Тестовый GUI - хорошая идея, нужно будет попробовать сделать :)

Кстати, в этом же CElement::Moving

//--- Если привязка справа
   if(m_anchor_right_window_side)
     {
      //--- Сохранение координат в полях элемента
      CElementBase::X(m_main.X2()-XGap());
      //--- Сохранение координат в полях объектов
      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(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());
     }

Если есть привязка, элемент двигается вместе с холстом. Так что теоретически ничего не должно сломаться :)

 

Кто нибудь пробовал создав комбобокс с помощью той библиотеки - менять в нем жлементы ??? Поделитесь Как Вы это делаете ?

Я создаю комбобокс, все работает. Далее заполняю его элементами при помощи следующей функции:

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);
  }

Все работает. После я выбираю в заполненном комбобоксе - к примеру третье значение. и нажимаю на кнопку, результатом нажатия которой происходит ряд действий итогом которых является перезаполнение комбобокса. Причем перезаполняю его я уже одним значением (к примеру изначально в нем было 20 элементов, после нажатия на кнопку остаеттся лишь один элемент !). 

И тут происходит интересная ошибка - после того как все перезаписалось (при помощи выше предоставленной функции) - я пытаюсь раскрыть комбобокс, но у меня это не получается, так как выскакивает ошибка  Array out of range! 
Ошибка возникает в методе:
void CListView::RedrawItemsByMode(const bool is_selected_item=false)

На строке 1364. Как я выяснил покопавшись, она возникает из за того что :
1) при выбоке третьего элемента списка (перед нажатием на кнопку) - в переменную 
m_prev_item_index_focus

заносится индекс равный 3. После чего жтот индекс передается через переменную prev_item_index в массив
indexes

на строке 1357. Резальтатом чего - на строке 1364 - происзодит выбор значения из массива
m_items

под индексом №  2 (индекс соответствующий прошлому выбранному элементу.) в то время, как массив (m_items) - насчитывает оишь одно значение - под индексом #0

Я копаюсь уже второй день и так и не смог найти место где бы сбрасывалось в нуль значение переменной 
m_prev_item_index_focus. 

Логически предположить что оно должно бы чиститься в методе Clear - класса CListView который я использовал для отчистки всех находившихся там жлементов, однако к сожалению я не смог найти там такового метода...


В связи со всем перечисленным вопрос:
1) Это баг библиотеки, или же я не верно обновляю значения ? 
2) Как бы лучше обойти получивлуюся проблемму ?

 
Минимальный воспроизводимый код моего вопроса:

//+------------------------------------------------------------------+
//|                                                 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();};
   //--- Обработчик события графика
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);//

   //--- Создаёт графический интерфейс программы
   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);
   //--- Главное окно
   CWindow           m_window;
   //--- Идентификатор и номер окна графика
   long              m_chart_id;
   int               m_subwin;
  };

CWindowManager _window;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   if(!_window.CreateGUI())
     {
      Print(__FUNCTION__," > Не удалось создать графический интерфейс!");
      return(INIT_FAILED);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization 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)
  {
//--- Добавим указатель окна в массив окон
   CWndContainer::AddWindow(m_window);
//--- Координаты
   int x=(m_window.X()>0) ? m_window.X() : 1;
   int y=(m_window.Y()>0) ? m_window.Y() : 1;
//--- Свойства
   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);

//--- Установим всплывающие подсказки
   m_window.GetCloseButtonPointer().Tooltip("Close");
   m_window.GetCollapseButtonPointer().Tooltip("Collapse/Expand");
//--- Создание формы
   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)
  {
//--- Сохраним указатель на главный элемент
   btn_link.MainPointer(m_window);
//--- Свойства
   btn_link.XSize(x_size);
   btn_link.YSize(y_size);
   btn_link.IconXGap(3);
   btn_link.IconYGap(3);
   btn_link.IsCenterText(true);
//--- Создадим элемент управления
   if(!btn_link.CreateButton(text,x_gap,y_gap))
      return(false);
//--- Добавим указатель на элемент в базу
   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)
  {
//--- Сохраним указатель на главный элемент
   comboBox_link.MainPointer(m_window);

   if(x_lableXSize==0)
      x_lableXSize=x_size;

   int items_total=ArraySize(items_text);

//--- Установим свойства перед созданием
   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);
     }

//--- Сохраним значения пунктов в список комбо-бокса
   for(int i=0;i<items_total;i++)
      comboBox_link.SetValue(i,items_text[i]);

//--- Получим указатель списка
   CListView *lv=comboBox_link.GetListViewPointer();

//--- Установим свойства списка
   lv.YSize((int)MathMin(items_total*y_size,150));
   lv.LightsHover(true);
   lv.SelectItem(lv.SelectedItemIndex()==WRONG_VALUE ? 0 : lv.SelectedItemIndex());

//--- Создадим элемент управления
   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);
  }
//+------------------------------------------------------------------+



Пока что все решения которые я нашел сводятся к редактированию кода библиотеки (добавлению новых 3 строк кода) - но мне не нравится мысль о корректировки чужого кода...

 
Andrey Azatskiy:
Минимальный воспроизводимый код моего вопроса:

...

Пока что все решения которые я нашел сводятся к редактированию кода библиотеки (добавлению новых 3 строк кода) - но мне не нравится мысль о корректировки чужого кода...

Спасибо за сообщение. 

Попробуйте внести небольшое дополнение в метод класса CListView. Нужно обнулить вспомогательные поля, как отмечено ниже:

//+------------------------------------------------------------------+
//| Очищает список (удаление всех пунктов)                           |
//+------------------------------------------------------------------+
void CListView::Clear(const bool redraw=false)
  {
//--- Обнулить вспомогательные поля
   m_item_index_focus      =WRONG_VALUE;
   m_prev_selected_item    =WRONG_VALUE;
   m_prev_item_index_focus =WRONG_VALUE;
//--- Установим нулевой размер
   ListSize(0);
//--- Рассчитать и установить новые размеры списка
   RecalculateAndResizeList(redraw);
  }
 
Anatoli Kazharski:

Спасибо за сообщение. 

Попробуйте внести небольшое дополнение в метод класса CListView. Нужно обнулить вспомогательные поля, как отмечено ниже:

Благодарю за ответ. 

 
Anatoli Kazharski:

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

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

 

Подскажите как правильно обрабатывать кнопку закрытия окна?

Проблема в следующем: помещаю на график эксперта (к примеру ExampleEAF.ex5) и свой индикатор в отдельное окно под графиком (минимальный код только отображет пустое окно). Далее нажимаю на кнопоку закрыть окно на любом из этих приложений и закрываются (удаляются с графика) оба.

Не совсвем корректное поведение. Есть ли какой способ различать события для разных приложений, работающих одновременно на одном графике? Есть подозрение, что и другие события, так же могут пересекаться.

 
Andrey Khatimlianskii:

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

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

Мне уже дали доступ. Многие правки у меня вызывают сомнения.

Нет обоснования для тех или иных изменений. Проще на форуме здесь вести обсуждение.

Если вносятся, какие-то изменения, то нужно приводить примеры и результаты тестов с объяснением, почему так будет лучше.

 
dmyger:

Подскажите как правильно обрабатывать кнопку закрытия окна?

Проблема в следующем: помещаю на график эксперта (к примеру ExampleEAF.ex5) и свой индикатор в отдельное окно под графиком (минимальный код только отображет пустое окно). Далее нажимаю на кнопоку закрыть окно на любом из этих приложений и закрываются (удаляются с графика) оба.

Не совсвем корректное поведение. Есть ли какой способ различать события для разных приложений, работающих одновременно на одном графике? Есть подозрение, что и другие события, так же могут пересекаться.

Я протестирую, когда появится время и сообщу здесь о результате. 

Причина обращения: