Содержание

Концепция

В прошлой статье мы начали разработку вспомогательного элемента управления ScrollBar. Сегодня мы продолжим работу с ним, а также реализуем реакцию его элементов на взаимодействие с мышью. Элементы, составляющие объект WinForms ScrollBar, — это кнопки прокрутки и область захвата. Для кнопок прокрутки у нас будут отдельные классы вспомогательных объектов (кнопки со стрелками), а область захвата мы реализуем в виде простой кнопки. Сегодня мы создадим отдельный класс на основе объекта кнопки для создания объекта области захвата. Дело в том, что для корректной обработки событий движения ползунка полосы прокрутки этот объект должен иметь свой тип. Следовательно, он будет производным от объекта кнопки: унаследует его свойства и станет отдельным объектом с уникальным типом.

Сегодня мы по большей части займемся беготней по созданию функций, позволяющих изменять размеры элементов управления и обрабатывать взаимодействие мыши с полосами прокрутки. Мы также расширим список состояний мыши и их событий. Все это позволит нам в последующих статьях спокойно разрабатывать элементы управления и их функционал, не отвлекаясь на рутинную работу.

Улучшение библиотечных классов

В файле \MQL5\Include\DoEasy\Определяет.mqhдля объекта ScrollBar, мы добавим константы цвета по умолчанию для ваших состояний :

#define  CLR_DEF_CONTROL_SCROLL_BAR_TRACK_BACK_COLOR  (C'0xF0,0xF0,0xF0' )  
#define  CLR_DEF_CONTROL_SCROLL_BAR_TRACK_BORDER_COLOR (C'0xFF,0xFF,0xFF' )  
#define  CLR_DEF_CONTROL_SCROLL_BAR_TRACK_FORE_COLOR  (C'0x60,0x60,0x60' )  
#define  CLR_DEF_CONTROL_SCROLL_BAR_TRACK_FORE_MOUSE_DOWN (C'0x00,0x00,0x00' )
#define  CLR_DEF_CONTROL_SCROLL_BAR_TRACK_FORE_MOUSE_OVER (C'0x00,0x00,0x00' )

#define  CLR_DEF_CONTROL_SCROLL_BAR_THUMB_COLOR        (C'0xCD,0xCD,0xCD' )  
#define  CLR_DEF_CONTROL_SCROLL_BAR_THUMB_BORDER_COLOR (C'0xCD,0xCD,0xCD' )  
#define  CLR_DEF_CONTROL_SCROLL_BAR_THUMB_MOUSE_DOWN  (C'0x60,0x60,0x60' )  
#define  CLR_DEF_CONTROL_SCROLL_BAR_THUMB_MOUSE_OVER  (C'0xA6,0xA6,0xA6' )  
#define  CLR_DEF_CONTROL_SCROLL_BAR_THUMB_FORE_COLOR  (C'0x60,0x60,0x60' )  
#define  CLR_DEF_CONTROL_SCROLL_BAR_THUMB_FORE_MOUSE_DOWN (C'0xFF,0xFF,0xFF' )
#define  CLR_DEF_CONTROL_SCROLL_BAR_THUMB_FORE_MOUSE_OVER (C'0x00,0x00,0x00' )

#define  CLR_DEF_CONTROL_SCROLL_BAR_BUTT_COLOR        (C'0xF0,0xF0,0xF0' )  
#define  CLR_DEF_CONTROL_SCROLL_BAR_BUTT_BORDER_COLOR  (C'0xCD,0xCD,0xCD' )  
#define  CLR_DEF_CONTROL_SCROLL_BAR_BUTT_MOUSE_DOWN    (C'0x60,0x60,0x60' )  
#define  CLR_DEF_CONTROL_SCROLL_BAR_BUTT_MOUSE_OVER    (C'0xDA,0xDA,0xDA' )  
#define  CLR_DEF_CONTROL_SCROLL_BAR_BUTT_FORE_COLOR    (C'0x60,0x60,0x60' )  
#define  CLR_DEF_CONTROL_SCROLL_BAR_BUTT_FORE_MOUSE_DOWN (C'0xFF,0xFF,0xFF' )
#define  CLR_DEF_CONTROL_SCROLL_BAR_BUTT_FORE_MOUSE_OVER (C'0x00,0x00,0x00' )

#define  DEF_CONTROL_SCROLL_BAR_WIDTH                  (11 )                 
#define  DEF_CONTROL_CORNER_AREA                      (4 )                    
#define  DEF_CONTROL_LIST_MARGIN_X                    (1 )                  
#define  DEF_CONTROL_LIST_MARGIN_Y                    (0 )                  

Каждая область прокрутки имеет толщину . Для вертикальной полосы прокрутки это будет ширина объекта, а для горизонтальной полосы прокрутки — его высота. Для этого параметра мы установим значение по умолчанию 11. Полоса прокрутки будет иметь границу, отделяющую ее от интерфейса, когда она перекрывает его. При значении ширины 11 пикселей активная область полосы прокрутки будет равна 9 пикселям (по одному пикселю на рамку, сверху, снизу, слева и справа). Так как полоса прокрутки будет построена с объектами для управления ею — кнопками со стрелками и ползунком (область захвата) — то 9 пикселей будет достаточным нечетным числом, в котором треугольник стрелок будет прорисован ровно и красиво. . Вообще, при изменении размеров объектов, на которых нарисованы фигуры, очерченные вокруг их центральной оси, всегда нужно стараться использовать нечетное количество пикселей, чтобы рисунок был ровным и точным. Угловая зона будет частью формы, где курсор будет считаться находящимся в углу. Например, при изменении размера объекта, если курсор находится в одном из четырех углов, мы можем изменить одновременно два параметра его размера: высоту и ширину.

Далее добавим в список возможных состояний мыши по отношению к форме новые ценности. Размеры объекта будут изменяться в восьми направлениях. :

  1. Когда курсор находится на верхней границе объекта, мы можем изменить его высоту, переместив границу вверх,
  2. Когда курсор находится на нижнем краю объекта, мы можем изменить его высоту, переместив край вниз,
  3. Когда курсор находится на левом краю объекта, мы можем изменить его ширину, переместив край влево,
  4. Когда курсор находится на правом краю объекта, мы можем изменить его ширину, переместив край вправо,
  5. Когда курсор находится в области левого верхнего угла объекта, мы можем изменить его высоту и ширину, двигаясь вверх и влево,
  6. Когда курсор находится в области правого верхнего угла объекта, мы можем изменить его высоту и ширину, двигаясь вверх и вправо,
  7. Когда курсор находится в левом нижнем углу объекта, мы можем изменить его высоту и ширину, прокручивая вниз и влево,
  8. Когда курсор находится в правом нижнем углу объекта, мы можем изменить его высоту и ширину, прокручивая вниз и вправо,

Прокручиваемый контейнер будет иметь полосы прокрутки справа и снизу. Только нам нужно будет определить, на какой полосе прокрутки находится курсор, справа или снизу и запишите эти состояния в состоянии мыши:



enum  ENUM_MOUSE_FORM_STATE
  {
  MOUSE_FORM_STATE_NONE = 0 ,                        

  MOUSE_FORM_STATE_OUTSIDE_FORM_NOT_PRESSED,        
  MOUSE_FORM_STATE_OUTSIDE_FORM_PRESSED,            
  MOUSE_FORM_STATE_OUTSIDE_FORM_WHEEL,              

  MOUSE_FORM_STATE_INSIDE_FORM_NOT_PRESSED,          
  MOUSE_FORM_STATE_INSIDE_FORM_PRESSED,              
  MOUSE_FORM_STATE_INSIDE_FORM_WHEEL,                

  MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_NOT_PRESSED,  
  MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_PRESSED,      
  MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_WHEEL,        
  MOUSE_FORM_STATE_INSIDE_ACTIVE_AREA_RELEASED,      
  

  MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_RIGHT_NOT_PRESSED,
  MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_RIGHT_PRESSED,    
  MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_RIGHT_WHEEL,      

  MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_BOTTOM_NOT_PRESSED,
  MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_BOTTOM_PRESSED,  
  MOUSE_FORM_STATE_INSIDE_SCROLL_AREA_BOTTOM_WHEEL,     


  MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_AREA_NOT_PRESSED,  
  MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_AREA_PRESSED,      
  MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_AREA_WHEEL,        

  MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_AREA_NOT_PRESSED,
  MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_AREA_PRESSED,  
  MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_AREA_WHEEL,    

  MOUSE_FORM_STATE_INSIDE_RESIZE_LEFT_AREA_NOT_PRESSED, 
  MOUSE_FORM_STATE_INSIDE_RESIZE_LEFT_AREA_PRESSED,    
  MOUSE_FORM_STATE_INSIDE_RESIZE_LEFT_AREA_WHEEL,      

  MOUSE_FORM_STATE_INSIDE_RESIZE_RIGHT_AREA_NOT_PRESSED,
  MOUSE_FORM_STATE_INSIDE_RESIZE_RIGHT_AREA_PRESSED,    
  MOUSE_FORM_STATE_INSIDE_RESIZE_RIGHT_AREA_WHEEL,      

  MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_LEFT_AREA_NOT_PRESSED,  
  MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_LEFT_AREA_PRESSED,      
  MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_LEFT_AREA_WHEEL,        

  MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_RIGHT_AREA_NOT_PRESSED,  
  MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_RIGHT_AREA_PRESSED,      
  MOUSE_FORM_STATE_INSIDE_RESIZE_TOP_RIGHT_AREA_WHEEL,        

  MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_LEFT_AREA_NOT_PRESSED,
  MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_LEFT_AREA_PRESSED,    
  MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_LEFT_AREA_WHEEL,      

  MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_RIGHT_AREA_NOT_PRESSED,
  MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_RIGHT_AREA_PRESSED,  
  MOUSE_FORM_STATE_INSIDE_RESIZE_BOTTOM_RIGHT_AREA_WHEEL,     
  

  MOUSE_FORM_STATE_INSIDE_CONTROL_AREA_NOT_PRESSED,  
  MOUSE_FORM_STATE_INSIDE_CONTROL_AREA_PRESSED,      
  MOUSE_FORM_STATE_INSIDE_CONTROL_AREA_WHEEL,        
  };


Все эти новые состояния будут определены и записаны как состояние мыши относительно объекта.

Когда событие мыши регистрируется в одном из предопределенных состояний, соответствующее событие будет отправлено в библиотеку, где на каждом из объектов будут вызваны соответствующие обработчики событий, делающие возможной обработку события мыши.
Запишем новые состояния в список возможных событий мыши. :



enum  ENUM_MOUSE_EVENT
  {
  MOUSE_EVENT_NO_EVENT = CHART_OBJ_EVENTS_NEXT_CODE, 

  MOUSE_EVENT_OUTSIDE_FORM_NOT_PRESSED,              
  MOUSE_EVENT_OUTSIDE_FORM_PRESSED,                  
  MOUSE_EVENT_OUTSIDE_FORM_WHEEL,                    

  MOUSE_EVENT_INSIDE_FORM_NOT_PRESSED,              
  MOUSE_EVENT_INSIDE_FORM_PRESSED,                  
  MOUSE_EVENT_INSIDE_FORM_WHEEL,                    

  MOUSE_EVENT_INSIDE_ACTIVE_AREA_NOT_PRESSED,        
  MOUSE_EVENT_INSIDE_ACTIVE_AREA_PRESSED,            
  MOUSE_EVENT_INSIDE_ACTIVE_AREA_WHEEL,              
  MOUSE_EVENT_INSIDE_ACTIVE_AREA_RELEASED,          

  MOUSE_EVENT_INSIDE_SCROLL_AREA_RIGHT_NOT_PRESSED,  
  MOUSE_EVENT_INSIDE_SCROLL_AREA_RIGHT_PRESSED,      
  MOUSE_EVENT_INSIDE_SCROLL_AREA_RIGHT_WHEEL,        

  MOUSE_EVENT_INSIDE_SCROLL_AREA_BOTTOM_NOT_PRESSED, 
  MOUSE_EVENT_INSIDE_SCROLL_AREA_BOTTOM_PRESSED,    
  MOUSE_EVENT_INSIDE_SCROLL_AREA_BOTTOM_WHEEL,      


  MOUSE_EVENT_INSIDE_RESIZE_TOP_AREA_NOT_PRESSED,    
  MOUSE_EVENT_INSIDE_RESIZE_TOP_AREA_PRESSED,        
  MOUSE_EVENT_INSIDE_RESIZE_TOP_AREA_WHEEL,          

  MOUSE_EVENT_INSIDE_RESIZE_BOTTOM_AREA_NOT_PRESSED, 
  MOUSE_EVENT_INSIDE_RESIZE_BOTTOM_AREA_PRESSED,    
  MOUSE_EVENT_INSIDE_RESIZE_BOTTOM_AREA_WHEEL,       

  MOUSE_EVENT_INSIDE_RESIZE_LEFT_AREA_NOT_PRESSED,  
  MOUSE_EVENT_INSIDE_RESIZE_LEFT_AREA_PRESSED,      
  MOUSE_EVENT_INSIDE_RESIZE_LEFT_AREA_WHEEL,        

  MOUSE_EVENT_INSIDE_RESIZE_RIGHT_AREA_NOT_PRESSED,  
  ...